-
Notifications
You must be signed in to change notification settings - Fork 523
HEAD response can include Content-Length header #1163
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -617,6 +617,21 @@ private void VerifyAndUpdateWrite(int count) | |
_responseBytesWritten += count; | ||
} | ||
|
||
protected void VerifyResponseContentLength() | ||
{ | ||
var responseHeaders = FrameResponseHeaders; | ||
|
||
if (!HttpMethods.IsHead(Method) && | ||
!responseHeaders.HasTransferEncoding && | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you have to check There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And I prefer checking There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. The spec allows both and There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yikes. I think the spec suggests removing the content-length header in this case which makes sense to me.
https://tools.ietf.org/html/rfc7230#section-3.3.3 @Tratcher thoughts? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. out of scope of the current issue. Apps almost never set Transfer-Encoding so I'm not too worried about it right now. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @halter73 might want to add that as a separate issue to request parsing? (and proxy https://github.com/aspnet/Proxy though I assume the httpclient its using would be handling it) |
||
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); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -607,6 +607,62 @@ await connection.Receive( | |
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; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should have a HEAD test where we set the content-length and attempt to write a response body in the app. We have ResponseTests.ResponseBodyNotWrittenOnHeadResponseAndLoggedOnlyOnce, but it doesn't attempt to set a content-length. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added. |
||
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 | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should you check that if
HttpMethods.IsHead(Method) && responseHeaders.ContentLengthValue.HasValue
then_responseBytesWritten == 0 || _responseBytesWritten == responseHeaders.ContentLengthValue.Value
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I forgot that we actually ignore writes now for HEAD responses. I guess what you have is fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even though we count those bytes, we ignore writes to HEAD responses. It would alert the app that there's an issue, but the error would surface anyways on a response to the same resource using a different method.