Skip to content

Commit 7ddfa2b

Browse files
committed
Strip trailing OWS from header values. Fixes #47.
1 parent 215afce commit 7ddfa2b

3 files changed

Lines changed: 107 additions & 1 deletion

File tree

lib/protocol/http1/connection.rb

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -500,7 +500,14 @@ def read_headers
500500
break if line.empty?
501501

502502
if match = line.match(HEADER)
503-
fields << [match[1], match[2] || ""]
503+
# The RFCs require stripping of optional whitespace, but only at the end of the field value:
504+
if value = match[2]
505+
value.rstrip!(" \t")
506+
else
507+
value = ""
508+
end
509+
510+
fields << [match[1], value]
504511
else
505512
raise BadHeader, "Could not parse header: #{line.inspect}"
506513
end

releases.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## Unreleased
44

55
- Use chunked encoding when trailers are present, even when body has known length or is empty. Previously, `write_body` would use `write_fixed_length_body` or `write_empty_body` when the body had a length, silently dropping trailers. Per RFC 7230, trailers require chunked transfer encoding since `content-length` cannot coexist with trailers.
6+
- Strip optional whitespace (OWS) from the end of header field values when parsing headers.
67

78
## v0.37.0
89

test/protocol/http1/connection/headers.rb

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,5 +207,103 @@ def validate_headers!(expected_headers = self.headers)
207207
end.to raise_exception(Protocol::HTTP1::BadHeader)
208208
end
209209
end
210+
211+
with "a header with leading whitespace (spaces)" do
212+
let(:headers) {[
213+
"x-test: here it is"
214+
]}
215+
216+
it "strips leading spaces" do
217+
authority, method, target, version, headers, body = server.read_request
218+
219+
expect(headers).to have_keys(
220+
"x-test" => be == ["here it is"]
221+
)
222+
end
223+
end
224+
225+
with "a header with leading whitespace (tabs)" do
226+
let(:headers) {[
227+
"x-test:\t\there it is"
228+
]}
229+
230+
it "strips leading tabs" do
231+
authority, method, target, version, headers, body = server.read_request
232+
233+
expect(headers).to have_keys(
234+
"x-test" => be == ["here it is"]
235+
)
236+
end
237+
end
238+
239+
with "a header with leading whitespace (mixed)" do
240+
let(:headers) {[
241+
"x-test: \t \there it is"
242+
]}
243+
244+
it "strips leading spaces and tabs" do
245+
authority, method, target, version, headers, body = server.read_request
246+
247+
expect(headers).to have_keys(
248+
"x-test" => be == ["here it is"]
249+
)
250+
end
251+
end
252+
253+
with "a header with trailing whitespace (spaces)" do
254+
let(:headers) {[
255+
"x-test: here it is "
256+
]}
257+
258+
it "strips trailing spaces" do
259+
authority, method, target, version, headers, body = server.read_request
260+
261+
expect(headers).to have_keys(
262+
"x-test" => be == ["here it is"]
263+
)
264+
end
265+
end
266+
267+
with "a header with trailing whitespace (tabs)" do
268+
let(:headers) {[
269+
"x-test: here it is\t\t"
270+
]}
271+
272+
it "strips trailing tabs" do
273+
authority, method, target, version, headers, body = server.read_request
274+
275+
expect(headers).to have_keys(
276+
"x-test" => be == ["here it is"]
277+
)
278+
end
279+
end
280+
281+
with "a header with trailing whitespace (mixed)" do
282+
let(:headers) {[
283+
"x-test: here it is \t \t"
284+
]}
285+
286+
it "strips trailing spaces and tabs" do
287+
authority, method, target, version, headers, body = server.read_request
288+
289+
expect(headers).to have_keys(
290+
"x-test" => be == ["here it is"]
291+
)
292+
end
293+
end
294+
295+
with "a header with both leading and trailing whitespace" do
296+
let(:headers) {[
297+
"x-test: \t here it is \t "
298+
]}
299+
300+
it "strips both leading and trailing whitespace" do
301+
authority, method, target, version, headers, body = server.read_request
302+
303+
expect(headers).to have_keys(
304+
"x-test" => be == ["here it is"]
305+
)
306+
end
307+
end
210308
end
211309
end

0 commit comments

Comments
 (0)