Skip to content

Commit 3e47724

Browse files
Classify header parse errors as bad requests.
Assisted-By: devx/71d171da-b98c-42c2-922b-36328d89d0d6
1 parent 0f3e285 commit 3e47724

20 files changed

Lines changed: 77 additions & 16 deletions

‎lib/protocol/http/error.rb‎

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,17 @@ class RemoteError < Error
2222
# @deprecated Use {RefusedError} instead.
2323
RequestRefusedError = RefusedError
2424

25-
# Represents a bad request error (as opposed to a server error).
26-
# This is used to indicate that the request was malformed or invalid.
25+
# Marks errors which may indicate a malformed or invalid request when raised while processing an incoming request.
2726
module BadRequest
2827
end
2928

30-
# Raised when a singleton (e.g. `content-length`) header is duplicated in a request or response.
31-
class DuplicateHeaderError < Error
29+
# Raised when an HTTP header is malformed or invalid. When raised while processing an incoming request, it may be treated as a bad request.
30+
class InvalidHeaderError < Error
3231
include BadRequest
33-
32+
end
33+
34+
# Raised when a singleton (e.g. `content-length`) header is duplicated in a request or response.
35+
class DuplicateHeaderError < InvalidHeaderError
3436
# @parameter key [String] The header key that was duplicated.
3537
def initialize(key, existing_value, new_value)
3638
super("Duplicate singleton header key: #{key.inspect}")
@@ -62,9 +64,7 @@ def detailed_message(highlight: false)
6264
end
6365

6466
# Raised when an invalid trailer header is encountered in headers.
65-
class InvalidTrailerError < Error
66-
include BadRequest
67-
67+
class InvalidTrailerError < InvalidHeaderError
6868
# @parameter key [String] The trailer key that is invalid.
6969
def initialize(key)
7070
super("Invalid trailer key: #{key.inspect}")

‎lib/protocol/http/header/accept.rb‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class Accept < Split
2323
(?=,|\z) # Match until a comma or end of string
2424
/x
2525

26-
ParseError = Class.new(Error)
26+
ParseError = Class.new(InvalidHeaderError)
2727

2828
MEDIA_RANGE = /\A(?<type>#{TOKEN})\/(?<subtype>#{TOKEN})(?<parameters>.*)\z/
2929

‎lib/protocol/http/header/accept_charset.rb‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ module HTTP
1212
module Header
1313
# The `accept-charset` header represents a list of character sets that the client can accept.
1414
class AcceptCharset < Split
15-
ParseError = Class.new(Error)
15+
ParseError = Class.new(InvalidHeaderError)
1616

1717
# https://tools.ietf.org/html/rfc7231#section-5.3.3
1818
CHARSET = /\A(?<name>#{TOKEN})(;q=(?<q>#{QVALUE}))?\z/

‎lib/protocol/http/header/accept_encoding.rb‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ module HTTP
1212
module Header
1313
# The `accept-encoding` header represents a list of encodings that the client can accept.
1414
class AcceptEncoding < Split
15-
ParseError = Class.new(Error)
15+
ParseError = Class.new(InvalidHeaderError)
1616

1717
# https://tools.ietf.org/html/rfc7231#section-5.3.1
1818
QVALUE = /0(\.[0-9]{0,3})?|1(\.[0]{0,3})?/

‎lib/protocol/http/header/accept_language.rb‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ module HTTP
1212
module Header
1313
# The `accept-language` header represents a list of languages that the client can accept.
1414
class AcceptLanguage < Split
15-
ParseError = Class.new(Error)
15+
ParseError = Class.new(InvalidHeaderError)
1616

1717
# https://tools.ietf.org/html/rfc3066#section-2.1
1818
NAME = /\*|[A-Z]{1,8}(-[A-Z0-9]{1,8})*/i

‎lib/protocol/http/header/digest.rb‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ module Header
2323
# # => "sha-256=X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=, md5=9bb58f26192e4ba00f01e2e7b136bbd8"
2424
# ```
2525
class Digest < Split
26-
ParseError = Class.new(Error)
26+
ParseError = Class.new(InvalidHeaderError)
2727

2828
# https://tools.ietf.org/html/rfc3230#section-4.3.2
2929
ENTRY = /\A(?<algorithm>[a-zA-Z0-9][a-zA-Z0-9\-]*)\s*=\s*(?<value>.*)\z/

‎lib/protocol/http/header/range.rb‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ module HTTP
1010
module Header
1111
# Represents a `range` request header.
1212
class Range
13-
ParseError = Class.new(Error)
13+
ParseError = Class.new(InvalidHeaderError)
1414

1515
TOKEN = /[!#$%&'*+\-.0-9A-Z^_`a-z|~]+/
1616
HEADER = /\A(?<unit>#{TOKEN})=(?<ranges>.*)\z/

‎lib/protocol/http/header/server_timing.rb‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ module Header
2323
# # => "db;dur=53.2, cache;dur=12.1;desc=\"Redis lookup\""
2424
# ```
2525
class ServerTiming < Split
26-
ParseError = Class.new(Error)
26+
ParseError = Class.new(InvalidHeaderError)
2727

2828
# https://www.w3.org/TR/server-timing/
2929
METRIC = /\A(?<name>[a-zA-Z0-9][a-zA-Z0-9_\-]*)(;(?<parameters>.*))?\z/

‎lib/protocol/http/header/te.rb‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ module Header
1414
#
1515
# The `te` header allows a client to indicate which transfer encodings it can handle, and in what order of preference using quality factors.
1616
class TE < Split
17-
ParseError = Class.new(Error)
17+
ParseError = Class.new(InvalidHeaderError)
1818

1919
# Transfer encoding token pattern
2020
TOKEN = /[!#$%&'*+\-.0-9A-Z^_`a-z|~]+/

‎readme.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ Please see the [project documentation](https://socketry.github.io/protocol-http/
3030

3131
Please see the [project releases](https://socketry.github.io/protocol-http/releases/index) for all releases.
3232

33+
### Unreleased
34+
35+
- Introduce `Protocol::HTTP::InvalidHeaderError` for malformed or invalid headers, which can be treated as bad requests.
36+
3337
### v0.71.0
3438

3539
- Parse all cookie pairs from `Cookie` header fields, including multiple semicolon-separated pairs within each field.

0 commit comments

Comments
 (0)