Getting request body variations to work
This commit is contained in:
parent
313db3f0cf
commit
044bbb83e6
|
|
@ -45,17 +45,9 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
((Connection)state).OnRead(handle, nread);
|
||||
}
|
||||
|
||||
|
||||
private readonly Func<object, Task> _app;
|
||||
private readonly UvStreamHandle _socket;
|
||||
|
||||
private Frame _frame;
|
||||
|
||||
private Action<Exception> _fault;
|
||||
private Action<Frame, Exception> _frameConsumeCallback;
|
||||
private Action _receiveAsyncCompleted;
|
||||
private Frame _receiveAsyncCompletedFrame;
|
||||
|
||||
public Connection(ListenerContext context, UvStreamHandle socket) : base(context)
|
||||
{
|
||||
_socket = socket;
|
||||
|
|
@ -64,41 +56,10 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
|
||||
public void Start()
|
||||
{
|
||||
//_services.Trace.Event(TraceEventType.Start, TraceMessage.Connection);
|
||||
|
||||
SocketInput = new SocketInput(Memory);
|
||||
SocketOutput = new SocketOutput(Thread, _socket);
|
||||
|
||||
_frame = new Frame(this);
|
||||
_socket.ReadStart(_allocCallback, _readCallback, this);
|
||||
|
||||
//_fault = ex => { Debug.WriteLine(ex.Message); };
|
||||
|
||||
//_frameConsumeCallback = (frame, error) =>
|
||||
//{
|
||||
// if (error != null)
|
||||
// {
|
||||
// _fault(error);
|
||||
// }
|
||||
// try
|
||||
// {
|
||||
// Go(false, frame);
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// _fault(ex);
|
||||
// }
|
||||
//};
|
||||
|
||||
//try
|
||||
//{
|
||||
// //_socket.Blocking = false;
|
||||
// //_socket.NoDelay = true;
|
||||
// Go(true, null);
|
||||
//}
|
||||
//catch (Exception ex)
|
||||
//{
|
||||
// _fault(ex);
|
||||
//}
|
||||
}
|
||||
|
||||
private Libuv.uv_buf_t OnAlloc(UvStreamHandle handle, int suggestedSize)
|
||||
|
|
@ -119,10 +80,6 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
SocketInput.RemoteIntakeFin = true;
|
||||
}
|
||||
|
||||
if (_frame == null)
|
||||
{
|
||||
_frame = new Frame(this);
|
||||
}
|
||||
_frame.Consume();
|
||||
}
|
||||
|
||||
|
|
@ -141,14 +98,26 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
switch (endType)
|
||||
{
|
||||
case ProduceEndType.SocketShutdownSend:
|
||||
var shutdown = new UvShutdownReq();
|
||||
shutdown.Init(Thread.Loop);
|
||||
shutdown.Shutdown(_socket, (req, status, state) => req.Close(), null);
|
||||
Thread.Post(
|
||||
x =>
|
||||
{
|
||||
var self = (Connection)x;
|
||||
var shutdown = new UvShutdownReq();
|
||||
shutdown.Init(self.Thread.Loop);
|
||||
shutdown.Shutdown(self._socket, (req, status, state) => req.Close(), null);
|
||||
},
|
||||
this);
|
||||
break;
|
||||
case ProduceEndType.ConnectionKeepAlive:
|
||||
_frame = new Frame(this);
|
||||
Thread.Post(
|
||||
x => ((Frame)x).Consume(),
|
||||
_frame);
|
||||
break;
|
||||
case ProduceEndType.SocketDisconnect:
|
||||
_socket.Close();
|
||||
Thread.Post(
|
||||
x => ((UvHandle)x).Close(),
|
||||
_socket);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
switch (_mode)
|
||||
{
|
||||
case Mode.StartLine:
|
||||
if (input.RemoteIntakeFin)
|
||||
if (input.Buffer.Count == 0 && input.RemoteIntakeFin)
|
||||
{
|
||||
_mode = Mode.Terminated;
|
||||
return;
|
||||
|
|
@ -95,6 +95,10 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
|
||||
if (!TakeStartLine(input))
|
||||
{
|
||||
if (input.RemoteIntakeFin)
|
||||
{
|
||||
_mode = Mode.Terminated;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -102,7 +106,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
break;
|
||||
|
||||
case Mode.MessageHeader:
|
||||
if (input.RemoteIntakeFin)
|
||||
if (input.Buffer.Count == 0 && input.RemoteIntakeFin)
|
||||
{
|
||||
_mode = Mode.Terminated;
|
||||
return;
|
||||
|
|
@ -113,16 +117,25 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
{
|
||||
if (!TakeMessageHeader(input, out endOfHeaders))
|
||||
{
|
||||
if (input.RemoteIntakeFin)
|
||||
{
|
||||
_mode = Mode.Terminated;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//var resumeBody = HandleExpectContinue(callback);
|
||||
Execute();
|
||||
_mode = Mode.MessageBody;
|
||||
Execute();
|
||||
break;
|
||||
|
||||
case Mode.MessageBody:
|
||||
if (_messageBody.LocalIntakeFin)
|
||||
{
|
||||
// NOTE: stop reading and resume on keepalive?
|
||||
return;
|
||||
}
|
||||
_messageBody.Consume();
|
||||
// NOTE: keep looping?
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -6,24 +6,6 @@ using System.Collections.Generic;
|
|||
|
||||
namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||
{
|
||||
public static class DelegateExtensions
|
||||
{
|
||||
public static void InvokeNoThrow(this Action d)
|
||||
{
|
||||
try
|
||||
{ d.Invoke(); }
|
||||
catch
|
||||
{ }
|
||||
}
|
||||
public static void InvokeNoThrow<T>(this Action<T> d, T arg1)
|
||||
{
|
||||
try
|
||||
{ d.Invoke(arg1); }
|
||||
catch
|
||||
{ }
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class MessageBody : MessageBodyExchanger
|
||||
{
|
||||
private Action _continuation = () => { };
|
||||
|
|
@ -156,8 +138,6 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
var consumeLength = Math.Min(_neededLength, input.Buffer.Count);
|
||||
_neededLength -= consumeLength;
|
||||
|
||||
var consumed = input.Take(consumeLength);
|
||||
|
||||
if (_neededLength != 0)
|
||||
{
|
||||
Intake(consumeLength);
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
uv_loop_close _uv_loop_close;
|
||||
public void loop_close(UvLoopHandle handle)
|
||||
{
|
||||
handle.Validate(closed: true);
|
||||
Check(_uv_loop_close(handle.DangerousGetHandle()));
|
||||
}
|
||||
|
||||
|
|
@ -67,6 +68,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
uv_run _uv_run;
|
||||
public int run(UvLoopHandle handle, int mode)
|
||||
{
|
||||
handle.Validate();
|
||||
return Check(_uv_run(handle, mode));
|
||||
}
|
||||
|
||||
|
|
@ -75,6 +77,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
uv_stop _uv_stop;
|
||||
public void stop(UvLoopHandle handle)
|
||||
{
|
||||
handle.Validate();
|
||||
_uv_stop(handle);
|
||||
}
|
||||
|
||||
|
|
@ -83,6 +86,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
uv_ref _uv_ref;
|
||||
public void @ref(UvHandle handle)
|
||||
{
|
||||
handle.Validate();
|
||||
_uv_ref(handle);
|
||||
}
|
||||
|
||||
|
|
@ -91,6 +95,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
uv_unref _uv_unref;
|
||||
public void unref(UvHandle handle)
|
||||
{
|
||||
handle.Validate();
|
||||
_uv_unref(handle);
|
||||
}
|
||||
|
||||
|
|
@ -102,6 +107,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
uv_close _uv_close;
|
||||
public void close(UvHandle handle, uv_close_cb close_cb)
|
||||
{
|
||||
handle.Validate(closed: true);
|
||||
_uv_close(handle.DangerousGetHandle(), close_cb);
|
||||
}
|
||||
|
||||
|
|
@ -112,6 +118,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
uv_async_init _uv_async_init;
|
||||
public void async_init(UvLoopHandle loop, UvAsyncHandle handle, uv_async_cb cb)
|
||||
{
|
||||
loop.Validate();
|
||||
handle.Validate();
|
||||
Check(_uv_async_init(loop, handle, cb));
|
||||
}
|
||||
|
||||
|
|
@ -128,6 +136,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
uv_tcp_init _uv_tcp_init;
|
||||
public void tcp_init(UvLoopHandle loop, UvTcpHandle handle)
|
||||
{
|
||||
loop.Validate();
|
||||
handle.Validate();
|
||||
Check(_uv_tcp_init(loop, handle));
|
||||
}
|
||||
|
||||
|
|
@ -136,6 +146,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
uv_tcp_bind _uv_tcp_bind;
|
||||
public void tcp_bind(UvTcpHandle handle, ref sockaddr addr, int flags)
|
||||
{
|
||||
handle.Validate();
|
||||
Check(_uv_tcp_bind(handle, ref addr, flags));
|
||||
}
|
||||
|
||||
|
|
@ -146,6 +157,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
uv_listen _uv_listen;
|
||||
public void listen(UvStreamHandle handle, int backlog, uv_connection_cb cb)
|
||||
{
|
||||
handle.Validate();
|
||||
Check(_uv_listen(handle, backlog, cb));
|
||||
}
|
||||
|
||||
|
|
@ -154,6 +166,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
uv_accept _uv_accept;
|
||||
public void accept(UvStreamHandle server, UvStreamHandle client)
|
||||
{
|
||||
server.Validate();
|
||||
client.Validate();
|
||||
Check(_uv_accept(server, client));
|
||||
}
|
||||
|
||||
|
|
@ -166,6 +180,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
uv_read_start _uv_read_start;
|
||||
public void read_start(UvStreamHandle handle, uv_alloc_cb alloc_cb, uv_read_cb read_cb)
|
||||
{
|
||||
handle.Validate();
|
||||
Check(_uv_read_start(handle, alloc_cb, read_cb));
|
||||
}
|
||||
|
||||
|
|
@ -174,6 +189,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
uv_read_stop _uv_read_stop;
|
||||
public void read_stop(UvStreamHandle handle)
|
||||
{
|
||||
handle.Validate();
|
||||
Check(_uv_read_stop(handle));
|
||||
}
|
||||
|
||||
|
|
@ -182,6 +198,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
uv_try_write _uv_try_write;
|
||||
public int try_write(UvStreamHandle handle, Libuv.uv_buf_t[] bufs, int nbufs)
|
||||
{
|
||||
handle.Validate();
|
||||
return Check(_uv_try_write(handle, bufs, nbufs));
|
||||
}
|
||||
|
||||
|
|
@ -192,6 +209,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
uv_write _uv_write;
|
||||
public void write(UvWriteReq req, UvStreamHandle handle, Libuv.uv_buf_t[] bufs, int nbufs, uv_write_cb cb)
|
||||
{
|
||||
req.Validate();
|
||||
handle.Validate();
|
||||
Check(_uv_write(req, handle, bufs, nbufs, cb));
|
||||
}
|
||||
|
||||
|
|
@ -202,6 +221,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
uv_shutdown _uv_shutdown;
|
||||
public void shutdown(UvShutdownReq req, UvStreamHandle handle, uv_shutdown_cb cb)
|
||||
{
|
||||
req.Validate();
|
||||
handle.Validate();
|
||||
Check(_uv_shutdown(req, handle, cb));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,8 +9,6 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
{
|
||||
static Libuv.uv_close_cb _close_cb = DestroyHandle;
|
||||
|
||||
|
||||
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
var memory = handle;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#define TRACE
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace Microsoft.AspNet.Server.Kestrel.Networking
|
||||
{
|
||||
|
|
@ -12,6 +14,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
public abstract class UvMemory : SafeHandle
|
||||
{
|
||||
protected Libuv _uv;
|
||||
int _threadId;
|
||||
|
||||
public UvMemory() : base(IntPtr.Zero, true)
|
||||
{
|
||||
}
|
||||
|
|
@ -29,6 +33,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
unsafe protected void CreateHandle(Libuv uv, int size)
|
||||
{
|
||||
_uv = uv;
|
||||
_threadId = Thread.CurrentThread.ManagedThreadId;
|
||||
|
||||
handle = Marshal.AllocCoTaskMem(size);
|
||||
*(IntPtr*)handle = GCHandle.ToIntPtr(GCHandle.Alloc(this));
|
||||
}
|
||||
|
|
@ -36,8 +42,17 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
protected void CreateHandle(UvLoopHandle loop, int size)
|
||||
{
|
||||
CreateHandle(loop._uv, size);
|
||||
_threadId = loop._threadId;
|
||||
}
|
||||
|
||||
public void Validate(bool closed = false)
|
||||
{
|
||||
Trace.Assert(IsClosed == closed, "Handle is closed");
|
||||
Trace.Assert(!IsInvalid, "Handle is invalid");
|
||||
Trace.Assert(_threadId == Thread.CurrentThread.ManagedThreadId, "ThreadId is correct");
|
||||
}
|
||||
|
||||
|
||||
unsafe protected static void DestroyHandle(IntPtr memory)
|
||||
{
|
||||
var gcHandlePtr = *(IntPtr*)memory;
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
|
||||
public void Init(UvLoopHandle loop)
|
||||
{
|
||||
CreateHandle(loop.Libuv, loop.Libuv.req_size(3));
|
||||
CreateHandle(loop, loop.Libuv.req_size(3));
|
||||
}
|
||||
|
||||
public void Shutdown(UvStreamHandle handle, Action<UvShutdownReq, int, object> callback, object state)
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
|
||||
public void Init(UvLoopHandle loop)
|
||||
{
|
||||
CreateHandle(loop.Libuv, loop.Libuv.req_size(2));
|
||||
CreateHandle(loop, loop.Libuv.req_size(2));
|
||||
}
|
||||
|
||||
public void Write(UvStreamHandle handle, Libuv.uv_buf_t[] bufs, int nbufs, Action<UvWriteReq, int, object> callback, object state)
|
||||
|
|
@ -39,14 +39,6 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
|
||||
public abstract class UvReq : UvMemory
|
||||
{
|
||||
|
||||
unsafe protected void CreateHandle(Libuv uv, int size)
|
||||
{
|
||||
_uv = uv;
|
||||
handle = Marshal.AllocCoTaskMem(size);
|
||||
*(IntPtr*)handle = GCHandle.ToIntPtr(GCHandle.Alloc(this));
|
||||
}
|
||||
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
DestroyHandle(handle);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SampleApp
|
||||
|
|
@ -17,6 +18,8 @@ namespace SampleApp
|
|||
engine.Stop();
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static async Task App(object arg)
|
||||
{
|
||||
var httpContext = new Microsoft.AspNet.PipelineCore.DefaultHttpContext(
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using Microsoft.AspNet.HttpFeature;
|
||||
using Microsoft.AspNet.Server.Kestrel;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
|
|
@ -29,6 +30,25 @@ namespace Microsoft.AspNet.Server.KestralTests
|
|||
await response.Body.WriteAsync(buffer, 0, count);
|
||||
}
|
||||
}
|
||||
private async Task AppChunked(object callContext)
|
||||
{
|
||||
var request = callContext as IHttpRequestFeature;
|
||||
var response = callContext as IHttpResponseFeature;
|
||||
response.Headers["Transfer-Encoding"] = new[] { "chunked" };
|
||||
for (; ;)
|
||||
{
|
||||
var buffer = new byte[8192];
|
||||
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)
|
||||
{
|
||||
break;
|
||||
}
|
||||
await response.Body.WriteAsync(buffer, 0, count);
|
||||
await response.Body.WriteAsync(new[] { (byte)'\r', (byte)'\n' }, 0, 2);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task EngineCanStartAndStop()
|
||||
|
|
@ -70,5 +90,187 @@ namespace Microsoft.AspNet.Server.KestralTests
|
|||
started.Dispose();
|
||||
engine.Stop();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Http10()
|
||||
{
|
||||
var engine = new KestrelEngine();
|
||||
engine.Start(1);
|
||||
var started = engine.CreateServer(App);
|
||||
|
||||
Transceive(
|
||||
@"POST / HTTP/1.0
|
||||
|
||||
Hello World",
|
||||
@"HTTP/1.0 200 OK
|
||||
|
||||
Hello World");
|
||||
started.Dispose();
|
||||
engine.Stop();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Http10ContentLength()
|
||||
{
|
||||
var engine = new KestrelEngine();
|
||||
engine.Start(1);
|
||||
var started = engine.CreateServer(App);
|
||||
|
||||
Transceive(
|
||||
@"POST / HTTP/1.0
|
||||
Content-Length: 5
|
||||
|
||||
Hello World",
|
||||
@"HTTP/1.0 200 OK
|
||||
|
||||
Hello");
|
||||
started.Dispose();
|
||||
engine.Stop();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Http10TransferEncoding()
|
||||
{
|
||||
var engine = new KestrelEngine();
|
||||
engine.Start(1);
|
||||
var started = engine.CreateServer(App);
|
||||
|
||||
Transceive(
|
||||
@"POST / HTTP/1.0
|
||||
Transfer-Encoding: chunked
|
||||
|
||||
5
|
||||
Hello
|
||||
6
|
||||
World
|
||||
0
|
||||
ignored",
|
||||
@"HTTP/1.0 200 OK
|
||||
|
||||
Hello World");
|
||||
started.Dispose();
|
||||
engine.Stop();
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public async Task Http10KeepAlive()
|
||||
{
|
||||
var engine = new KestrelEngine();
|
||||
engine.Start(1);
|
||||
var started = engine.CreateServer(AppChunked);
|
||||
|
||||
Transceive(
|
||||
@"GET / HTTP/1.0
|
||||
Connection: Keep-Alive
|
||||
|
||||
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();
|
||||
engine.Stop();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Http10KeepAliveContentLength()
|
||||
{
|
||||
var engine = new KestrelEngine();
|
||||
engine.Start(1);
|
||||
var started = engine.CreateServer(AppChunked);
|
||||
|
||||
Transceive(
|
||||
@"POST / HTTP/1.0
|
||||
Connection: Keep-Alive
|
||||
Content-Length: 11
|
||||
|
||||
Hello WorldPOST / 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();
|
||||
engine.Stop();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Http10KeepAliveTransferEncoding()
|
||||
{
|
||||
var engine = new KestrelEngine();
|
||||
engine.Start(1);
|
||||
var started = engine.CreateServer(AppChunked);
|
||||
|
||||
Transceive(
|
||||
@"POST / HTTP/1.0
|
||||
Transfer-Encoding: chunked
|
||||
Connection: keep-alive
|
||||
|
||||
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();
|
||||
engine.Stop();
|
||||
}
|
||||
|
||||
|
||||
private void Transceive(string send, string expected)
|
||||
{
|
||||
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
||||
socket.Connect(new IPEndPoint(IPAddress.Loopback, 4001));
|
||||
|
||||
var stream = new NetworkStream(socket, false);
|
||||
var writer = new StreamWriter(stream, Encoding.ASCII);
|
||||
writer.Write(send);
|
||||
writer.Flush();
|
||||
stream.Flush();
|
||||
socket.Shutdown(SocketShutdown.Send);
|
||||
|
||||
var reader = new StreamReader(stream, Encoding.ASCII);
|
||||
var actual = reader.ReadToEnd();
|
||||
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,9 @@
|
|||
"Microsoft.AspNet.Server.Kestrel": "0.1-*"
|
||||
},
|
||||
"configurations": {
|
||||
"net45": {}
|
||||
"net45": {
|
||||
"compilationOptions": { "define": [ "TRACE" ] }
|
||||
}
|
||||
},
|
||||
"commands": {
|
||||
"run": "Xunit.KRunner",
|
||||
|
|
|
|||
Loading…
Reference in New Issue