summaryrefslogtreecommitdiff
path: root/src/http-header-glue.c
diff options
context:
space:
mode:
authorGlenn Strauss <gstrauss@gluelogic.com>2021-05-14 20:45:59 -0400
committerGlenn Strauss <gstrauss@gluelogic.com>2021-05-14 20:45:59 -0400
commit0532d6763973e55baddbe9e8f371eaae36ce24d6 (patch)
treed97fe245eab0d15a7a46821a395875b978d112df /src/http-header-glue.c
parent5ff9e2f6eb364d735cad31ff7a32a04c6576c67c (diff)
downloadlighttpd-git-0532d6763973e55baddbe9e8f371eaae36ce24d6.tar.gz
[core] document error edge case for HTTP/1.0
When lighttpd is not configured to stream the response body, lighttpd sends partial content with an incorrect Content-Length to an HTTP/1.0 client if a backend sends Transfer-Encoding: chunked in response to lighttpd HTTP/1.1 request (to backend), and the response from the backend ends up truncated. lighttpd could instead send an HTTP/1.0 502 Bad Gateway, but the current implementation chooses to send the partial content. After all, an HTTP/1.0 client is, well, HTTP/1.0, and so of limited intelligence.
Diffstat (limited to 'src/http-header-glue.c')
-rw-r--r--src/http-header-glue.c38
1 files changed, 38 insertions, 0 deletions
diff --git a/src/http-header-glue.c b/src/http-header-glue.c
index 3430e056..4924d88c 100644
--- a/src/http-header-glue.c
+++ b/src/http-header-glue.c
@@ -653,6 +653,44 @@ void http_response_backend_done (request_st * const r) {
if (!r->resp_body_finished) {
if (r->http_version == HTTP_VERSION_1_1)
http_chunk_close(r);
+ #if 0
+ /* This is a lot of work to make it possible for an HTTP/1.0 client
+ * to detect that response is truncated (after lighttpd made an
+ * HTTP/1.1 request to backend, and backend gave a Transfer-Encoding
+ * chunked response instead of sending Content-Length, and lighttpd
+ * is streaming response to client). An HTTP/1.0 client is probably
+ * not checking for truncated response, or else client should really
+ * prefer HTTP/1.1 or better. If lighttpd were streaming response,
+ * there would be no Content-Length and lighttpd would have sent
+ * Connection: close. Alternatively, since not streaming (if these
+ * conditions are true), could send an HTTP status error instead of
+ * sending partial content with a bogus Content-Length. If we do
+ * not send an HTTP error status, then response_start hooks may add
+ * caching headers (e.g. mod_expire, mod_setenv). If in future we
+ * send HTTP error status, might special-case HEAD requests and
+ * clear response body so that response headers (w/o Content-Length)
+ * can be sent. For now, we have chosen to send partial content,
+ * including generating an incorrect Content-Length (later), and not
+ * to take any of these extra steps. */
+ else if (__builtin_expect( (r->http_version == HTTP_VERSION_1_0), 0)
+ && r->gw_dechunk && !r->gw_dechunk->done
+ && !(r->conf.stream_response_body
+ & (FDEVENT_STREAM_RESPONSE
+ |FDEVENT_STREAM_RESPONSE_BUFMIN))) {
+ r->keep_alive = 0; /* disable keep-alive, send bogus length */
+ http_header_response_set(r, HTTP_HEADER_CONTENT_LENGTH,
+ CONST_STR_LEN("Content-Length"),
+ CONST_STR_LEN("9999999999999"));
+ http_header_response_unset(r, HTTP_HEADER_ETAG,
+ CONST_STR_LEN("ETag"));
+ http_header_response_unset(r, HTTP_HEADER_LAST_MODIFIED,
+ CONST_STR_LEN("Last-Modified"));
+ http_header_response_unset(r, HTTP_HEADER_CACHE_CONTROL,
+ CONST_STR_LEN("Cache-Control"));
+ http_header_response_unset(r, HTTP_HEADER_EXPIRES,
+ CONST_STR_LEN("Expires"));
+ }
+ #endif
r->resp_body_finished = 1;
}
default: