From: Kirill A. Korinsky Subject: Re: relayd: handle HEAD responses as bodyless To: Rafael Sadowski Cc: OpenBSD tech Date: Thu, 07 May 2026 18:45:59 +0200 On Thu, 07 May 2026 07:22:56 +0200, Rafael Sadowski wrote: > > On Thu May 07, 2026 at 03:17:06AM +0200, Kirill A. Korinsky wrote: > > tech@, > > > > RFC 9110 defines HEAD as GET without response content; RFC 9112 Section > > 6.3 makes the HTTP/1.1 framing rule explicit: any response to a HEAD > > request is terminated by the empty line after the header section, > > regardless of Content-Length or Transfer-Encoding. > > I think here is more: > > "Any response to a HEAD request and any response with a 1xx > (Informational), 204 (No Content), or 304 (Not Modified) status code is > always terminated by the first empty line after the header fields, > regardless of the header fields present in the message, and thus cannot > contain a message body or trailer section." > -- https://www.rfc-editor.org/rfc/rfc9112.html > Yes, I missed that. That leads to this diff with your tweaks. Index: usr.sbin/relayd/relay_http.c =================================================================== RCS file: /home/cvs/src/usr.sbin/relayd/relay_http.c,v diff -u -p -r1.96 relay_http.c --- usr.sbin/relayd/relay_http.c 2 Apr 2026 13:35:36 -0000 1.96 +++ usr.sbin/relayd/relay_http.c 7 May 2026 16:42:51 -0000 @@ -196,6 +196,7 @@ relay_read_http(struct bufferevent *bev, struct kv *upgrade = NULL, *upgrade_ws = NULL; struct kv *connection_close = NULL; int ws_response = 0; + int headers_only = 0; enum httpmethod request_method = HTTP_METHOD_NONE; getmonotime(&con->se_tv_last); @@ -480,6 +481,16 @@ relay_read_http(struct bufferevent *bev, connection_close = kv_find_value(&desc->http_headers, "Connection", "close", ","); + /* + * RFC 9112 section 6.3: these responses end at the empty + * line after the header section. 101 upgrades become streams. + */ + headers_only = cre->dir == RELAY_DIR_RESPONSE && !ws_response && + (request_method == HTTP_METHOD_HEAD || + (desc->http_status >= 100 && desc->http_status < 200) || + desc->http_status == 204 || desc->http_status == 304); + if (headers_only) + cre->toread = 0; switch (desc->http_method) { case HTTP_METHOD_CONNECT: @@ -539,7 +550,7 @@ relay_read_http(struct bufferevent *bev, bev->readcb = relay_read_http; break; } - if (desc->http_chunked) { + if (desc->http_chunked && !headers_only) { /* Chunked transfer encoding */ cre->toread = TOREAD_HTTP_CHUNK_LENGTH; bev->readcb = relay_read_httpchunks; -- wbr, Kirill