parent
ece60cc9f5
commit
7991a9a2e2
|
|
@ -198,9 +198,6 @@
|
|||
<data name="BadRequest_UnrecognizedHTTPVersion" xml:space="preserve">
|
||||
<value>Unrecognized HTTP version: '{detail}'</value>
|
||||
</data>
|
||||
<data name="BadRequest_UpgradeRequestCannotHavePayload" xml:space="preserve">
|
||||
<value>Requests with 'Connection: Upgrade' cannot have content in the request body.</value>
|
||||
</data>
|
||||
<data name="FallbackToIPv4Any" xml:space="preserve">
|
||||
<value>Failed to bind to http://[::]:{port} (IPv6Any). Attempting to bind to http://0.0.0.0:{port} instead.</value>
|
||||
</data>
|
||||
|
|
|
|||
|
|
@ -130,13 +130,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
keepAlive = keepAlive && (connectionOptions & ConnectionOptions.Close) == 0;
|
||||
}
|
||||
|
||||
if (upgrade)
|
||||
// Ignore upgrades if the request has a body. Technically it's possible to support, but we'd have to add a lot
|
||||
// more logic to allow reading/draining the normal body before the connection could be fully upgraded.
|
||||
// See https://tools.ietf.org/html/rfc7230#section-6.7, https://tools.ietf.org/html/rfc7540#section-3.2
|
||||
if (upgrade
|
||||
&& headers.ContentLength.GetValueOrDefault() == 0
|
||||
&& headers.HeaderTransferEncoding.Count == 0)
|
||||
{
|
||||
if (headers.HeaderTransferEncoding.Count > 0 || (headers.ContentLength.HasValue && headers.ContentLength.Value != 0))
|
||||
{
|
||||
KestrelBadHttpRequestException.Throw(RequestRejectionReason.UpgradeRequestCannotHavePayload);
|
||||
}
|
||||
|
||||
context.OnTrailersComplete(); // No trailers for these.
|
||||
return new Http1UpgradeMessageBody(context, keepAlive);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
MissingHostHeader,
|
||||
MultipleHostHeaders,
|
||||
InvalidHostHeader,
|
||||
UpgradeRequestCannotHavePayload,
|
||||
RequestBodyExceedsContentLength
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,9 +88,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core
|
|||
case RequestRejectionReason.InvalidHostHeader:
|
||||
ex = new BadHttpRequestException(CoreStrings.BadRequest_InvalidHostHeader, StatusCodes.Status400BadRequest, reason);
|
||||
break;
|
||||
case RequestRejectionReason.UpgradeRequestCannotHavePayload:
|
||||
ex = new BadHttpRequestException(CoreStrings.BadRequest_UpgradeRequestCannotHavePayload, StatusCodes.Status400BadRequest, reason);
|
||||
break;
|
||||
default:
|
||||
ex = new BadHttpRequestException(CoreStrings.BadRequest, StatusCodes.Status400BadRequest, reason);
|
||||
break;
|
||||
|
|
@ -3,16 +3,16 @@
|
|||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO.Pipelines;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Connections;
|
||||
using Microsoft.AspNetCore.Connections.Features;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests.TestTransport;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Tests;
|
||||
using Microsoft.AspNetCore.Testing;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests
|
||||
|
|
@ -153,9 +153,24 @@ namespace Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RejectsRequestWithContentLengthAndUpgrade()
|
||||
public async Task AcceptsRequestWithContentLengthAndUpgrade()
|
||||
{
|
||||
await using (var server = new TestServer(context => Task.CompletedTask, new TestServiceContext(LoggerFactory)))
|
||||
await using (var server = new TestServer(async context =>
|
||||
{
|
||||
var feature = context.Features.Get<IHttpUpgradeFeature>();
|
||||
|
||||
if (HttpMethods.IsPost(context.Request.Method))
|
||||
{
|
||||
Assert.False(feature.IsUpgradableRequest);
|
||||
Assert.Equal(1, context.Request.ContentLength);
|
||||
Assert.Equal(1, await context.Request.Body.ReadAsync(new byte[10], 0, 10));
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.True(feature.IsUpgradableRequest);
|
||||
}
|
||||
},
|
||||
new TestServiceContext(LoggerFactory)))
|
||||
{
|
||||
using (var connection = server.CreateConnection())
|
||||
{
|
||||
|
|
@ -164,15 +179,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests
|
|||
"Content-Length: 1",
|
||||
"Connection: Upgrade",
|
||||
"",
|
||||
"");
|
||||
"A");
|
||||
|
||||
await connection.ReceiveEnd(
|
||||
"HTTP/1.1 400 Bad Request",
|
||||
"Connection: close",
|
||||
$"Date: {server.Context.DateHeaderValue}",
|
||||
"Content-Length: 0",
|
||||
"",
|
||||
"");
|
||||
await connection.Receive("HTTP/1.1 200 OK");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -180,7 +189,18 @@ namespace Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests
|
|||
[Fact]
|
||||
public async Task AcceptsRequestWithNoContentLengthAndUpgrade()
|
||||
{
|
||||
await using (var server = new TestServer(context => Task.CompletedTask, new TestServiceContext(LoggerFactory)))
|
||||
await using (var server = new TestServer(async context =>
|
||||
{
|
||||
var feature = context.Features.Get<IHttpUpgradeFeature>();
|
||||
Assert.True(feature.IsUpgradableRequest);
|
||||
|
||||
if (HttpMethods.IsPost(context.Request.Method))
|
||||
{
|
||||
Assert.Equal(0, context.Request.ContentLength);
|
||||
}
|
||||
Assert.Equal(0, await context.Request.Body.ReadAsync(new byte[10], 0, 10));
|
||||
},
|
||||
new TestServiceContext(LoggerFactory)))
|
||||
{
|
||||
using (var connection = server.CreateConnection())
|
||||
{
|
||||
|
|
@ -202,9 +222,26 @@ namespace Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RejectsRequestWithChunkedEncodingAndUpgrade()
|
||||
public async Task AcceptsRequestWithChunkedEncodingAndUpgrade()
|
||||
{
|
||||
await using (var server = new TestServer(context => Task.CompletedTask, new TestServiceContext(LoggerFactory)))
|
||||
await using (var server = new TestServer(async context =>
|
||||
{
|
||||
var feature = context.Features.Get<IHttpUpgradeFeature>();
|
||||
|
||||
Assert.Null(context.Request.ContentLength);
|
||||
|
||||
if (HttpMethods.IsPost(context.Request.Method))
|
||||
{
|
||||
Assert.False(feature.IsUpgradableRequest);
|
||||
Assert.Equal("chunked", context.Request.Headers[HeaderNames.TransferEncoding]);
|
||||
Assert.Equal(11, await context.Request.Body.ReadAsync(new byte[12], 0, 12));
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.True(feature.IsUpgradableRequest);
|
||||
}
|
||||
},
|
||||
new TestServiceContext(LoggerFactory)))
|
||||
{
|
||||
using (var connection = server.CreateConnection())
|
||||
{
|
||||
|
|
@ -213,14 +250,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests
|
|||
"Transfer-Encoding: chunked",
|
||||
"Connection: Upgrade",
|
||||
"",
|
||||
"");
|
||||
await connection.ReceiveEnd(
|
||||
"HTTP/1.1 400 Bad Request",
|
||||
"Connection: close",
|
||||
$"Date: {server.Context.DateHeaderValue}",
|
||||
"Content-Length: 0",
|
||||
"B", "Hello World",
|
||||
"0",
|
||||
"",
|
||||
"");
|
||||
await connection.Receive("HTTP/1.1 200 OK");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue