Skip to content

Commit 872aa31

Browse files
authored
Introduce InvalidTrailerError. (#94)
* Prefer `self.to_h` in `Headers#each`.
1 parent 42aa6ab commit 872aa31

4 files changed

Lines changed: 28 additions & 7 deletions

File tree

lib/protocol/http/error.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,18 @@ def initialize(key)
2626
# @attribute [String] key The header key that was duplicated.
2727
attr :key
2828
end
29+
30+
# Raised when an invalid trailer header is encountered in headers.
31+
class InvalidTrailerError < Error
32+
include BadRequest
33+
34+
# @parameter key [String] The trailer key that is invalid.
35+
def initialize(key)
36+
super("Invalid trailer key: #{key.inspect}")
37+
end
38+
39+
# @attribute [String] key The trailer key that is invalid.
40+
attr :key
41+
end
2942
end
3043
end

lib/protocol/http/headers.rb

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ def empty?
191191
# @parameter key [String] The header key.
192192
# @parameter value [String] The raw header value.
193193
def each(&block)
194-
@fields.each(&block)
194+
self.to_h.each(&block)
195195
end
196196

197197
# @returns [Boolean] Whether the headers include the specified key.
@@ -279,7 +279,7 @@ def []=(key, value)
279279
# @parameter key [String] The header key.
280280
# @returns [String | Array | Object] The header value.
281281
def [] key
282-
to_h[key]
282+
self.to_h[key]
283283
end
284284

285285
# Merge the headers into this instance.
@@ -403,11 +403,12 @@ def delete(key)
403403
# @parameter hash [Hash] The hash to merge into.
404404
# @parameter key [String] The header key.
405405
# @parameter value [String] The raw header value.
406+
# @parameter trailer [Boolean] Whether this header is in the trailer section.
406407
protected def merge_into(hash, key, value, trailer = @tail)
407408
if policy = @policy[key]
408409
# Check if we're adding to trailers and this header is allowed:
409410
if trailer && !policy.trailer?
410-
return false
411+
raise InvalidTrailerError, key
411412
end
412413

413414
if current_value = hash[key]
@@ -418,7 +419,7 @@ def delete(key)
418419
else
419420
# By default, headers are not allowed in trailers:
420421
if trailer
421-
return false
422+
raise InvalidTrailerError, key
422423
end
423424

424425
if hash.key?(key)
@@ -431,6 +432,8 @@ def delete(key)
431432

432433
# Compute a hash table of headers, where the keys are normalized to lower case and the values are normalized according to the policy for that header.
433434
#
435+
# This will enforce policy rules, such as merging multiple headers into arrays, or raising errors for duplicate headers.
436+
#
434437
# @returns [Hash] A hash table of `{key, value}` pairs.
435438
def to_h
436439
unless @indexed
@@ -461,7 +464,7 @@ def inspect
461464
def == other
462465
case other
463466
when Hash
464-
to_h == other
467+
self.to_h == other
465468
when Headers
466469
@fields == other.fields
467470
else

releases.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Releases
22

3+
## Unreleased
4+
5+
- Always use `#parse` when parsing header values from strings to ensure proper normalization and validation.
6+
- Introduce `Protocol::HTTP::InvalidTrailerError` which is raised when a trailer header is not allowed by the current policy.
7+
38
## v0.56.0
49

510
- Introduce `Header::*.parse(value)` which parses a raw header value string into a header instance.

test/protocol/http/headers.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@
153153
end
154154

155155
it "can enumerate fields" do
156-
headers.each.with_index do |field, index|
156+
headers.fields.each_with_index do |field, index|
157157
expect(field).to be == fields[index]
158158
end
159159
end
@@ -343,7 +343,7 @@
343343
it "can't add a #{key.inspect} header in the trailer", unique: key do
344344
trailer = headers.trailer!
345345
headers.add(key, "example")
346-
expect(headers).not.to be(:include?, key)
346+
expect{headers.to_h}.to raise_exception(Protocol::HTTP::InvalidTrailerError)
347347
end
348348
end
349349
end

0 commit comments

Comments
 (0)