HEAD response can include Content-Length header.

This commit is contained in:
Cesar Blum Silveira 2016-10-12 10:30:53 -07:00
parent ce6e65b1d7
commit ffc3eb3afd
3 changed files with 73 additions and 10 deletions

View File

@ -617,6 +617,21 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
_responseBytesWritten += count;
}
protected void VerifyResponseContentLength()
{
var responseHeaders = FrameResponseHeaders;
if (!HttpMethods.IsHead(Method) &&
!responseHeaders.HasTransferEncoding &&
responseHeaders.HeaderContentLengthValue.HasValue &&
_responseBytesWritten < responseHeaders.HeaderContentLengthValue.Value)
{
_keepAlive = false;
ReportApplicationError(new InvalidOperationException(
$"Response Content-Length mismatch: too few bytes written ({_responseBytesWritten} of {responseHeaders.HeaderContentLengthValue.Value})."));
}
}
private void WriteChunked(ArraySegment<byte> data)
{
SocketOutput.Write(data, chunk: true);

View File

@ -5,6 +5,7 @@ using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
@ -92,16 +93,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
try
{
await _application.ProcessRequestAsync(context).ConfigureAwait(false);
var responseHeaders = FrameResponseHeaders;
if (!responseHeaders.HasTransferEncoding &&
responseHeaders.HasContentLength &&
_responseBytesWritten < responseHeaders.HeaderContentLengthValue.Value)
{
_keepAlive = false;
ReportApplicationError(new InvalidOperationException(
$"Response Content-Length mismatch: too few bytes written ({_responseBytesWritten} of {responseHeaders.HeaderContentLengthValue.Value})."));
}
VerifyResponseContentLength();
}
catch (Exception ex)
{

View File

@ -607,6 +607,62 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
Assert.Equal(0, testLogger.ApplicationErrorsLogged);
}
[Fact]
public async Task HeadResponseCanContainContentLengthHeader()
{
var testLogger = new TestApplicationErrorLogger();
var serviceContext = new TestServiceContext { Log = new TestKestrelTrace(testLogger) };
using (var server = new TestServer(httpContext =>
{
httpContext.Response.ContentLength = 42;
return TaskCache.CompletedTask;
}, serviceContext))
{
using (var connection = server.CreateConnection())
{
await connection.SendEnd(
"HEAD / HTTP/1.1",
"",
"");
await connection.ReceiveEnd(
$"HTTP/1.1 200 OK",
$"Date: {server.Context.DateHeaderValue}",
"Content-Length: 42",
"",
"");
}
}
}
[Fact]
public async Task HeadResponseCanContainContentLengthHeaderButBodyNotWritten()
{
var testLogger = new TestApplicationErrorLogger();
var serviceContext = new TestServiceContext { Log = new TestKestrelTrace(testLogger) };
using (var server = new TestServer(async httpContext =>
{
httpContext.Response.ContentLength = 12;
await httpContext.Response.WriteAsync("hello, world");
}, serviceContext))
{
using (var connection = server.CreateConnection())
{
await connection.SendEnd(
"HEAD / HTTP/1.1",
"",
"");
await connection.ReceiveEnd(
$"HTTP/1.1 200 OK",
$"Date: {server.Context.DateHeaderValue}",
"Content-Length: 12",
"",
"");
}
}
}
public static TheoryData<string, StringValues, string> NullHeaderData
{
get