Assume zero length on non-keepalive requests without Content-Length or Transfer-Encoding (#1104).
This commit is contained in:
parent
0312da7df3
commit
73656f6503
|
|
@ -234,6 +234,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
var connection = headers.HeaderConnection.ToString();
|
var connection = headers.HeaderConnection.ToString();
|
||||||
if (connection.Length > 0)
|
if (connection.Length > 0)
|
||||||
{
|
{
|
||||||
|
if (connection.Equals("upgrade", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return new ForRemainingData(context);
|
||||||
|
}
|
||||||
|
|
||||||
keepAlive = connection.Equals("keep-alive", StringComparison.OrdinalIgnoreCase);
|
keepAlive = connection.Equals("keep-alive", StringComparison.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -257,12 +262,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keepAlive)
|
return new ForContentLength(keepAlive, 0, context);
|
||||||
{
|
|
||||||
return new ForContentLength(true, 0, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ForRemainingData(context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ForRemainingData : MessageBody
|
private class ForRemainingData : MessageBody
|
||||||
|
|
|
||||||
|
|
@ -53,15 +53,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
||||||
// Disables all code related to computing and limiting the size of the input buffer.
|
// Disables all code related to computing and limiting the size of the input buffer.
|
||||||
Tuple.Create((long?)null, false)
|
Tuple.Create((long?)null, false)
|
||||||
};
|
};
|
||||||
var sendContentLengthHeaderValues = new[] { true, false };
|
|
||||||
var sslValues = new[] { true, false };
|
var sslValues = new[] { true, false };
|
||||||
|
|
||||||
return from maxRequestBufferSize in maxRequestBufferSizeValues
|
return from maxRequestBufferSize in maxRequestBufferSizeValues
|
||||||
from sendContentLengthHeader in sendContentLengthHeaderValues
|
|
||||||
from ssl in sslValues
|
from ssl in sslValues
|
||||||
select new object[] {
|
select new object[] {
|
||||||
maxRequestBufferSize.Item1,
|
maxRequestBufferSize.Item1,
|
||||||
sendContentLengthHeader,
|
|
||||||
ssl,
|
ssl,
|
||||||
maxRequestBufferSize.Item2
|
maxRequestBufferSize.Item2
|
||||||
};
|
};
|
||||||
|
|
@ -70,7 +67,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[MemberData("LargeUploadData")]
|
[MemberData("LargeUploadData")]
|
||||||
public async Task LargeUpload(long? maxRequestBufferSize, bool sendContentLengthHeader, bool ssl, bool expectPause)
|
public async Task LargeUpload(long? maxRequestBufferSize, bool ssl, bool expectPause)
|
||||||
{
|
{
|
||||||
// Parameters
|
// Parameters
|
||||||
var data = new byte[_dataLength];
|
var data = new byte[_dataLength];
|
||||||
|
|
@ -91,7 +88,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
||||||
using (var socket = CreateSocket(port))
|
using (var socket = CreateSocket(port))
|
||||||
using (var stream = await CreateStreamAsync(socket, ssl, host.GetHost()))
|
using (var stream = await CreateStreamAsync(socket, ssl, host.GetHost()))
|
||||||
{
|
{
|
||||||
await WritePostRequestHeaders(stream, sendContentLengthHeader ? (int?)data.Length : null);
|
await WritePostRequestHeaders(stream, data.Length);
|
||||||
|
|
||||||
var bytesWritten = 0;
|
var bytesWritten = 0;
|
||||||
|
|
||||||
|
|
@ -236,15 +233,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
||||||
return socket;
|
return socket;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task WritePostRequestHeaders(Stream stream, int? contentLength)
|
private static async Task WritePostRequestHeaders(Stream stream, int contentLength)
|
||||||
{
|
{
|
||||||
using (var writer = new StreamWriter(stream, Encoding.ASCII, bufferSize: 1024, leaveOpen: true))
|
using (var writer = new StreamWriter(stream, Encoding.ASCII, bufferSize: 1024, leaveOpen: true))
|
||||||
{
|
{
|
||||||
await writer.WriteAsync("POST / HTTP/1.0\r\n");
|
await writer.WriteAsync("POST / HTTP/1.0\r\n");
|
||||||
if (contentLength.HasValue)
|
await writer.WriteAsync($"Content-Length: {contentLength}\r\n");
|
||||||
{
|
|
||||||
await writer.WriteAsync($"Content-Length: {contentLength.Value}\r\n");
|
|
||||||
}
|
|
||||||
await writer.WriteAsync("\r\n");
|
await writer.WriteAsync("\r\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
"0",
|
"0",
|
||||||
"",
|
"",
|
||||||
"POST / HTTP/1.0",
|
"POST / HTTP/1.0",
|
||||||
|
"Content-Length: 7",
|
||||||
"",
|
"",
|
||||||
"Goodbye");
|
"Goodbye");
|
||||||
await connection.Receive(
|
await connection.Receive(
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
var filter = new RewritingConnectionFilter();
|
var filter = new RewritingConnectionFilter();
|
||||||
var serviceContext = new TestServiceContext(filter);
|
var serviceContext = new TestServiceContext(filter);
|
||||||
|
|
||||||
var sendString = "POST / HTTP/1.0\r\n\r\nHello World?";
|
var sendString = "POST / HTTP/1.0\r\nContent-Length: 12\r\n\r\nHello World?";
|
||||||
|
|
||||||
using (var server = new TestServer(App, serviceContext))
|
using (var server = new TestServer(App, serviceContext))
|
||||||
{
|
{
|
||||||
|
|
@ -66,6 +66,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
{
|
{
|
||||||
await connection.SendEnd(
|
await connection.SendEnd(
|
||||||
"POST / HTTP/1.0",
|
"POST / HTTP/1.0",
|
||||||
|
"Content-Length: 12",
|
||||||
"",
|
"",
|
||||||
"Hello World?");
|
"Hello World?");
|
||||||
await connection.ReceiveEnd(
|
await connection.ReceiveEnd(
|
||||||
|
|
@ -91,6 +92,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
{
|
{
|
||||||
await connection.SendEnd(
|
await connection.SendEnd(
|
||||||
"POST / HTTP/1.0",
|
"POST / HTTP/1.0",
|
||||||
|
"Content-Length: 12",
|
||||||
"",
|
"",
|
||||||
"Hello World?");
|
"Hello World?");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@ using Microsoft.AspNetCore.Http.Features;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel;
|
using Microsoft.AspNetCore.Server.Kestrel;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Internal;
|
using Microsoft.AspNetCore.Server.Kestrel.Internal;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Internal.Http;
|
using Microsoft.AspNetCore.Server.Kestrel.Internal.Http;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure;
|
|
||||||
using Microsoft.AspNetCore.Testing;
|
using Microsoft.AspNetCore.Testing;
|
||||||
using Microsoft.Extensions.Internal;
|
using Microsoft.Extensions.Internal;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
@ -108,7 +107,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
var started = engine.CreateServer(address);
|
var started = engine.CreateServer(address);
|
||||||
|
|
||||||
var socket = TestConnection.CreateConnectedLoopbackSocket(address.Port);
|
var socket = TestConnection.CreateConnectedLoopbackSocket(address.Port);
|
||||||
socket.Send(Encoding.ASCII.GetBytes("POST / HTTP/1.0\r\n\r\nHello World"));
|
socket.Send(Encoding.ASCII.GetBytes("POST / HTTP/1.0\r\nContent-Length: 11\r\n\r\nHello World"));
|
||||||
socket.Shutdown(SocketShutdown.Send);
|
socket.Shutdown(SocketShutdown.Send);
|
||||||
var buffer = new byte[8192];
|
var buffer = new byte[8192];
|
||||||
while (true)
|
while (true)
|
||||||
|
|
@ -131,6 +130,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
{
|
{
|
||||||
await connection.SendEnd(
|
await connection.SendEnd(
|
||||||
"POST / HTTP/1.0",
|
"POST / HTTP/1.0",
|
||||||
|
"Content-Length: 11",
|
||||||
"",
|
"",
|
||||||
"Hello World");
|
"Hello World");
|
||||||
await connection.ReceiveEnd(
|
await connection.ReceiveEnd(
|
||||||
|
|
@ -156,6 +156,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
"",
|
"",
|
||||||
"GET / HTTP/1.1",
|
"GET / HTTP/1.1",
|
||||||
"Connection: close",
|
"Connection: close",
|
||||||
|
"Content-Length: 7",
|
||||||
"",
|
"",
|
||||||
"Goodbye");
|
"Goodbye");
|
||||||
await connection.ReceiveEnd(
|
await connection.ReceiveEnd(
|
||||||
|
|
@ -219,7 +220,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
{
|
{
|
||||||
var requestData =
|
var requestData =
|
||||||
Enumerable.Repeat("GET / HTTP/1.1\r\n", loopCount)
|
Enumerable.Repeat("GET / HTTP/1.1\r\n", loopCount)
|
||||||
.Concat(new[] { "GET / HTTP/1.1\r\nConnection: close\r\n\r\nGoodbye" });
|
.Concat(new[] { "GET / HTTP/1.1\r\nContent-Length: 7\r\nConnection: close\r\n\r\nGoodbye" });
|
||||||
|
|
||||||
var response = string.Join("\r\n", new string[] {
|
var response = string.Join("\r\n", new string[] {
|
||||||
"HTTP/1.1 200 OK",
|
"HTTP/1.1 200 OK",
|
||||||
|
|
@ -288,6 +289,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
"Connection: keep-alive",
|
"Connection: keep-alive",
|
||||||
"",
|
"",
|
||||||
"POST / HTTP/1.0",
|
"POST / HTTP/1.0",
|
||||||
|
"Content-Length: 7",
|
||||||
"",
|
"",
|
||||||
"Goodbye");
|
"Goodbye");
|
||||||
await connection.Receive(
|
await connection.Receive(
|
||||||
|
|
@ -320,8 +322,8 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
"Connection: keep-alive",
|
"Connection: keep-alive",
|
||||||
"",
|
"",
|
||||||
"POST / HTTP/1.0",
|
"POST / HTTP/1.0",
|
||||||
"Content-Length: 7",
|
|
||||||
"Connection: keep-alive",
|
"Connection: keep-alive",
|
||||||
|
"Content-Length: 7",
|
||||||
"",
|
"",
|
||||||
"Goodbye");
|
"Goodbye");
|
||||||
await connection.Receive(
|
await connection.Receive(
|
||||||
|
|
@ -354,6 +356,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
"Connection: keep-alive",
|
"Connection: keep-alive",
|
||||||
"",
|
"",
|
||||||
"Hello WorldPOST / HTTP/1.0",
|
"Hello WorldPOST / HTTP/1.0",
|
||||||
|
"Content-Length: 7",
|
||||||
"",
|
"",
|
||||||
"Goodbye");
|
"Goodbye");
|
||||||
await connection.Receive(
|
await connection.Receive(
|
||||||
|
|
@ -461,11 +464,17 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
[MemberData(nameof(ConnectionFilterData))]
|
[MemberData(nameof(ConnectionFilterData))]
|
||||||
public async Task ZeroContentLengthSetAutomaticallyForNonKeepAliveRequests(TestServiceContext testContext)
|
public async Task ZeroContentLengthSetAutomaticallyForNonKeepAliveRequests(TestServiceContext testContext)
|
||||||
{
|
{
|
||||||
using (var server = new TestServer(EmptyApp, testContext))
|
using (var server = new TestServer(async httpContext =>
|
||||||
|
{
|
||||||
|
Assert.Equal(0, await httpContext.Request.Body.ReadAsync(new byte[1], 0, 1).TimeoutAfter(TimeSpan.FromSeconds(10)));
|
||||||
|
}, testContext))
|
||||||
{
|
{
|
||||||
using (var connection = server.CreateConnection())
|
using (var connection = server.CreateConnection())
|
||||||
{
|
{
|
||||||
await connection.SendEnd(
|
// Use Send instead of SendEnd to ensure the connection will remain open while
|
||||||
|
// the app runs and reads 0 bytes from the body nonetheless. This checks that
|
||||||
|
// https://github.com/aspnet/KestrelHttpServer/issues/1104 is not regressing.
|
||||||
|
await connection.Send(
|
||||||
"GET / HTTP/1.1",
|
"GET / HTTP/1.1",
|
||||||
"Connection: close",
|
"Connection: close",
|
||||||
"",
|
"",
|
||||||
|
|
@ -481,7 +490,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
|
|
||||||
using (var connection = server.CreateConnection())
|
using (var connection = server.CreateConnection())
|
||||||
{
|
{
|
||||||
await connection.SendEnd(
|
await connection.Send(
|
||||||
"GET / HTTP/1.0",
|
"GET / HTTP/1.0",
|
||||||
"",
|
"",
|
||||||
"");
|
"");
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
{
|
{
|
||||||
using (var input = new TestInput())
|
using (var input = new TestInput())
|
||||||
{
|
{
|
||||||
var body = MessageBody.For(HttpVersion.Http10, new FrameRequestHeaders(), input.FrameContext);
|
var body = MessageBody.For(HttpVersion.Http10, new FrameRequestHeaders { HeaderContentLength = "5" }, input.FrameContext);
|
||||||
var stream = new FrameRequestStream();
|
var stream = new FrameRequestStream();
|
||||||
stream.StartAcceptingReads(body);
|
stream.StartAcceptingReads(body);
|
||||||
|
|
||||||
|
|
@ -48,7 +48,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
{
|
{
|
||||||
using (var input = new TestInput())
|
using (var input = new TestInput())
|
||||||
{
|
{
|
||||||
var body = MessageBody.For(HttpVersion.Http10, new FrameRequestHeaders(), input.FrameContext);
|
var body = MessageBody.For(HttpVersion.Http10, new FrameRequestHeaders { HeaderContentLength = "5" }, input.FrameContext);
|
||||||
var stream = new FrameRequestStream();
|
var stream = new FrameRequestStream();
|
||||||
stream.StartAcceptingReads(body);
|
stream.StartAcceptingReads(body);
|
||||||
|
|
||||||
|
|
@ -65,7 +65,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task CanHandleLargeBlocks()
|
public void Http10NoContentLength()
|
||||||
{
|
{
|
||||||
using (var input = new TestInput())
|
using (var input = new TestInput())
|
||||||
{
|
{
|
||||||
|
|
@ -73,6 +73,102 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
var stream = new FrameRequestStream();
|
var stream = new FrameRequestStream();
|
||||||
stream.StartAcceptingReads(body);
|
stream.StartAcceptingReads(body);
|
||||||
|
|
||||||
|
input.Add("Hello", true);
|
||||||
|
|
||||||
|
var buffer1 = new byte[1024];
|
||||||
|
Assert.Equal(0, stream.Read(buffer1, 0, 1024));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Http10NoContentLengthAsync()
|
||||||
|
{
|
||||||
|
using (var input = new TestInput())
|
||||||
|
{
|
||||||
|
var body = MessageBody.For(HttpVersion.Http10, new FrameRequestHeaders(), input.FrameContext);
|
||||||
|
var stream = new FrameRequestStream();
|
||||||
|
stream.StartAcceptingReads(body);
|
||||||
|
|
||||||
|
input.Add("Hello", true);
|
||||||
|
|
||||||
|
var buffer1 = new byte[1024];
|
||||||
|
Assert.Equal(0, await stream.ReadAsync(buffer1, 0, 1024));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Http11NoContentLength()
|
||||||
|
{
|
||||||
|
using (var input = new TestInput())
|
||||||
|
{
|
||||||
|
var body = MessageBody.For(HttpVersion.Http11, new FrameRequestHeaders(), input.FrameContext);
|
||||||
|
var stream = new FrameRequestStream();
|
||||||
|
stream.StartAcceptingReads(body);
|
||||||
|
|
||||||
|
input.Add("Hello", true);
|
||||||
|
|
||||||
|
var buffer1 = new byte[1024];
|
||||||
|
Assert.Equal(0, stream.Read(buffer1, 0, 1024));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Http11NoContentLengthAsync()
|
||||||
|
{
|
||||||
|
using (var input = new TestInput())
|
||||||
|
{
|
||||||
|
var body = MessageBody.For(HttpVersion.Http11, new FrameRequestHeaders(), input.FrameContext);
|
||||||
|
var stream = new FrameRequestStream();
|
||||||
|
stream.StartAcceptingReads(body);
|
||||||
|
|
||||||
|
input.Add("Hello", true);
|
||||||
|
|
||||||
|
var buffer1 = new byte[1024];
|
||||||
|
Assert.Equal(0, await stream.ReadAsync(buffer1, 0, 1024));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Http11NoContentLengthConnectionClose()
|
||||||
|
{
|
||||||
|
using (var input = new TestInput())
|
||||||
|
{
|
||||||
|
var body = MessageBody.For(HttpVersion.Http11, new FrameRequestHeaders { HeaderConnection = "close" }, input.FrameContext);
|
||||||
|
var stream = new FrameRequestStream();
|
||||||
|
stream.StartAcceptingReads(body);
|
||||||
|
|
||||||
|
input.Add("Hello", true);
|
||||||
|
|
||||||
|
var buffer1 = new byte[1024];
|
||||||
|
Assert.Equal(0, stream.Read(buffer1, 0, 1024));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Http11NoContentLengthConnectionCloseAsync()
|
||||||
|
{
|
||||||
|
using (var input = new TestInput())
|
||||||
|
{
|
||||||
|
var body = MessageBody.For(HttpVersion.Http11, new FrameRequestHeaders { HeaderConnection = "close" }, input.FrameContext);
|
||||||
|
var stream = new FrameRequestStream();
|
||||||
|
stream.StartAcceptingReads(body);
|
||||||
|
|
||||||
|
input.Add("Hello", true);
|
||||||
|
|
||||||
|
var buffer1 = new byte[1024];
|
||||||
|
Assert.Equal(0, await stream.ReadAsync(buffer1, 0, 1024));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task CanHandleLargeBlocks()
|
||||||
|
{
|
||||||
|
using (var input = new TestInput())
|
||||||
|
{
|
||||||
|
var body = MessageBody.For(HttpVersion.Http10, new FrameRequestHeaders { HeaderContentLength = "8197" }, input.FrameContext);
|
||||||
|
var stream = new FrameRequestStream();
|
||||||
|
stream.StartAcceptingReads(body);
|
||||||
|
|
||||||
// Input needs to be greater than 4032 bytes to allocate a block not backed by a slab.
|
// Input needs to be greater than 4032 bytes to allocate a block not backed by a slab.
|
||||||
var largeInput = new string('a', 8192);
|
var largeInput = new string('a', 8192);
|
||||||
|
|
||||||
|
|
@ -101,8 +197,6 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
|
||||||
|
|
||||||
public static IEnumerable<object[]> RequestData => new[]
|
public static IEnumerable<object[]> RequestData => new[]
|
||||||
{
|
{
|
||||||
// Remaining Data
|
|
||||||
new object[] { new FrameRequestHeaders { HeaderConnection = "close" }, new[] { "Hello ", "World!" } },
|
|
||||||
// Content-Length
|
// Content-Length
|
||||||
new object[] { new FrameRequestHeaders { HeaderContentLength = "12" }, new[] { "Hello ", "World!" } },
|
new object[] { new FrameRequestHeaders { HeaderContentLength = "12" }, new[] { "Hello ", "World!" } },
|
||||||
// Chunked
|
// Chunked
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue