Skip to content

Fix Kestrel's Content-Length handling for 1xx, 204 and 205 responses and CONNECT requests #42956

@halter73

Description

@halter73

Describe the bug

The spec forbids Content-Length headers on 1xx and 204 responses and on 2xx responses to CONNECT requests. Kestrel should not allow responses to violate this spec.

A server MUST NOT send a Content-Length header field in any response with a status code of 1xx (Informational) or 204 (No Content). A server MUST NOT send a Content-Length header field in any 2xx (Successful) response to a CONNECT request (Section 4.3.6 of [RFC7231]).

https://httpwg.org/specs/rfc7230.html#rfc.section.3.3.2

Furthermore, Kestrel should reject non-zero Content-Length headers on 205 responses considering it disallows writing 205 responses with non-empty bodies and the spec requires this (or an empty chunked body or closing the connection but we use Content-Length: 0 because it performs better):

Since the 205 status code implies that no additional content will be provided, a server MUST NOT generate a payload in a 205 response. In other words, a server MUST do one of the following for a 205 response: a) indicate a zero-length body for the response by including a Content-Length header field with a value of 0; b) indicate a zero-length payload for the response by including a Transfer-Encoding header field with a value of chunked and a message body consisting of a single chunk of zero-length; or, c) close the connection immediately after sending the blank line terminating the header section.

https://httpwg.org/specs/rfc7231.html#rfc.section.6.3.6

[StackTraceHidden]
private void ThrowWritingToResponseBodyNotSupported()
{
// Throw Exception for 204, 205, 304 responses.
throw new InvalidOperationException(CoreStrings.FormatWritingToResponseBodyNotSupported(StatusCode));
}

But we also need to make sure that manually setting a non-zero Content-Lenth response header for any of the kinds of responses mentioned above (except 304s) fail since it can never be valid.

Prior discussion: #40882 (comment) and dotnet/yarp#1762.

Expected Behavior

Kestrel should throw before flushing invalid Content-Length headers like it already does for Transfer-Encoding.

Maybe just warning log is justified instead of throwing if the header was Content-Lenth: 0 and it should have simply been omitted, but setting a non-zero Content-Length header on a response that doesn't allow it should always throw.

We need to be careful to still allow Content-Length headers for 304 responses since it is allowed even though it "SHOULD NOT" be generated.

The server generating a 304 response MUST generate any of the following header fields that would have been sent in a 200 (OK) response to the same request: Cache-Control, Content-Location, Date, ETag, Expires, and Vary.

Since the goal of a 304 response is to minimize information transfer when the recipient already has one or more cached representations, a sender SHOULD NOT generate representation metadata other than the above listed fields unless said metadata exists for the purpose of guiding cache updates (e.g., Last-Modified might be useful if the response does not have an ETag field).

https://httpwg.org/specs/rfc7232.html#rfc.section.4.1

Metadata

Metadata

Labels

area-networkingIncludes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractionsfeature-kestrel

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions