From c057dfdb27e5dab08be55e65fc53aa42f452cdbc Mon Sep 17 00:00:00 2001 From: kirill Date: Sat, 16 May 2026 15:25:28 +0000 Subject: [PATCH] usr.sbin/relayd: handle HTTP responses without bodies RFC 9112 section 6.3 specifies that responses to HEAD requests, and responses with 1xx, 204, or 304 status codes, are terminated by the empty line after the header section regardless of Content-Length or Transfer-Encoding. They cannot contain a message body or trailer section. Teach relayd to apply that framing rule before deciding whether a response body is bounded. Otherwise relayd treats these responses as unbounded, adds Connection: close, and can forward both the backend's Connection: keep-alive and its own Connection: close. Tweaks and OK: rsadowski@ --- usr.sbin/relayd/relay_http.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/usr.sbin/relayd/relay_http.c b/usr.sbin/relayd/relay_http.c index d6960e83eb7..2570940fbba 100644 --- a/usr.sbin/relayd/relay_http.c +++ b/usr.sbin/relayd/relay_http.c @@ -1,4 +1,4 @@ -/* $OpenBSD: relay_http.c,v 1.96 2026/04/02 13:35:36 tb Exp $ */ +/* $OpenBSD: relay_http.c,v 1.97 2026/05/16 15:25:28 kirill Exp $ */ /* * Copyright (c) 2006 - 2016 Reyk Floeter @@ -196,6 +196,7 @@ relay_read_http(struct bufferevent *bev, void *arg) 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, void *arg) 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, void *arg) 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;