From ea9fb4df92ef7993d3143970caf11b944484cf29 Mon Sep 17 00:00:00 2001 From: Sutou Kouhei Date: Fri, 18 Sep 2026 18:17:31 +0900 Subject: [PATCH] Treat a whitespace-only header line as obs-fold The current implementation has a problem with the following case: ```ruby print("HTTP/1.1 200 OK\r\n") print("Content-Length: 5\r\n") print(" \t\r\n") print("X-After: value\r\n") print("\r\n") print("hello") ``` The `" \t\r\n"` line should be processed as obs-fold in RFC 9112: https://www.rfc-editor.org/rfc/rfc9112.html#section-5.2 > obs-fold = OWS CRLF RWS > ; obsolete line folding > > A user agent that receives an obs-fold in a response message that > is not within a "message/http" container MUST replace each received > obs-fold with one or more SP octets prior to interpreting the field > value. But it's processed as the header part end: Header: ```text HTTP/1.1 200 OK Content-Length: 5 ``` Body: ```text X-After: value hello ``` It must be processed as the following (whitespace only obs-fold is ignored): Header: ```text HTTP/1.1 200 OK Content-Length: 5 X-After: value ``` Body: ```text hello ``` --- lib/net/http/response.rb | 9 +++++--- test/net/http/test_httpresponse.rb | 34 ++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/lib/net/http/response.rb b/lib/net/http/response.rb index b3b54bed..137744ad 100644 --- a/lib/net/http/response.rb +++ b/lib/net/http/response.rb @@ -188,11 +188,14 @@ def each_response_header(sock) line = read_line(sock, MAX_RESPONSE_HEADER_LENGTH, true) remaining -= line.bytesize raise Net::HTTPBadResponse, 'response header too large' if remaining < 0 - line = line.sub(/\s+\z/, '') + line = line.chomp break if line.empty? if line[0] == ?\s or line[0] == ?\t and value - value << ' ' unless value.empty? - value << line.strip + folded = line.strip + unless folded.empty? + value << ' ' unless value.empty? + value << folded + end else yield key, value if key key, value = line.strip.split(/\s*:\s*/, 2) diff --git a/test/net/http/test_httpresponse.rb b/test/net/http/test_httpresponse.rb index e845f80f..13e26727 100644 --- a/test/net/http/test_httpresponse.rb +++ b/test/net/http/test_httpresponse.rb @@ -93,6 +93,40 @@ def test_multiline_header assert_equal('XXX YYY', res['x-bar']) end + def test_multiline_header_whitespace_only + io = dummy_io(<