CookiestxtSaver: Hide HttpOnly cookies from old browsers.

This trick is the one that has been used in Mozilla before switching
the cookie database to SQLite.
This commit is contained in:
Akinori MUSHA 2013-03-26 02:14:21 +09:00
parent 8b78e3d1e4
commit bd3ae6c1ae
2 changed files with 31 additions and 5 deletions

View file

@ -28,11 +28,14 @@ class HTTP::CookieJar::CookiestxtSaver < HTTP::CookieJar::AbstractSaver
}
end
HTTPONLY_PREFIX = '#HttpOnly_'
RE_HTTPONLY_PREFIX = /\A#{HTTPONLY_PREFIX}/
# Serializes the cookie into a cookies.txt line.
def cookie_to_record(cookie)
cookie.instance_eval {
[
dot_domain,
@httponly ? HTTPONLY_PREFIX + dot_domain : dot_domain,
@for_domain ? True : False,
@path,
@secure ? True : False,
@ -46,7 +49,15 @@ class HTTP::CookieJar::CookiestxtSaver < HTTP::CookieJar::AbstractSaver
# Parses a line from cookies.txt and returns a cookie object if the
# line represents a cookie record or returns nil otherwise.
def parse_record(line)
return nil if line.match(/^#/)
case line
when RE_HTTPONLY_PREFIX
httponly = true
line = $'
when /\A#/
return nil
else
httponly = false
end
domain,
s_for_domain, # Whether this cookie is for domain
@ -68,6 +79,7 @@ class HTTP::CookieJar::CookiestxtSaver < HTTP::CookieJar::AbstractSaver
:for_domain => s_for_domain == True,
:path => path,
:secure => s_secure == True,
:httponly => httponly,
:expires => expires,
:version => 0)
end

View file

@ -360,12 +360,16 @@ class TestHTTPCookieJar < Test::Unit::TestCase
:value => 'Foo#Baz',
:path => '/foo/',
:for_domain => false))
h_cookie = HTTP::Cookie.new(cookie_values(:name => 'Quux',
:value => 'Foo#Quux',
:httponly => true))
@jar.add(cookie)
@jar.add(s_cookie)
@jar.add(cookie2)
@jar.add(h_cookie)
assert_equal(3, @jar.cookies(url).length)
assert_equal(4, @jar.cookies(url).length)
Dir.mktmpdir do |dir|
filename = File.join(dir, "cookies.txt")
@ -375,11 +379,12 @@ class TestHTTPCookieJar < Test::Unit::TestCase
assert_match(/^\.rubyforge\.org\t.*\tFoo\t/, content)
assert_match(/^rubyforge\.org\t.*\tBaz\t/, content)
assert_match(/^#HttpOnly_\.rubyforge\.org\t/, content)
jar = HTTP::CookieJar.new
jar.load(filename, :cookiestxt) # HACK test the format
cookies = jar.cookies(url)
assert_equal(2, cookies.length)
assert_equal(3, cookies.length)
cookies.each { |cookie|
case cookie.name
when 'Foo'
@ -388,18 +393,27 @@ class TestHTTPCookieJar < Test::Unit::TestCase
assert_equal 'rubyforge.org', cookie.domain
assert_equal true, cookie.for_domain
assert_equal '/', cookie.path
assert_equal false, cookie.httponly?
when 'Baz'
assert_equal 'Foo#Baz', cookie.value
assert_equal 'rubyforge.org', cookie.domain
assert_equal false, cookie.for_domain
assert_equal '/foo/', cookie.path
assert_equal false, cookie.httponly?
when 'Quux'
assert_equal 'Foo#Quux', cookie.value
assert_equal expires, cookie.expires
assert_equal 'rubyforge.org', cookie.domain
assert_equal true, cookie.for_domain
assert_equal '/', cookie.path
assert_equal true, cookie.httponly?
else
raise
end
}
end
assert_equal(3, @jar.cookies(url).length)
assert_equal(4, @jar.cookies(url).length)
end
def test_expire_cookies