Skip to content

Commit

Permalink
fix: cookie-av allows arbitrary casing
Browse files Browse the repository at this point in the history
According to [RFC6265](https://httpwg.org/specs/rfc6265.html#sane-set-cookie), cookie attributes are supposed to be ~PascalCase (`Path`, `HttpOnly`, `Secure`, etc). In practice, browsers are lax in their interpretation of cookie attributes and will allow arbitrary casing (`path`, `Path`, `pAtH`, etc).

Prior to this PR, `Rack::Test::Cookie` only supported lowercased cookie attributes, but this PR allows it to have any casing, making it behave closer to browsers and other cookie jars.

https://github.com/python/cpython/blob/f0d3f10c43c9029378adba11a65b3d1287e4be32/Lib/http/cookiejar.py#L511-L512
https://cs.opensource.google/go/go/+/master:src/net/http/cookie.go;l=126-131;drc=592da0ba474b94b6eceee62b5613f1c9c1ed9c89?q=cookie&ss=go%2Fgo
  • Loading branch information
gmalette authored and jeremyevans committed Nov 27, 2024
1 parent 8e5a77b commit 16a3c5c
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 6 deletions.
8 changes: 5 additions & 3 deletions lib/rack/test/cookie_jar.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def initialize(raw, uri = nil, default_host = DEFAULT_HOST)
@raw, options = raw.split(/[;,] */n, 2)

@name, @value = parse_query(@raw, ';').to_a.first
@options = parse_query(options, ';')
@options = Hash[parse_query(options, ';').map { |k, v| [k.downcase, v] }]

if domain = @options['domain']
@exact_domain_match = false
Expand Down Expand Up @@ -69,7 +69,7 @@ def secure?
# Whether the cookie has the httponly flag, indicating it is not available via
# a javascript API.
def http_only?
@options.key?('HttpOnly') || @options.key?('httponly')
@options.key?('httponly')
end

# The explicit or implicit path for the cookie.
Expand Down Expand Up @@ -110,11 +110,13 @@ def <=>(other)

# A hash of cookie options, including the cookie value, but excluding the cookie name.
def to_h
@options.merge(
hash = @options.merge(
'value' => @value,
'HttpOnly' => http_only?,
'secure' => secure?
)
hash.delete('httponly')
hash
end
alias to_hash to_h

Expand Down
22 changes: 19 additions & 3 deletions spec/rack/test/cookie_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,28 @@ def cookie.expired?; true end
cookie_string = [
'/',
'csrf_id=ABC123',
'path=/',
'expires=Wed, 01 Jan 2020 08:00:00 GMT',
'path=/cookie',
'HttpOnly'
].join(Rack::Test::CookieJar::DELIMITER)
cookie = Rack::Test::Cookie.new(cookie_string)
cookie.path.must_equal '/'
cookie.path.must_equal '/cookie'
end

it 'attribute names are case-insensitive' do
cookie_string = [
'/',
'csrf_id=ABC123',
'Path=/cookie',
'Expires=Wed, 01 Jan 2020 08:00:00 GMT',
'HttpOnly',
'Secure',
].join(Rack::Test::CookieJar::DELIMITER)
cookie = Rack::Test::Cookie.new(cookie_string)

cookie.path.must_equal '/cookie'
cookie.secure?.must_equal true
cookie.http_only?.must_equal true
cookie.expires.must_equal Time.parse('Wed, 01 Jan 2020 08:00:00 GMT')
end

it 'escapes cookie values' do
Expand Down

0 comments on commit 16a3c5c

Please sign in to comment.