Properly close keep alive connections

This commit is contained in:
Stephen Halter 2015-08-04 16:56:08 -07:00
parent 43ebf710ab
commit b162202519
3 changed files with 84 additions and 3 deletions

View File

@ -9,6 +9,9 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
public class Connection : ConnectionContext, IConnectionControl
{
private const int EOF = -4095;
private const int ECONNRESET = -4077;
private static readonly Action<UvStreamHandle, int, Exception, object> _readCallback = ReadCallback;
private static readonly Func<UvStreamHandle, int, object, Libuv.uv_buf_t> _allocCallback = AllocCallback;
@ -54,7 +57,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
SocketInput.Unpin(status);
var normalRead = error == null && status > 0;
var normalDone = status == 0 || status == -4077 || status == -4095;
var normalDone = status == 0 || status == ECONNRESET || status == EOF;
var errorDone = !(normalDone || normalRead);
if (normalRead)

View File

@ -94,7 +94,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
if (input.Buffer.Count == 0 && input.RemoteIntakeFin)
{
_mode = Mode.Terminated;
return;
break;
}
if (!TakeStartLine(input))
@ -102,6 +102,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
if (input.RemoteIntakeFin)
{
_mode = Mode.Terminated;
break;
}
return;
}
@ -113,7 +114,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
if (input.Buffer.Count == 0 && input.RemoteIntakeFin)
{
_mode = Mode.Terminated;
return;
break;
}
var endOfHeaders = false;
@ -124,11 +125,19 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
if (input.RemoteIntakeFin)
{
_mode = Mode.Terminated;
break;
}
return;
}
}
if (_mode == Mode.Terminated)
{
// If we broke out of the above while loop in the Terminated
// state, we don't want to transition to the MessageBody state.
break;
}
//var resumeBody = HandleExpectContinue(callback);
_mode = Mode.MessageBody;
Execute();
@ -145,6 +154,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
return;
case Mode.Terminated:
ConnectionControl.End(ProduceEndType.SocketShutdownSend);
ConnectionControl.End(ProduceEndType.SocketDisconnect);
return;
}
}

View File

@ -468,5 +468,72 @@ namespace Microsoft.AspNet.Server.KestrelTests
}
}
}
[Fact]
public async Task ConnectionClosesWhenFinReceived()
{
using (var server = new TestServer(AppChunked))
{
using (var connection = new TestConnection())
{
await connection.SendEnd(
"GET / HTTP/1.1",
"",
"Post / HTTP/1.1",
"Content-Length: 7",
"",
"Goodbye");
await connection.ReceiveEnd(
"HTTP/1.1 200 OK",
"Content-Length: 0",
"",
"HTTP/1.1 200 OK",
"Content-Length: 7",
"",
"Goodbye");
}
}
}
[Fact]
public async Task ConnectionClosesWhenFinReceivedBeforeRequestCompletes()
{
using (var server = new TestServer(AppChunked))
{
using (var connection = new TestConnection())
{
await connection.SendEnd(
"GET /");
await connection.ReceiveEnd();
}
using (var connection = new TestConnection())
{
await connection.SendEnd(
"GET / HTTP/1.1",
"",
"Post / HTTP/1.1");
await connection.ReceiveEnd(
"HTTP/1.1 200 OK",
"Content-Length: 0",
"",
"");
}
using (var connection = new TestConnection())
{
await connection.SendEnd(
"GET / HTTP/1.1",
"",
"Post / HTTP/1.1",
"Content-Length: 7");
await connection.ReceiveEnd(
"HTTP/1.1 200 OK",
"Content-Length: 0",
"",
"");
}
}
}
}
}