Trying to get 100 Continue working again
This commit is contained in:
parent
044bbb83e6
commit
ebd6af0fd6
|
|
@ -17,6 +17,13 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ConnectionContext(ConnectionContext context) : base(context)
|
||||||
|
{
|
||||||
|
SocketInput = context.SocketInput;
|
||||||
|
SocketOutput = context.SocketOutput;
|
||||||
|
ConnectionControl = context.ConnectionControl;
|
||||||
|
}
|
||||||
|
|
||||||
public SocketInput SocketInput { get; set; }
|
public SocketInput SocketInput { get; set; }
|
||||||
public ISocketOutput SocketOutput { get; set; }
|
public ISocketOutput SocketOutput { get; set; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,29 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
ConnectionKeepAlive,
|
ConnectionKeepAlive,
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Frame
|
public class FrameContext : ConnectionContext
|
||||||
{
|
{
|
||||||
private ConnectionContext _context;
|
public FrameContext()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public FrameContext(ConnectionContext context) : base(context)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public IFrameControl FrameControl { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IFrameControl
|
||||||
|
{
|
||||||
|
void ProduceContinue();
|
||||||
|
void Write(ArraySegment<byte> data, Action<object> callback, object state);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Frame : FrameContext, IFrameControl
|
||||||
|
{
|
||||||
Mode _mode;
|
Mode _mode;
|
||||||
|
|
||||||
enum Mode
|
enum Mode
|
||||||
|
|
@ -64,10 +83,11 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
Task _upgradeTask = _completedTask;
|
Task _upgradeTask = _completedTask;
|
||||||
static readonly Task _completedTask = Task.FromResult(0);
|
static readonly Task _completedTask = Task.FromResult(0);
|
||||||
|
|
||||||
public Frame(ConnectionContext context)
|
public Frame(ConnectionContext context) : base(context)
|
||||||
{
|
{
|
||||||
_context = context;
|
FrameControl = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
public bool LocalIntakeFin
|
public bool LocalIntakeFin
|
||||||
{
|
{
|
||||||
|
|
@ -81,7 +101,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
*/
|
*/
|
||||||
public void Consume()
|
public void Consume()
|
||||||
{
|
{
|
||||||
var input = _context.SocketInput;
|
var input = SocketInput;
|
||||||
for (; ;)
|
for (; ;)
|
||||||
{
|
{
|
||||||
switch (_mode)
|
switch (_mode)
|
||||||
|
|
@ -146,46 +166,15 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Action<Frame, Exception> HandleExpectContinue(Action<Frame, Exception> continuation)
|
|
||||||
{
|
|
||||||
string[] expect;
|
|
||||||
if (_httpVersion.Equals("HTTP/1.1") &&
|
|
||||||
_requestHeaders.TryGetValue("Expect", out expect) &&
|
|
||||||
(expect.FirstOrDefault() ?? "").Equals("100-continue", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
return (frame, error) =>
|
|
||||||
{
|
|
||||||
if (_resultStarted)
|
|
||||||
{
|
|
||||||
continuation.Invoke(frame, error);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var bytes = Encoding.Default.GetBytes("HTTP/1.1 100 Continue\r\n\r\n");
|
|
||||||
|
|
||||||
//var isasync = _context.SocketOutput.Write(
|
|
||||||
// new ArraySegment<byte>(bytes),
|
|
||||||
// error2 => continuation(frame, error2));
|
|
||||||
|
|
||||||
//if (!isasync)
|
|
||||||
//{
|
|
||||||
// continuation.Invoke(frame, null);
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return continuation;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Execute()
|
private void Execute()
|
||||||
{
|
{
|
||||||
_messageBody = MessageBody.For(
|
_messageBody = MessageBody.For(
|
||||||
_httpVersion,
|
_httpVersion,
|
||||||
_requestHeaders,
|
_requestHeaders,
|
||||||
_context);
|
this);
|
||||||
_keepAlive = _messageBody.RequestKeepAlive;
|
_keepAlive = _messageBody.RequestKeepAlive;
|
||||||
_callContext = CreateCallContext();
|
_callContext = CreateCallContext();
|
||||||
_context.SocketInput.Free();
|
SocketInput.Free();
|
||||||
Task.Run(ExecuteAsync);
|
Task.Run(ExecuteAsync);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -194,7 +183,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
Exception error = null;
|
Exception error = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _context.Application.Invoke(_callContext);
|
await Application.Invoke(_callContext);
|
||||||
await _upgradeTask;
|
await _upgradeTask;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|
@ -210,7 +199,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
private CallContext CreateCallContext()
|
private CallContext CreateCallContext()
|
||||||
{
|
{
|
||||||
_inputStream = new FrameRequestStream(_messageBody);
|
_inputStream = new FrameRequestStream(_messageBody);
|
||||||
_outputStream = new FrameResponseStream(OnWrite);
|
_outputStream = new FrameResponseStream(this);
|
||||||
_duplexStream = new FrameDuplexStream(_inputStream, _outputStream);
|
_duplexStream = new FrameDuplexStream(_inputStream, _outputStream);
|
||||||
|
|
||||||
var remoteIpAddress = "127.0.0.1";
|
var remoteIpAddress = "127.0.0.1";
|
||||||
|
|
@ -279,13 +268,13 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
return callContext;
|
return callContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnWrite(ArraySegment<byte> data, Action<object> callback, object state)
|
public void Write(ArraySegment<byte> data, Action<object> callback, object state)
|
||||||
{
|
{
|
||||||
ProduceStart();
|
ProduceStart();
|
||||||
_context.SocketOutput.Write(data, callback, state);
|
SocketOutput.Write(data, callback, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Upgrade(IDictionary<string, object> options, Func<object, Task> callback)
|
public void Upgrade(IDictionary<string, object> options, Func<object, Task> callback)
|
||||||
{
|
{
|
||||||
_keepAlive = false;
|
_keepAlive = false;
|
||||||
ProduceStart();
|
ProduceStart();
|
||||||
|
|
@ -293,7 +282,22 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
_upgradeTask = callback(_callContext);
|
_upgradeTask = callback(_callContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProduceStart()
|
byte[] _continueBytes = Encoding.ASCII.GetBytes("HTTP/1.1 100 Continue\r\n\r\n");
|
||||||
|
|
||||||
|
public void ProduceContinue()
|
||||||
|
{
|
||||||
|
if (_resultStarted) return;
|
||||||
|
|
||||||
|
string[] expect;
|
||||||
|
if (_httpVersion.Equals("HTTP/1.1") &&
|
||||||
|
_requestHeaders.TryGetValue("Expect", out expect) &&
|
||||||
|
(expect.FirstOrDefault() ?? "").Equals("100-continue", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
SocketOutput.Write(new ArraySegment<byte>(_continueBytes, 0, _continueBytes.Length), _ => { }, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ProduceStart()
|
||||||
{
|
{
|
||||||
if (_resultStarted) return;
|
if (_resultStarted) return;
|
||||||
|
|
||||||
|
|
@ -305,27 +309,27 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
response.ReasonPhrase);
|
response.ReasonPhrase);
|
||||||
|
|
||||||
var responseHeader = CreateResponseHeader(status, _responseHeaders);
|
var responseHeader = CreateResponseHeader(status, _responseHeaders);
|
||||||
_context.SocketOutput.Write(responseHeader.Item1, x => ((IDisposable)x).Dispose(), responseHeader.Item2);
|
SocketOutput.Write(responseHeader.Item1, x => ((IDisposable)x).Dispose(), responseHeader.Item2);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ProduceEnd(Exception ex)
|
public void ProduceEnd(Exception ex)
|
||||||
{
|
{
|
||||||
ProduceStart();
|
ProduceStart();
|
||||||
|
|
||||||
if (!_keepAlive)
|
if (!_keepAlive)
|
||||||
{
|
{
|
||||||
_context.ConnectionControl.End(ProduceEndType.SocketShutdownSend);
|
ConnectionControl.End(ProduceEndType.SocketShutdownSend);
|
||||||
}
|
}
|
||||||
|
|
||||||
_messageBody.Drain(() =>
|
_messageBody.Drain(() =>
|
||||||
_context.ConnectionControl.End(_keepAlive ? ProduceEndType.ConnectionKeepAlive : ProduceEndType.SocketDisconnect));
|
ConnectionControl.End(_keepAlive ? ProduceEndType.ConnectionKeepAlive : ProduceEndType.SocketDisconnect));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private Tuple<ArraySegment<byte>, IDisposable> CreateResponseHeader(
|
private Tuple<ArraySegment<byte>, IDisposable> CreateResponseHeader(
|
||||||
string status, IEnumerable<KeyValuePair<string, string[]>> headers)
|
string status, IEnumerable<KeyValuePair<string, string[]>> headers)
|
||||||
{
|
{
|
||||||
var writer = new MemoryPoolTextWriter(_context.Memory);
|
var writer = new MemoryPoolTextWriter(Memory);
|
||||||
writer.Write(_httpVersion);
|
writer.Write(_httpVersion);
|
||||||
writer.Write(' ');
|
writer.Write(' ');
|
||||||
writer.Write(status);
|
writer.Write(status);
|
||||||
|
|
|
||||||
|
|
@ -63,11 +63,25 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
|
|
||||||
public Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken, object state)
|
public Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken, object state)
|
||||||
{
|
{
|
||||||
//NOTE todo
|
var tcs = new TaskCompletionSource<int>(state);
|
||||||
throw new NotImplementedException();
|
var task = _body.ReadAsync(new ArraySegment<byte>(buffer, offset, count));
|
||||||
//var tcs = new TaskCompletionSource<int>(state);
|
task.ContinueWith((t, x) =>
|
||||||
//_body.ReadAsync(new ArraySegment<byte>(buffer, offset, count));
|
{
|
||||||
//return tcs.Task;
|
var tcs2 = (TaskCompletionSource<int>)x;
|
||||||
|
if (t.IsCanceled)
|
||||||
|
{
|
||||||
|
tcs2.SetCanceled();
|
||||||
|
}
|
||||||
|
else if (t.IsFaulted)
|
||||||
|
{
|
||||||
|
tcs2.SetException(t.Exception);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tcs2.SetResult(t.Result);
|
||||||
|
}
|
||||||
|
}, tcs);
|
||||||
|
return tcs.Task;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Write(byte[] buffer, int offset, int count)
|
public override void Write(byte[] buffer, int offset, int count)
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,11 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
{
|
{
|
||||||
class FrameResponseStream : Stream
|
class FrameResponseStream : Stream
|
||||||
{
|
{
|
||||||
readonly Action<ArraySegment<byte>, Action<object>, object> _write;
|
private readonly FrameContext _context;
|
||||||
|
|
||||||
public FrameResponseStream(Action<ArraySegment<byte>, Action<object>, object> write)
|
public FrameResponseStream(FrameContext context)
|
||||||
{
|
{
|
||||||
_write = write;
|
_context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Flush()
|
public override void Flush()
|
||||||
|
|
@ -25,7 +25,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
public override Task FlushAsync(CancellationToken cancellationToken)
|
public override Task FlushAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var tcs = new TaskCompletionSource<int>();
|
var tcs = new TaskCompletionSource<int>();
|
||||||
_write(new ArraySegment<byte>(new byte[0]), x => ((TaskCompletionSource<int>)x).SetResult(0), tcs);
|
_context.FrameControl.Write(new ArraySegment<byte>(new byte[0]), x => ((TaskCompletionSource<int>)x).SetResult(0), tcs);
|
||||||
return tcs.Task;
|
return tcs.Task;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -52,7 +52,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
|
public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var tcs = new TaskCompletionSource<int>();
|
var tcs = new TaskCompletionSource<int>();
|
||||||
_write(new ArraySegment<byte>(buffer, offset, count), x => ((TaskCompletionSource<int>)x).SetResult(0), tcs);
|
_context.FrameControl.Write(new ArraySegment<byte>(buffer, offset, count), x => ((TaskCompletionSource<int>)x).SetResult(0), tcs);
|
||||||
return tcs.Task;
|
return tcs.Task;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
|
|
||||||
public bool RequestKeepAlive { get; protected set; }
|
public bool RequestKeepAlive { get; protected set; }
|
||||||
|
|
||||||
protected MessageBody(ConnectionContext context) : base(context)
|
protected MessageBody(FrameContext context) : base(context)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -35,7 +35,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
public static MessageBody For(
|
public static MessageBody For(
|
||||||
string httpVersion,
|
string httpVersion,
|
||||||
IDictionary<string, string[]> headers,
|
IDictionary<string, string[]> headers,
|
||||||
ConnectionContext context)
|
FrameContext context)
|
||||||
{
|
{
|
||||||
// see also http://tools.ietf.org/html/rfc2616#section-4.4
|
// see also http://tools.ietf.org/html/rfc2616#section-4.4
|
||||||
|
|
||||||
|
|
@ -99,7 +99,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
|
|
||||||
class ForRemainingData : MessageBody
|
class ForRemainingData : MessageBody
|
||||||
{
|
{
|
||||||
public ForRemainingData(ConnectionContext context)
|
public ForRemainingData(FrameContext context)
|
||||||
: base(context)
|
: base(context)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
@ -124,7 +124,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
private readonly int _contentLength;
|
private readonly int _contentLength;
|
||||||
private int _neededLength;
|
private int _neededLength;
|
||||||
|
|
||||||
public ForContentLength(bool keepAlive, int contentLength, ConnectionContext context)
|
public ForContentLength(bool keepAlive, int contentLength, FrameContext context)
|
||||||
: base(context)
|
: base(context)
|
||||||
{
|
{
|
||||||
RequestKeepAlive = keepAlive;
|
RequestKeepAlive = keepAlive;
|
||||||
|
|
@ -168,7 +168,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
public ForChunkedEncoding(bool keepAlive, ConnectionContext context)
|
public ForChunkedEncoding(bool keepAlive, FrameContext context)
|
||||||
: base(context)
|
: base(context)
|
||||||
{
|
{
|
||||||
RequestKeepAlive = keepAlive;
|
RequestKeepAlive = keepAlive;
|
||||||
|
|
|
||||||
|
|
@ -15,14 +15,15 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
public class MessageBodyExchanger
|
public class MessageBodyExchanger
|
||||||
{
|
{
|
||||||
private static readonly WaitCallback _completePending = CompletePending;
|
private static readonly WaitCallback _completePending = CompletePending;
|
||||||
protected readonly ConnectionContext _context;
|
protected readonly FrameContext _context;
|
||||||
|
|
||||||
object _sync = new Object();
|
object _sync = new Object();
|
||||||
|
|
||||||
ArraySegment<byte> _buffer;
|
ArraySegment<byte> _buffer;
|
||||||
Queue<ReadOperation> _reads = new Queue<ReadOperation>();
|
Queue<ReadOperation> _reads = new Queue<ReadOperation>();
|
||||||
|
bool _send100Continue = true;
|
||||||
|
|
||||||
public MessageBodyExchanger(ConnectionContext context)
|
public MessageBodyExchanger(FrameContext context)
|
||||||
{
|
{
|
||||||
_context = context;
|
_context = context;
|
||||||
_buffer = new ArraySegment<byte>(_context.Memory.Empty);
|
_buffer = new ArraySegment<byte>(_context.Memory.Empty);
|
||||||
|
|
@ -32,9 +33,18 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
|
|
||||||
public void Transfer(int count, bool fin)
|
public void Transfer(int count, bool fin)
|
||||||
{
|
{
|
||||||
|
if (count == 0 && !fin)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
var input = _context.SocketInput;
|
var input = _context.SocketInput;
|
||||||
lock (_sync)
|
lock (_sync)
|
||||||
{
|
{
|
||||||
|
if (_send100Continue)
|
||||||
|
{
|
||||||
|
_send100Continue = false;
|
||||||
|
}
|
||||||
|
|
||||||
// NOTE: this should not copy each time
|
// NOTE: this should not copy each time
|
||||||
var oldBuffer = _buffer;
|
var oldBuffer = _buffer;
|
||||||
var newData = _context.SocketInput.Take(count);
|
var newData = _context.SocketInput.Take(count);
|
||||||
|
|
@ -63,7 +73,9 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
|
|
||||||
public Task<int> ReadAsync(ArraySegment<byte> buffer)
|
public Task<int> ReadAsync(ArraySegment<byte> buffer)
|
||||||
{
|
{
|
||||||
for (; ;)
|
Task<int> result = null;
|
||||||
|
var send100Continue = false;
|
||||||
|
while (result == null)
|
||||||
{
|
{
|
||||||
while (CompletePending())
|
while (CompletePending())
|
||||||
{
|
{
|
||||||
|
|
@ -83,7 +95,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
var count = Math.Min(buffer.Count, _buffer.Count);
|
var count = Math.Min(buffer.Count, _buffer.Count);
|
||||||
Array.Copy(_buffer.Array, _buffer.Offset, buffer.Array, buffer.Offset, count);
|
Array.Copy(_buffer.Array, _buffer.Offset, buffer.Array, buffer.Offset, count);
|
||||||
_buffer = new ArraySegment<byte>(_buffer.Array, _buffer.Offset + count, _buffer.Count - count);
|
_buffer = new ArraySegment<byte>(_buffer.Array, _buffer.Offset + count, _buffer.Count - count);
|
||||||
return Task.FromResult(count);
|
result = Task.FromResult(count);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -94,10 +106,17 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
Buffer = buffer,
|
Buffer = buffer,
|
||||||
CompletionSource = tcs,
|
CompletionSource = tcs,
|
||||||
});
|
});
|
||||||
return tcs.Task;
|
result = tcs.Task;
|
||||||
|
send100Continue = _send100Continue;
|
||||||
|
_send100Continue = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (send100Continue)
|
||||||
|
{
|
||||||
|
_context.FrameControl.ProduceContinue();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CompletePending(object state)
|
static void CompletePending(object state)
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
using Microsoft.AspNet.Server.Kestrel.Networking;
|
using Microsoft.AspNet.Server.Kestrel.Networking;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.ExceptionServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
|
@ -22,6 +23,7 @@ namespace Microsoft.AspNet.Server.Kestrel
|
||||||
Queue<Work> _workRunning = new Queue<Work>();
|
Queue<Work> _workRunning = new Queue<Work>();
|
||||||
object _workSync = new Object();
|
object _workSync = new Object();
|
||||||
bool _stopImmediate = false;
|
bool _stopImmediate = false;
|
||||||
|
private ExceptionDispatchInfo _closeError;
|
||||||
|
|
||||||
public KestrelThread(KestrelEngine engine)
|
public KestrelThread(KestrelEngine engine)
|
||||||
{
|
{
|
||||||
|
|
@ -51,6 +53,10 @@ namespace Microsoft.AspNet.Server.Kestrel
|
||||||
_thread.Abort();
|
_thread.Abort();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (_closeError != null)
|
||||||
|
{
|
||||||
|
_closeError.Throw();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnStop(object obj)
|
private void OnStop(object obj)
|
||||||
|
|
@ -86,20 +92,27 @@ namespace Microsoft.AspNet.Server.Kestrel
|
||||||
{
|
{
|
||||||
tcs.SetException(ex);
|
tcs.SetException(ex);
|
||||||
}
|
}
|
||||||
var ran1 = _loop.Run();
|
try
|
||||||
if (_stopImmediate)
|
|
||||||
{
|
{
|
||||||
// thread-abort form of exit, resources will be leaked
|
var ran1 = _loop.Run();
|
||||||
return;
|
if (_stopImmediate)
|
||||||
|
{
|
||||||
|
// thread-abort form of exit, resources will be leaked
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// run the loop one more time to delete the _post handle
|
||||||
|
_post.Reference();
|
||||||
|
_post.DangerousClose();
|
||||||
|
var ran2 = _loop.Run();
|
||||||
|
|
||||||
|
// delete the last of the unmanaged memory
|
||||||
|
_loop.Close();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_closeError = ExceptionDispatchInfo.Capture(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// run the loop one more time to delete the _post handle
|
|
||||||
_post.Reference();
|
|
||||||
_post.Close();
|
|
||||||
var ran2 = _loop.Run();
|
|
||||||
|
|
||||||
// delete the last of the unmanaged memory
|
|
||||||
_loop.Close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnPost()
|
private void OnPost()
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,12 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
||||||
_uv.async_init(loop, this, _uv_async_cb);
|
_uv.async_init(loop, this, _uv_async_cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void DangerousClose()
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
ReleaseHandle();
|
||||||
|
}
|
||||||
|
|
||||||
private void UvAsyncCb(IntPtr handle)
|
private void UvAsyncCb(IntPtr handle)
|
||||||
{
|
{
|
||||||
_callback.Invoke();
|
_callback.Invoke();
|
||||||
|
|
|
||||||
|
|
@ -34,20 +34,21 @@ namespace Microsoft.AspNet.Server.KestralTests
|
||||||
{
|
{
|
||||||
var request = callContext as IHttpRequestFeature;
|
var request = callContext as IHttpRequestFeature;
|
||||||
var response = callContext as IHttpResponseFeature;
|
var response = callContext as IHttpResponseFeature;
|
||||||
response.Headers["Transfer-Encoding"] = new[] { "chunked" };
|
|
||||||
|
var data = new MemoryStream();
|
||||||
for (; ;)
|
for (; ;)
|
||||||
{
|
{
|
||||||
var buffer = new byte[8192];
|
var buffer = new byte[8192];
|
||||||
var count = await request.Body.ReadAsync(buffer, 0, buffer.Length);
|
var count = await request.Body.ReadAsync(buffer, 0, buffer.Length);
|
||||||
var hex = Encoding.ASCII.GetBytes(count.ToString("x") + "\r\n");
|
|
||||||
await response.Body.WriteAsync(hex, 0, hex.Length);
|
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
await response.Body.WriteAsync(buffer, 0, count);
|
data.Write(buffer, 0, count);
|
||||||
await response.Body.WriteAsync(new[] { (byte)'\r', (byte)'\n' }, 0, 2);
|
|
||||||
}
|
}
|
||||||
|
var bytes = data.ToArray();
|
||||||
|
response.Headers["Content-Length"] = new[] { bytes.Length.ToString() };
|
||||||
|
await response.Body.WriteAsync(bytes, 0, bytes.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -118,12 +119,12 @@ Hello World");
|
||||||
|
|
||||||
Transceive(
|
Transceive(
|
||||||
@"POST / HTTP/1.0
|
@"POST / HTTP/1.0
|
||||||
Content-Length: 5
|
Content-Length: 11
|
||||||
|
|
||||||
Hello World",
|
Hello World",
|
||||||
@"HTTP/1.0 200 OK
|
@"HTTP/1.0 200 OK
|
||||||
|
|
||||||
Hello");
|
Hello World");
|
||||||
started.Dispose();
|
started.Dispose();
|
||||||
engine.Stop();
|
engine.Stop();
|
||||||
}
|
}
|
||||||
|
|
@ -135,19 +136,21 @@ Hello");
|
||||||
engine.Start(1);
|
engine.Start(1);
|
||||||
var started = engine.CreateServer(App);
|
var started = engine.CreateServer(App);
|
||||||
|
|
||||||
Transceive(
|
using (var connection = new TestConnection())
|
||||||
@"POST / HTTP/1.0
|
{
|
||||||
Transfer-Encoding: chunked
|
await connection.Send(
|
||||||
|
"POST / HTTP/1.0",
|
||||||
|
"Transfer-Encoding: chunked",
|
||||||
|
"",
|
||||||
|
"5", "Hello", "6", " World", "0\r\n");
|
||||||
|
await connection.ReceiveEnd(
|
||||||
|
"HTTP/1.0 200 OK",
|
||||||
|
"",
|
||||||
|
"Hello World");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
5
|
|
||||||
Hello
|
|
||||||
6
|
|
||||||
World
|
|
||||||
0
|
|
||||||
ignored",
|
|
||||||
@"HTTP/1.0 200 OK
|
|
||||||
|
|
||||||
Hello World");
|
|
||||||
started.Dispose();
|
started.Dispose();
|
||||||
engine.Stop();
|
engine.Stop();
|
||||||
}
|
}
|
||||||
|
|
@ -160,25 +163,27 @@ Hello World");
|
||||||
engine.Start(1);
|
engine.Start(1);
|
||||||
var started = engine.CreateServer(AppChunked);
|
var started = engine.CreateServer(AppChunked);
|
||||||
|
|
||||||
Transceive(
|
using (var connection = new TestConnection())
|
||||||
@"GET / HTTP/1.0
|
{
|
||||||
Connection: Keep-Alive
|
await connection.SendEnd(
|
||||||
|
"GET / HTTP/1.0",
|
||||||
|
"Connection: keep-alive",
|
||||||
|
"",
|
||||||
|
"POST / HTTP/1.0",
|
||||||
|
"",
|
||||||
|
"Goodbye");
|
||||||
|
await connection.Receive(
|
||||||
|
"HTTP/1.0 200 OK",
|
||||||
|
"Content-Length: 0",
|
||||||
|
"Connection: keep-alive",
|
||||||
|
"\r\n");
|
||||||
|
await connection.ReceiveEnd(
|
||||||
|
"HTTP/1.0 200 OK",
|
||||||
|
"Content-Length: 7",
|
||||||
|
"",
|
||||||
|
"Goodbye");
|
||||||
|
}
|
||||||
|
|
||||||
POST / HTTP/1.0
|
|
||||||
|
|
||||||
Goodbye",
|
|
||||||
@"HTTP/1.0 200 OK
|
|
||||||
Transfer-Encoding: chunked
|
|
||||||
Connection: keep-alive
|
|
||||||
|
|
||||||
0
|
|
||||||
HTTP/1.0 200 OK
|
|
||||||
Transfer-Encoding: chunked
|
|
||||||
|
|
||||||
7
|
|
||||||
Goodbye
|
|
||||||
0
|
|
||||||
");
|
|
||||||
started.Dispose();
|
started.Dispose();
|
||||||
engine.Stop();
|
engine.Stop();
|
||||||
}
|
}
|
||||||
|
|
@ -190,28 +195,28 @@ Goodbye
|
||||||
engine.Start(1);
|
engine.Start(1);
|
||||||
var started = engine.CreateServer(AppChunked);
|
var started = engine.CreateServer(AppChunked);
|
||||||
|
|
||||||
Transceive(
|
using (var connection = new TestConnection())
|
||||||
@"POST / HTTP/1.0
|
{
|
||||||
Connection: Keep-Alive
|
await connection.SendEnd(
|
||||||
Content-Length: 11
|
"POST / HTTP/1.0",
|
||||||
|
"Connection: keep-alive",
|
||||||
Hello WorldPOST / HTTP/1.0
|
"Content-Length: 11",
|
||||||
|
"",
|
||||||
Goodbye",
|
"Hello WorldPOST / HTTP/1.0",
|
||||||
@"HTTP/1.0 200 OK
|
"",
|
||||||
Transfer-Encoding: chunked
|
"Goodbye");
|
||||||
Connection: keep-alive
|
await connection.Receive(
|
||||||
|
"HTTP/1.0 200 OK",
|
||||||
b
|
"Content-Length: 11",
|
||||||
Hello World
|
"Connection: keep-alive",
|
||||||
0
|
"",
|
||||||
HTTP/1.0 200 OK
|
"Hello World");
|
||||||
Transfer-Encoding: chunked
|
await connection.ReceiveEnd(
|
||||||
|
"HTTP/1.0 200 OK",
|
||||||
7
|
"Content-Length: 7",
|
||||||
Goodbye
|
"",
|
||||||
0
|
"Goodbye");
|
||||||
");
|
}
|
||||||
started.Dispose();
|
started.Dispose();
|
||||||
engine.Stop();
|
engine.Stop();
|
||||||
}
|
}
|
||||||
|
|
@ -223,37 +228,52 @@ Goodbye
|
||||||
engine.Start(1);
|
engine.Start(1);
|
||||||
var started = engine.CreateServer(AppChunked);
|
var started = engine.CreateServer(AppChunked);
|
||||||
|
|
||||||
Transceive(
|
using (var connection = new TestConnection())
|
||||||
@"POST / HTTP/1.0
|
{
|
||||||
Transfer-Encoding: chunked
|
await connection.SendEnd(
|
||||||
Connection: keep-alive
|
"POST / HTTP/1.0",
|
||||||
|
"Transfer-Encoding: chunked",
|
||||||
|
"Connection: keep-alive",
|
||||||
|
"",
|
||||||
|
"5", "Hello", "6", " World", "0",
|
||||||
|
"POST / HTTP/1.0",
|
||||||
|
"",
|
||||||
|
"Goodbye");
|
||||||
|
await connection.Receive(
|
||||||
|
"HTTP/1.0 200 OK",
|
||||||
|
"Content-Length: 11",
|
||||||
|
"Connection: keep-alive",
|
||||||
|
"",
|
||||||
|
"Hello World");
|
||||||
|
await connection.ReceiveEnd(
|
||||||
|
"HTTP/1.0 200 OK",
|
||||||
|
"Content-Length: 7",
|
||||||
|
"",
|
||||||
|
"Goodbye");
|
||||||
|
}
|
||||||
|
|
||||||
5
|
|
||||||
Hello
|
|
||||||
6
|
|
||||||
World
|
|
||||||
0
|
|
||||||
POST / HTTP/1.0
|
|
||||||
|
|
||||||
Goodbye",
|
|
||||||
@"HTTP/1.0 200 OK
|
|
||||||
Transfer-Encoding: chunked
|
|
||||||
Connection: keep-alive
|
|
||||||
|
|
||||||
b
|
|
||||||
Hello World
|
|
||||||
0
|
|
||||||
HTTP/1.0 200 OK
|
|
||||||
Transfer-Encoding: chunked
|
|
||||||
|
|
||||||
7
|
|
||||||
Goodbye
|
|
||||||
0
|
|
||||||
");
|
|
||||||
started.Dispose();
|
started.Dispose();
|
||||||
engine.Stop();
|
engine.Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact(Skip = "This is still not working")]
|
||||||
|
public async Task Expect100ContinueForBody()
|
||||||
|
{
|
||||||
|
var engine = new KestrelEngine();
|
||||||
|
engine.Start(1);
|
||||||
|
var started = engine.CreateServer(AppChunked);
|
||||||
|
|
||||||
|
using (var connection = new TestConnection())
|
||||||
|
{
|
||||||
|
await connection.Send("POST / HTTP/1.1", "Expect: 100-continue", "Content-Length: 11", "\r\n");
|
||||||
|
await connection.Receive("HTTP/1.1 100 Continue", "\r\n");
|
||||||
|
await connection.SendEnd("Hello World");
|
||||||
|
await connection.ReceiveEnd("HTTP/1.1 200 OK", "Content-Length: 11", "", "Hello World");
|
||||||
|
}
|
||||||
|
|
||||||
|
started.Dispose();
|
||||||
|
engine.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
private void Transceive(string send, string expected)
|
private void Transceive(string send, string expected)
|
||||||
{
|
{
|
||||||
|
|
@ -261,11 +281,25 @@ Goodbye
|
||||||
socket.Connect(new IPEndPoint(IPAddress.Loopback, 4001));
|
socket.Connect(new IPEndPoint(IPAddress.Loopback, 4001));
|
||||||
|
|
||||||
var stream = new NetworkStream(socket, false);
|
var stream = new NetworkStream(socket, false);
|
||||||
var writer = new StreamWriter(stream, Encoding.ASCII);
|
Task.Run(async () =>
|
||||||
writer.Write(send);
|
{
|
||||||
writer.Flush();
|
try
|
||||||
stream.Flush();
|
{
|
||||||
socket.Shutdown(SocketShutdown.Send);
|
var writer = new StreamWriter(stream, Encoding.ASCII);
|
||||||
|
foreach (var ch in send)
|
||||||
|
{
|
||||||
|
await writer.WriteAsync(ch);
|
||||||
|
await writer.FlushAsync();
|
||||||
|
await Task.Delay(TimeSpan.FromMilliseconds(5));
|
||||||
|
}
|
||||||
|
writer.Flush();
|
||||||
|
stream.Flush();
|
||||||
|
socket.Shutdown(SocketShutdown.Send);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
var reader = new StreamReader(stream, Encoding.ASCII);
|
var reader = new StreamReader(stream, Encoding.ASCII);
|
||||||
var actual = reader.ReadToEnd();
|
var actual = reader.ReadToEnd();
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ namespace Microsoft.AspNet.Server.KestralTests
|
||||||
var context = new ConnectionContext();
|
var context = new ConnectionContext();
|
||||||
context.SocketInput = new SocketInput(new MemoryPool());
|
context.SocketInput = new SocketInput(new MemoryPool());
|
||||||
|
|
||||||
var exchanger = new MessageBodyExchanger(testInput.ConnectionContext);
|
var exchanger = new MessageBodyExchanger(testInput.FrameContext);
|
||||||
|
|
||||||
var buffer1 = new byte[1024];
|
var buffer1 = new byte[1024];
|
||||||
var buffer2 = new byte[1024];
|
var buffer2 = new byte[1024];
|
||||||
|
|
@ -54,7 +54,7 @@ namespace Microsoft.AspNet.Server.KestralTests
|
||||||
var context = new ConnectionContext();
|
var context = new ConnectionContext();
|
||||||
context.SocketInput = new SocketInput(new MemoryPool());
|
context.SocketInput = new SocketInput(new MemoryPool());
|
||||||
|
|
||||||
var exchanger = new MessageBodyExchanger(testInput.ConnectionContext);
|
var exchanger = new MessageBodyExchanger(testInput.FrameContext);
|
||||||
|
|
||||||
testInput.Add("Hello");
|
testInput.Add("Hello");
|
||||||
|
|
||||||
|
|
@ -84,7 +84,7 @@ namespace Microsoft.AspNet.Server.KestralTests
|
||||||
var context = new ConnectionContext();
|
var context = new ConnectionContext();
|
||||||
context.SocketInput = new SocketInput(new MemoryPool());
|
context.SocketInput = new SocketInput(new MemoryPool());
|
||||||
|
|
||||||
var exchanger = new MessageBodyExchanger(testInput.ConnectionContext);
|
var exchanger = new MessageBodyExchanger(testInput.FrameContext);
|
||||||
|
|
||||||
var buffer1 = new byte[1024];
|
var buffer1 = new byte[1024];
|
||||||
var buffer2 = new byte[1024];
|
var buffer2 = new byte[1024];
|
||||||
|
|
@ -117,7 +117,7 @@ namespace Microsoft.AspNet.Server.KestralTests
|
||||||
var context = new ConnectionContext();
|
var context = new ConnectionContext();
|
||||||
context.SocketInput = new SocketInput(new MemoryPool());
|
context.SocketInput = new SocketInput(new MemoryPool());
|
||||||
|
|
||||||
var exchanger = new MessageBodyExchanger(testInput.ConnectionContext);
|
var exchanger = new MessageBodyExchanger(testInput.FrameContext);
|
||||||
|
|
||||||
var buffer1 = new byte[1024];
|
var buffer1 = new byte[1024];
|
||||||
var buffer2 = new byte[1024];
|
var buffer2 = new byte[1024];
|
||||||
|
|
@ -155,7 +155,7 @@ namespace Microsoft.AspNet.Server.KestralTests
|
||||||
var context = new ConnectionContext();
|
var context = new ConnectionContext();
|
||||||
context.SocketInput = new SocketInput(new MemoryPool());
|
context.SocketInput = new SocketInput(new MemoryPool());
|
||||||
|
|
||||||
var exchanger = new MessageBodyExchanger(testInput.ConnectionContext);
|
var exchanger = new MessageBodyExchanger(testInput.FrameContext);
|
||||||
|
|
||||||
testInput.Add("Hello");
|
testInput.Add("Hello");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ namespace Microsoft.AspNet.Server.KestralTests
|
||||||
public async Task Http10ConnectionClose()
|
public async Task Http10ConnectionClose()
|
||||||
{
|
{
|
||||||
var input = new TestInput();
|
var input = new TestInput();
|
||||||
var body = MessageBody.For("HTTP/1.0", new Dictionary<string, string[]>(), input.ConnectionContext);
|
var body = MessageBody.For("HTTP/1.0", new Dictionary<string, string[]>(), input.FrameContext);
|
||||||
var stream = new FrameRequestStream(body);
|
var stream = new FrameRequestStream(body);
|
||||||
|
|
||||||
input.Add("Hello", true);
|
input.Add("Hello", true);
|
||||||
|
|
@ -35,7 +35,7 @@ namespace Microsoft.AspNet.Server.KestralTests
|
||||||
public async Task Http10ConnectionCloseAsync()
|
public async Task Http10ConnectionCloseAsync()
|
||||||
{
|
{
|
||||||
var input = new TestInput();
|
var input = new TestInput();
|
||||||
var body = MessageBody.For("HTTP/1.0", new Dictionary<string, string[]>(), input.ConnectionContext);
|
var body = MessageBody.For("HTTP/1.0", new Dictionary<string, string[]>(), input.FrameContext);
|
||||||
var stream = new FrameRequestStream(body);
|
var stream = new FrameRequestStream(body);
|
||||||
|
|
||||||
input.Add("Hello", true);
|
input.Add("Hello", true);
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@
|
||||||
<Compile Include="MessageBodyExchangerTests.cs" />
|
<Compile Include="MessageBodyExchangerTests.cs" />
|
||||||
<Compile Include="MessageBodyTests.cs" />
|
<Compile Include="MessageBodyTests.cs" />
|
||||||
<Compile Include="NetworkingTests.cs" />
|
<Compile Include="NetworkingTests.cs" />
|
||||||
|
<Compile Include="TestConnection.cs" />
|
||||||
<Compile Include="TestInput.cs" />
|
<Compile Include="TestInput.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.targets" Condition="'$(VSToolsPath)' != ''" />
|
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,87 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Server.KestralTests
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Summary description for TestConnection
|
||||||
|
/// </summary>
|
||||||
|
public class TestConnection : IDisposable
|
||||||
|
{
|
||||||
|
private Socket _socket;
|
||||||
|
private NetworkStream _stream;
|
||||||
|
private StreamReader _reader;
|
||||||
|
|
||||||
|
public TestConnection()
|
||||||
|
{
|
||||||
|
Create();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Create()
|
||||||
|
{
|
||||||
|
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
||||||
|
_socket.Connect(new IPEndPoint(IPAddress.Loopback, 4001));
|
||||||
|
|
||||||
|
_stream = new NetworkStream(_socket, false);
|
||||||
|
_reader = new StreamReader(_stream, Encoding.ASCII);
|
||||||
|
}
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_stream.Close();
|
||||||
|
_socket.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Send(params string[] lines)
|
||||||
|
{
|
||||||
|
var text = String.Join("\r\n", lines);
|
||||||
|
var writer = new StreamWriter(_stream, Encoding.ASCII);
|
||||||
|
foreach (var ch in text)
|
||||||
|
{
|
||||||
|
await writer.WriteAsync(ch);
|
||||||
|
await writer.FlushAsync();
|
||||||
|
await Task.Delay(TimeSpan.FromMilliseconds(5));
|
||||||
|
}
|
||||||
|
writer.Flush();
|
||||||
|
_stream.Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SendEnd(params string[] lines)
|
||||||
|
{
|
||||||
|
await Send(lines);
|
||||||
|
_socket.Shutdown(SocketShutdown.Send);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Receive(params string[] lines)
|
||||||
|
{
|
||||||
|
var expected = String.Join("\r\n", lines);
|
||||||
|
var actual = new char[expected.Length];
|
||||||
|
var offset = 0;
|
||||||
|
while (offset < expected.Length)
|
||||||
|
{
|
||||||
|
var task = _reader.ReadAsync(actual, offset, actual.Length - offset);
|
||||||
|
Assert.True(task.Wait(1000), "timeout");
|
||||||
|
var count = await task;
|
||||||
|
if (count == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
offset += count;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.Equal(expected, new String(actual, 0, offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task ReceiveEnd(params string[] lines)
|
||||||
|
{
|
||||||
|
await Receive(lines);
|
||||||
|
var ch = new char[1];
|
||||||
|
var count = await _reader.ReadAsync(ch, 0, 1);
|
||||||
|
Assert.Equal(0, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,32 +3,53 @@ using Microsoft.AspNet.Server.Kestrel.Http;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Server.KestralTests
|
namespace Microsoft.AspNet.Server.KestralTests
|
||||||
{
|
{
|
||||||
class TestInput
|
class TestInput : IConnectionControl, IFrameControl
|
||||||
{
|
{
|
||||||
public TestInput()
|
public TestInput()
|
||||||
{
|
{
|
||||||
var memory = new MemoryPool();
|
var memory = new MemoryPool();
|
||||||
ConnectionContext = new ConnectionContext
|
FrameContext = new FrameContext
|
||||||
{
|
{
|
||||||
SocketInput = new SocketInput(memory),
|
SocketInput = new SocketInput(memory),
|
||||||
Memory = memory,
|
Memory = memory,
|
||||||
|
ConnectionControl = this,
|
||||||
|
FrameControl = this
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
public ConnectionContext ConnectionContext { get; set; }
|
|
||||||
|
public FrameContext FrameContext { get; set; }
|
||||||
|
|
||||||
public void Add(string text, bool fin = false)
|
public void Add(string text, bool fin = false)
|
||||||
{
|
{
|
||||||
var encoding = System.Text.Encoding.ASCII;
|
var encoding = System.Text.Encoding.ASCII;
|
||||||
var count = encoding.GetByteCount(text);
|
var count = encoding.GetByteCount(text);
|
||||||
var buffer = ConnectionContext.SocketInput.Available(text.Length);
|
var buffer = FrameContext.SocketInput.Available(text.Length);
|
||||||
count = encoding.GetBytes(text, 0, text.Length, buffer.Array, buffer.Offset);
|
count = encoding.GetBytes(text, 0, text.Length, buffer.Array, buffer.Offset);
|
||||||
ConnectionContext.SocketInput.Extend(count);
|
FrameContext.SocketInput.Extend(count);
|
||||||
if (fin)
|
if (fin)
|
||||||
{
|
{
|
||||||
ConnectionContext.SocketInput.RemoteIntakeFin = true;
|
FrameContext.SocketInput.RemoteIntakeFin = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ProduceContinue()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Pause()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Resume()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Write(ArraySegment<byte> data, Action<object> callback, object state)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
public void End(ProduceEndType endType)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue