Skip to content

Commit d093d22

Browse files
Fix header parsing, allowing for \t characters between VCHAR.
1 parent b01fea1 commit d093d22

File tree

2 files changed

+37
-1
lines changed

2 files changed

+37
-1
lines changed

lib/protocol/http1/connection.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,11 @@ module HTTP1
3737

3838
# HTTP/1.x header parser:
3939
FIELD_NAME = TOKEN
40-
FIELD_VALUE = /[^\000-\037]*/.freeze
40+
41+
# This matches visible characters from ASCII 33 to 126:
42+
VCHAR = /[!-~]/
43+
44+
FIELD_VALUE = /(?:#{VCHAR}+(?:[ \t]+#{VCHAR})*)*/.freeze
4145
HEADER = /\A(#{FIELD_NAME}):\s*(#{FIELD_VALUE})\s*\z/.freeze
4246

4347
VALID_FIELD_NAME = /\A#{FIELD_NAME}\z/.freeze
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# frozen_string_literal: true
2+
3+
# Released under the MIT License.
4+
# Copyright, 2025, by Samuel Williams.
5+
6+
require "protocol/http1/connection"
7+
require "connection_context"
8+
9+
describe Protocol::HTTP1::Connection do
10+
include_context ConnectionContext
11+
12+
let(:headers) {Array.new}
13+
14+
before do
15+
client.stream.write "GET / HTTP/1.1\r\nHost: localhost\r\n#{headers.join("\r\n")}\r\n\r\n"
16+
client.stream.close
17+
end
18+
19+
with "funky user-agent header" do
20+
let(:headers) {[
21+
"user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) \t\t\tChrome/55.0.2883.95 Safari/537.36"
22+
]}
23+
24+
it "reads request without body" do
25+
authority, method, target, version, headers, body = server.read_request
26+
27+
expect(headers).to have_keys(
28+
"user-agent" => be == "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) \t\t\tChrome/55.0.2883.95 Safari/537.36"
29+
)
30+
end
31+
end
32+
end

0 commit comments

Comments
 (0)