From 5dfcea78ab7b11789b551a4926e0de60463d0909 Mon Sep 17 00:00:00 2001 From: benno Date: Sat, 23 Oct 2021 15:52:44 +0000 Subject: [PATCH] * stop sending the content for head requests, even when its supplied by the fcgi. Required by RFC 7231 and RFC 3875 section 4.3.2. * If the client sends an empty body without a Content-Lenght: do not add the Content-Lenght if it's a HEAD request. If it's a HEAD request, the Content-Lenght should show the size of the equivalent GET request, but we don't know how much that will be so don't lie. found by and fix suggested by Ross L Richardson, Thanks! Additionally: * when the fcgi supplies a Content-Length header, do not remove it and set Transfer-Encoding: chunked. Instead, leave the Content-Lenght header in place, as obviously the fcgi knows how much data will come. ok claudio@ --- usr.sbin/httpd/server_fcgi.c | 48 ++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/usr.sbin/httpd/server_fcgi.c b/usr.sbin/httpd/server_fcgi.c index 0f06f001a33..6542b1f1739 100644 --- a/usr.sbin/httpd/server_fcgi.c +++ b/usr.sbin/httpd/server_fcgi.c @@ -1,4 +1,4 @@ -/* $OpenBSD: server_fcgi.c,v 1.88 2021/05/20 15:12:10 florian Exp $ */ +/* $OpenBSD: server_fcgi.c,v 1.89 2021/10/23 15:52:44 benno Exp $ */ /* * Copyright (c) 2014 Florian Obser @@ -559,6 +559,12 @@ server_fcgi_read(struct bufferevent *bev, void *arg) return; } } + /* Don't send content for HEAD requests */ + if (clt->clt_fcgi.headerssent && + ((struct http_descriptor *) + clt->clt_descreq)->http_method + == HTTP_METHOD_HEAD) + return; if (server_fcgi_writechunk(clt) == -1) { server_abort_http(clt, 500, "encoding error"); @@ -621,29 +627,33 @@ server_fcgi_header(struct client *clt, unsigned int code) /* Can't chunk encode an empty body. */ clt->clt_fcgi.chunked = 0; - /* But then we need a Content-Length... */ - key.kv_key = "Content-Length"; - if ((kv = kv_find(&resp->http_headers, &key)) == NULL) { - if (kv_add(&resp->http_headers, - "Content-Length", "0") == NULL) - return (-1); + /* But then we need a Content-Length unless method is HEAD... */ + if (desc->http_method != HTTP_METHOD_HEAD) { + key.kv_key = "Content-Length"; + if ((kv = kv_find(&resp->http_headers, &key)) == NULL) { + if (kv_add(&resp->http_headers, + "Content-Length", "0") == NULL) + return (-1); + } } } - /* Set chunked encoding */ + /* Send chunked encoding header */ if (clt->clt_fcgi.chunked) { - /* XXX Should we keep and handle Content-Length instead? */ + /* but only if no Content-Length header is supplied */ key.kv_key = "Content-Length"; - if ((kv = kv_find(&resp->http_headers, &key)) != NULL) - kv_delete(&resp->http_headers, kv); - - /* - * XXX What if the FastCGI added some kind of Transfer-Encoding? - * XXX like gzip, deflate or even "chunked"? - */ - if (kv_add(&resp->http_headers, - "Transfer-Encoding", "chunked") == NULL) - return (-1); + if ((kv = kv_find(&resp->http_headers, &key)) != NULL) { + clt->clt_fcgi.chunked = 0; + } else { + /* + * XXX What if the FastCGI added some kind of + * Transfer-Encoding, like gzip, deflate or even + * "chunked"? + */ + if (kv_add(&resp->http_headers, + "Transfer-Encoding", "chunked") == NULL) + return (-1); + } } /* Is it a persistent connection? */ -- 2.20.1