Skip to content

Commit 16a3c5c

Browse files
gmalettejeremyevans
authored andcommitted
fix: cookie-av allows arbitrary casing
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
1 parent 8e5a77b commit 16a3c5c

File tree

2 files changed

+24
-6
lines changed

2 files changed

+24
-6
lines changed

lib/rack/test/cookie_jar.rb

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ def initialize(raw, uri = nil, default_host = DEFAULT_HOST)
2828
@raw, options = raw.split(/[;,] */n, 2)
2929

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

3333
if domain = @options['domain']
3434
@exact_domain_match = false
@@ -69,7 +69,7 @@ def secure?
6969
# Whether the cookie has the httponly flag, indicating it is not available via
7070
# a javascript API.
7171
def http_only?
72-
@options.key?('HttpOnly') || @options.key?('httponly')
72+
@options.key?('httponly')
7373
end
7474

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

111111
# A hash of cookie options, including the cookie value, but excluding the cookie name.
112112
def to_h
113-
@options.merge(
113+
hash = @options.merge(
114114
'value' => @value,
115115
'HttpOnly' => http_only?,
116116
'secure' => secure?
117117
)
118+
hash.delete('httponly')
119+
hash
118120
end
119121
alias to_hash to_h
120122

spec/rack/test/cookie_spec.rb

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,28 @@ def cookie.expired?; true end
4949
cookie_string = [
5050
'/',
5151
'csrf_id=ABC123',
52-
'path=/',
53-
'expires=Wed, 01 Jan 2020 08:00:00 GMT',
52+
'path=/cookie',
5453
'HttpOnly'
5554
].join(Rack::Test::CookieJar::DELIMITER)
5655
cookie = Rack::Test::Cookie.new(cookie_string)
57-
cookie.path.must_equal '/'
56+
cookie.path.must_equal '/cookie'
57+
end
58+
59+
it 'attribute names are case-insensitive' do
60+
cookie_string = [
61+
'/',
62+
'csrf_id=ABC123',
63+
'Path=/cookie',
64+
'Expires=Wed, 01 Jan 2020 08:00:00 GMT',
65+
'HttpOnly',
66+
'Secure',
67+
].join(Rack::Test::CookieJar::DELIMITER)
68+
cookie = Rack::Test::Cookie.new(cookie_string)
69+
70+
cookie.path.must_equal '/cookie'
71+
cookie.secure?.must_equal true
72+
cookie.http_only?.must_equal true
73+
cookie.expires.must_equal Time.parse('Wed, 01 Jan 2020 08:00:00 GMT')
5874
end
5975

6076
it 'escapes cookie values' do

0 commit comments

Comments
 (0)