This is a rewording of my later posts to bugs@ in:
        https://marc.info/?t=163309376900001&r=1&w=2
====

RFC 7231 [HTTP 1.1] states that, for a HEAD request, the server SHOULD
send the same header fields in response to HEAD as it would for GET,
except that payload headers MAY be omitted.  Content-Length is such
a header field.

The CGI on beta.undeadly.org has been updated (to be RFC-compliant)
such that it does not send a body in response to HEAD requests.
We now how:

#### www.undeadly.org ##########
$ printf "HEAD /cgi?action=front HTTP/1.0\r\nHost: www.undeadly.org\r\n\r\n" \
    | nc -c www.undeadly.org https \
    | head
HTTP/1.0 200 OK
Connection: close
Content-Type: text/html
Date: Wed, 06 Oct 2021 10:24:59 GMT
Server: OpenBSD httpd
Strict-Transport-Security: max-age=31536000; preload

<!DOCTYPE html>
<html lang="en">
<head>

#### beta.undeadly.org #########
$ printf "HEAD /cgi?action=front HTTP/1.0\r\nHost: beta.undeadly.org\r\n\r\n" \
    | nc -c beta.undeadly.org https
HTTP/1.0 200 OK
Connection: close
Content-Length: 0
Content-Type: text/html
Date: Wed, 06 Oct 2021 10:25:01 GMT
Server: OpenBSD httpd
Strict-Transport-Security: max-age=31536000; preload

So, if the CGI treats HEAD the same way as GET [and returns a body],
httpd does not add a Content-Length header.  However, if the CGI behaves
correctly, and does not include the body in the response, httpd _does_
add a Content-Type header.  That's clearly wrong/unhelpful.

I'm insufficiently familiar with the httpd code to be certain that the
patch below is correct, but it fixes the problem in light testing.

Ross
----
Index: server_fcgi.c
===================================================================
RCS file: /cvs/src/usr.sbin/httpd/server_fcgi.c,v
retrieving revision 1.88
diff -u -p -r1.88 server_fcgi.c
--- server_fcgi.c       20 May 2021 15:12:10 -0000      1.88
+++ server_fcgi.c       7 Oct 2021 02:56:07 -0000
@@ -621,12 +621,14 @@ server_fcgi_header(struct client *clt, u
                /* 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);
+                       }
                }
        }
 

Reply via email to