Commit 48083d47 authored by Harris Hancock's avatar Harris Hancock

Zero-length HTTP responses to HEAD get no Content-Length header

There is currently no way to explicitly omit a Content-Length/Transfer-Encoding header on an HTTP response to a HEAD request. This is awkward for a proxy, which would ideally pass along responses as-is, even if they have no such headers.

This change allows an author to pass zero as the expected body length to HttpService::Response::send() to mean "do not set any body header." This means that a proxy might strip Content-Length: 0 headers, but will never add a Content-Length header where there was none before.
parent 5bc2d30c
......@@ -809,6 +809,18 @@ kj::ArrayPtr<const HttpResponseTestCase> responseTestCases() {
HttpMethod::HEAD,
},
// Zero-length expected size response to HEAD request has no Content-Length header.
{
"HTTP/1.1 200 OK\r\n"
"\r\n",
200, "OK",
{},
uint64_t(0), {},
HttpMethod::HEAD,
},
{
"HTTP/1.1 200 OK\r\n"
"Content-Length: 8\r\n"
......@@ -1179,6 +1191,22 @@ kj::ArrayPtr<const HttpTestCase> pipelineTestCases() {
200, "OK", {}, 7, { "foo bar" }
},
},
// Zero-length expected size response to HEAD request has no Content-Length header.
{
{
"HEAD / HTTP/1.1\r\n"
"\r\n",
HttpMethod::HEAD, "/", {}, uint64_t(0), {},
},
{
"HTTP/1.1 200 OK\r\n"
"\r\n",
200, "OK", {}, uint64_t(0), {}, HttpMethod::HEAD,
},
},
};
// TODO(cleanup): A bug in GCC 4.8, fixed in 4.9, prevents RESPONSE_TEST_CASES from implicitly
......
......@@ -1603,6 +1603,10 @@ kj::Own<kj::AsyncInputStream> HttpInputStreamImpl::getEntityBody(
kj::Maybe<uint64_t> length;
KJ_IF_MAYBE(cl, headers.get(HttpHeaderId::CONTENT_LENGTH)) {
length = strtoull(cl->cStr(), nullptr, 10);
} else if (headers.get(HttpHeaderId::TRANSFER_ENCODING) == nullptr) {
// HACK: Neither Content-Length nor Transfer-Encoding header in response to HEAD request.
// Propagate this fact with a 0 expected body length.
length = uint64_t(0);
}
return kj::heap<HttpNullEntityReader>(*this, length);
} else if (statusCode == 204 || statusCode == 205 || statusCode == 304) {
......@@ -4384,8 +4388,14 @@ private:
if (statusCode == 204 || statusCode == 205 || statusCode == 304) {
// No entity-body.
} else KJ_IF_MAYBE(s, expectedBodySize) {
lengthStr = kj::str(*s);
connectionHeaders[HttpHeaders::BuiltinIndices::CONTENT_LENGTH] = lengthStr;
// HACK: We interpret a zero-length expected body length on responses to HEAD requests to mean
// "don't set a Content-Length header at all." This provides a way to omit a body header on
// HEAD responses with non-null-body status codes. This is a hack that *only* makes sense
// for HEAD responses.
if (method != HttpMethod::HEAD || *s > 0) {
lengthStr = kj::str(*s);
connectionHeaders[HttpHeaders::BuiltinIndices::CONTENT_LENGTH] = lengthStr;
}
} else {
connectionHeaders[HttpHeaders::BuiltinIndices::TRANSFER_ENCODING] = "chunked";
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment