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);
+ }
}
}