http-cookie-1.0.5/ 0000755 0000041 0000041 00000000000 14246426325 014003 5 ustar www-data www-data http-cookie-1.0.5/test/ 0000755 0000041 0000041 00000000000 14246426325 014762 5 ustar www-data www-data http-cookie-1.0.5/test/mechanize.yml 0000644 0000041 0000041 00000005572 14246426325 017461 0 ustar www-data www-data --- google.com: /: PREF: !ruby/object:Mechanize::Cookie version: 0 port: discard: comment_url: expires: Tue, 24 Mar 2065 08:20:15 GMT max_age: comment: secure: false path: / domain: google.com accessed_at: 2013-03-24 17:20:15.822619000 +09:00 created_at: 2013-03-24 17:20:15.822619000 +09:00 name: PREF value: ID=7571a59c059e09db:FF=0:TM=1364199615:LM=1364199615:S=BxUqnqPrchd2cVmC for_domain: true domain_name: !ruby/object:DomainName ipaddr: hostname: google.com uri_host: google.com tld: com canonical_tld_p: true domain: google.com session: false NID: !ruby/object:Mechanize::Cookie version: 0 port: discard: comment_url: expires: Sun, 23 Sep 2063 08:20:15 GMT max_age: comment: secure: false path: / domain: google.com accessed_at: 2013-03-24 17:20:15.828434000 +09:00 created_at: 2013-03-24 17:20:15.828434000 +09:00 name: NID value: 67=Kn2osS6wOzILpl7sCM1QIDmGg2VESBiwCyt6zx4vOVSWKOYDlwGIpgIGrpD8FpkbS9eqizo3QWFa5YkOygnCF6vRIQpbvlTxWB2Hq1Oo-qXWy0317yCqQ-B25eJLfUcC for_domain: true domain_name: !ruby/object:DomainName ipaddr: hostname: google.com uri_host: google.com tld: com canonical_tld_p: true domain: google.com session: false google.co.jp: /: PREF: !ruby/object:Mechanize::Cookie version: 0 port: discard: comment_url: expires: Tue, 24 Mar 2065 08:20:16 GMT max_age: comment: secure: false path: / domain: google.co.jp accessed_at: 2013-03-24 17:20:17.136581000 +09:00 created_at: 2013-03-24 17:20:17.136581000 +09:00 name: PREF value: ID=cb25dd1567d8b5c8:FF=0:TM=1364199616:LM=1364199616:S=c3PbhRq79Wo5T_vV for_domain: true domain_name: !ruby/object:DomainName ipaddr: hostname: google.co.jp uri_host: google.co.jp tld: jp canonical_tld_p: true domain: google.co.jp session: false NID: !ruby/object:Mechanize::Cookie version: 0 port: discard: comment_url: expires: Sun, 23 Sep 2063 08:20:16 GMT max_age: comment: secure: false path: / domain: google.co.jp accessed_at: 2013-03-24 17:20:17.139782000 +09:00 created_at: 2013-03-24 17:20:17.139782000 +09:00 name: NID value: 67=GS7P-68zgm_KRA0e0dpN_XbYpmw9uBDe56qUeoCGiSRTahsM7dtOBCKfCoIFRKlzSuOiwJQdIZNpwv3DSXQNHXDKltucgfv2qkHlGeoj8-5VlowPXLLesz2VIpLOLw-a for_domain: true domain_name: !ruby/object:DomainName ipaddr: hostname: google.co.jp uri_host: google.co.jp tld: jp canonical_tld_p: true domain: google.co.jp session: false http-cookie-1.0.5/test/helper.rb 0000644 0000041 0000041 00000002120 14246426325 016561 0 ustar www-data www-data require 'rubygems' require 'test-unit' require 'uri' require 'http/cookie' module Test module Unit module Assertions def assert_warn(pattern, message = nil, &block) class << (output = "") alias write << end stderr, $stderr = $stderr, output yield assert_match(pattern, output, message) ensure $stderr = stderr end def assert_warning(pattern, message = nil, &block) verbose, $VERBOSE = $VERBOSE, true assert_warn(pattern, message, &block) ensure $VERBOSE = verbose end end end end module Enumerable def combine masks = inject([[], 1]){|(ar, m), e| [ar << m, m << 1 ] }[0] all = masks.inject(0){ |al, m| al|m } result = [] for i in 1..all do tmp = [] each_with_index do |e, idx| tmp << e unless (masks[idx] & i) == 0 end result << tmp end result end end def test_file(filename) File.expand_path(filename, File.dirname(__FILE__)) end def sleep_until(time) if (s = time - Time.now) > 0 sleep s end end http-cookie-1.0.5/test/test_http_cookie.rb 0000644 0000041 0000041 00000111476 14246426325 020670 0 ustar www-data www-data # -*- coding: utf-8 -*- require File.expand_path('helper', File.dirname(__FILE__)) require 'psych' if !defined?(YAML) && RUBY_VERSION == "1.9.2" require 'yaml' class TestHTTPCookie < Test::Unit::TestCase def setup httpdate = 'Sun, 27-Sep-2037 00:00:00 GMT' @cookie_params = { 'expires' => 'expires=%s' % httpdate, 'path' => 'path=/', 'domain' => 'domain=.rubyforge.org', 'httponly' => 'HttpOnly', } @expires = Time.parse(httpdate) end def test_parse_dates url = URI.parse('http://localhost/') yesterday = Time.now - 86400 dates = [ "14 Apr 89 03:20:12", "14 Apr 89 03:20 GMT", "Fri, 17 Mar 89 4:01:33", "Fri, 17 Mar 89 4:01 GMT", "Mon Jan 16 16:12 PDT 1989", #"Mon Jan 16 16:12 +0130 1989", "6 May 1992 16:41-JST (Wednesday)", #"22-AUG-1993 10:59:12.82", "22-AUG-1993 10:59pm", "22-AUG-1993 12:59am", "22-AUG-1993 12:59 PM", #"Friday, August 04, 1995 3:54 PM", #"06/21/95 04:24:34 PM", #"20/06/95 21:07", #"95-06-08 19:32:48 EDT", ] dates.each do |date| cookie = "PREF=1; expires=#{date}" assert_equal 1, HTTP::Cookie.parse(cookie, url) { |c| assert c.expires, "Tried parsing: #{date}" assert_send [c.expires, :<, yesterday] }.size end [ ["PREF=1; expires=Wed, 01 Jan 100 12:34:56 GMT", nil], ["PREF=1; expires=Sat, 01 Jan 1600 12:34:56 GMT", nil], ["PREF=1; expires=Tue, 01 Jan 69 12:34:56 GMT", 2069], ["PREF=1; expires=Thu, 01 Jan 70 12:34:56 GMT", 1970], ["PREF=1; expires=Wed, 01 Jan 20 12:34:56 GMT", 2020], ["PREF=1; expires=Sat, 01 Jan 2020 12:34:60 GMT", nil], ["PREF=1; expires=Sat, 01 Jan 2020 12:60:56 GMT", nil], ["PREF=1; expires=Sat, 01 Jan 2020 24:00:00 GMT", nil], ["PREF=1; expires=Sat, 32 Jan 2020 12:34:56 GMT", nil], ].each { |set_cookie, year| cookie, = HTTP::Cookie.parse(set_cookie, url) if year assert_equal year, cookie.expires.year, "#{set_cookie}: expires in #{year}" else assert_equal nil, cookie.expires, "#{set_cookie}: invalid expiry date" end } end def test_parse_empty cookie_str = 'a=b; ; c=d' uri = URI.parse 'http://example' assert_equal 1, HTTP::Cookie.parse(cookie_str, uri) { |cookie| assert_equal 'a', cookie.name assert_equal 'b', cookie.value }.size end def test_parse_no_space cookie_str = "foo=bar;Expires=Sun, 06 Nov 2011 00:28:06 GMT;Path=/" uri = URI.parse 'http://example' assert_equal 1, HTTP::Cookie.parse(cookie_str, uri) { |cookie| assert_equal 'foo', cookie.name assert_equal 'bar', cookie.value assert_equal '/', cookie.path assert_equal Time.at(1320539286), cookie.expires }.size end def test_parse_too_long_cookie uri = URI.parse 'http://example' cookie_str = "foo=#{'Cookie' * 680}; path=/ab/" assert_equal(HTTP::Cookie::MAX_LENGTH - 1, cookie_str.bytesize) assert_equal 1, HTTP::Cookie.parse(cookie_str, uri).size assert_equal 1, HTTP::Cookie.parse(cookie_str.sub(';', 'x;'), uri).size assert_equal 0, HTTP::Cookie.parse(cookie_str.sub(';', 'xx;'), uri).size end def test_parse_quoted cookie_str = "quoted=\"value\"; Expires=Sun, 06 Nov 2011 00:11:18 GMT; Path=/; comment=\"comment is \\\"comment\\\"\"" uri = URI.parse 'http://example' assert_equal 1, HTTP::Cookie.parse(cookie_str, uri) { |cookie| assert_equal 'quoted', cookie.name assert_equal 'value', cookie.value }.size end def test_parse_no_nothing cookie = '; "", ;' url = URI.parse('http://www.example.com/') assert_equal 0, HTTP::Cookie.parse(cookie, url).size end def test_parse_no_name cookie = '=no-name; path=/' url = URI.parse('http://www.example.com/') assert_equal 0, HTTP::Cookie.parse(cookie, url).size end def test_parse_bad_name cookie = "a\001b=c" url = URI.parse('http://www.example.com/') assert_nothing_raised { assert_equal 0, HTTP::Cookie.parse(cookie, url).size } end def test_parse_bad_value cookie = "a=b\001c" url = URI.parse('http://www.example.com/') assert_nothing_raised { assert_equal 0, HTTP::Cookie.parse(cookie, url).size } end def test_parse_weird_cookie cookie = 'n/a, ASPSESSIONIDCSRRQDQR=FBLDGHPBNDJCPCGNCPAENELB; path=/' url = URI.parse('http://www.searchinnovation.com/') assert_equal 1, HTTP::Cookie.parse(cookie, url) { |c| assert_equal('ASPSESSIONIDCSRRQDQR', c.name) assert_equal('FBLDGHPBNDJCPCGNCPAENELB', c.value) }.size end def test_double_semicolon double_semi = 'WSIDC=WEST;; domain=.williams-sonoma.com; path=/' url = URI.parse('http://williams-sonoma.com/') assert_equal 1, HTTP::Cookie.parse(double_semi, url) { |cookie| assert_equal('WSIDC', cookie.name) assert_equal('WEST', cookie.value) }.size end def test_parse_bad_version bad_cookie = 'PRETANET=TGIAqbFXtt; Name=/PRETANET; Path=/; Version=1.2; Content-type=text/html; Domain=192.168.6.196; expires=Friday, 13-November-2026 23:01:46 GMT;' url = URI.parse('http://192.168.6.196/') # The version attribute is obsolete and simply ignored cookies = HTTP::Cookie.parse(bad_cookie, url) assert_equal 1, cookies.size end def test_parse_bad_max_age bad_cookie = 'PRETANET=TGIAqbFXtt; Name=/PRETANET; Path=/; Max-Age=forever; Content-type=text/html; Domain=192.168.6.196; expires=Friday, 13-November-2026 23:01:46 GMT;' url = URI.parse('http://192.168.6.196/') # A bad max-age is simply ignored cookies = HTTP::Cookie.parse(bad_cookie, url) assert_equal 1, cookies.size assert_equal nil, cookies.first.max_age end def test_parse_date_fail url = URI.parse('http://localhost/') dates = [ "20/06/95 21:07", ] dates.each { |date| cookie = "PREF=1; expires=#{date}" assert_equal 1, HTTP::Cookie.parse(cookie, url) { |c| assert_equal(true, c.expires.nil?) }.size } end def test_parse_domain_dot url = URI.parse('http://host.example.com/') cookie_str = 'a=b; domain=.example.com' cookie = HTTP::Cookie.parse(cookie_str, url).first assert_equal 'example.com', cookie.domain assert cookie.for_domain? assert_equal '.example.com', cookie.dot_domain end def test_parse_domain_no_dot url = URI.parse('http://host.example.com/') cookie_str = 'a=b; domain=example.com' cookie = HTTP::Cookie.parse(cookie_str, url).first assert_equal 'example.com', cookie.domain assert cookie.for_domain? assert_equal '.example.com', cookie.dot_domain end def test_parse_public_suffix cookie = HTTP::Cookie.new('a', 'b', :domain => 'com') assert_equal('com', cookie.domain) assert_equal(false, cookie.for_domain?) cookie.origin = 'http://com/' assert_equal('com', cookie.domain) assert_equal(false, cookie.for_domain?) assert_raises(ArgumentError) { cookie.origin = 'http://example.com/' } end def test_parse_domain_none url = URI.parse('http://example.com/') cookie_str = 'a=b;' cookie = HTTP::Cookie.parse(cookie_str, url).first assert_equal 'example.com', cookie.domain assert !cookie.for_domain? assert_equal 'example.com', cookie.dot_domain end def test_parse_max_age url = URI.parse('http://localhost/') epoch, date = 4485353164, 'Fri, 19 Feb 2112 19:26:04 GMT' base = Time.at(1363014000) cookie = HTTP::Cookie.parse("name=Akinori; expires=#{date}", url).first assert_equal Time.at(epoch), cookie.expires cookie = HTTP::Cookie.parse('name=Akinori; max-age=3600', url).first assert_in_delta Time.now + 3600, cookie.expires, 1 cookie = HTTP::Cookie.parse('name=Akinori; max-age=3600', url, :created_at => base).first assert_equal base + 3600, cookie.expires # Max-Age has precedence over Expires cookie = HTTP::Cookie.parse("name=Akinori; max-age=3600; expires=#{date}", url).first assert_in_delta Time.now + 3600, cookie.expires, 1 cookie = HTTP::Cookie.parse("name=Akinori; max-age=3600; expires=#{date}", url, :created_at => base).first assert_equal base + 3600, cookie.expires cookie = HTTP::Cookie.parse("name=Akinori; expires=#{date}; max-age=3600", url).first assert_in_delta Time.now + 3600, cookie.expires, 1 cookie = HTTP::Cookie.parse("name=Akinori; expires=#{date}; max-age=3600", url, :created_at => base).first assert_equal base + 3600, cookie.expires end def test_parse_expires_session url = URI.parse('http://localhost/') [ 'name=Akinori', 'name=Akinori; expires', 'name=Akinori; max-age', 'name=Akinori; expires=', 'name=Akinori; max-age=', ].each { |str| cookie = HTTP::Cookie.parse(str, url).first assert cookie.session?, str } [ 'name=Akinori; expires=Mon, 19 Feb 2012 19:26:04 GMT', 'name=Akinori; max-age=3600', ].each { |str| cookie = HTTP::Cookie.parse(str, url).first assert !cookie.session?, str } end def test_parse_many url = URI 'http://localhost/' cookie_str = "abc, " \ "name=Aaron; Domain=localhost; Expires=Sun, 06 Nov 2011 00:29:51 GMT; Path=/, " \ "name=Aaron; Domain=localhost; Expires=Sun, 06 Nov 2011 00:29:51 GMT; Path=/, " \ "name=Aaron; Domain=localhost; Expires=Sun, 06 Nov 2011 00:29:51 GMT; Path=/, " \ "name=Aaron; Domain=localhost; Expires=Sun, 06 Nov 2011 00:29:51 GMT; Path=/; HttpOnly, " \ "expired=doh; Expires=Fri, 04 Nov 2011 00:29:51 GMT; Path=/, " \ "a_path=some_path; Expires=Sun, 06 Nov 2011 00:29:51 GMT; Path=/some_path, " \ "no_path1=no_path; Expires=Sun, 06 Nov 2011 00:29:52 GMT, no_expires=nope; Path=/, " \ "no_path2=no_path; Expires=Sun, 06 Nov 2011 00:29:52 GMT; no_expires=nope; Path, " \ "no_path3=no_path; Expires=Sun, 06 Nov 2011 00:29:52 GMT; no_expires=nope; Path=, " \ "rel_path1=rel_path; Expires=Sun, 06 Nov 2011 00:29:52 GMT; no_expires=nope; Path=foo/bar, " \ "rel_path1=rel_path; Expires=Sun, 06 Nov 2011 00:29:52 GMT; no_expires=nope; Path=foo, " \ "no_domain1=no_domain; Expires=Sun, 06 Nov 2011 00:29:53 GMT; no_expires=nope, " \ "no_domain2=no_domain; Expires=Sun, 06 Nov 2011 00:29:53 GMT; no_expires=nope; Domain, " \ "no_domain3=no_domain; Expires=Sun, 06 Nov 2011 00:29:53 GMT; no_expires=nope; Domain=" cookies = HTTP::Cookie.parse cookie_str, url assert_equal 15, cookies.length name = cookies.find { |c| c.name == 'name' } assert_equal "Aaron", name.value assert_equal "/", name.path assert_equal Time.at(1320539391), name.expires a_path = cookies.find { |c| c.name == 'a_path' } assert_equal "some_path", a_path.value assert_equal "/some_path", a_path.path assert_equal Time.at(1320539391), a_path.expires no_expires = cookies.find { |c| c.name == 'no_expires' } assert_equal "nope", no_expires.value assert_equal "/", no_expires.path assert_nil no_expires.expires no_path_cookies = cookies.select { |c| c.value == 'no_path' } assert_equal 3, no_path_cookies.size no_path_cookies.each { |c| assert_equal "/", c.path, c.name assert_equal Time.at(1320539392), c.expires, c.name } rel_path_cookies = cookies.select { |c| c.value == 'rel_path' } assert_equal 2, rel_path_cookies.size rel_path_cookies.each { |c| assert_equal "/", c.path, c.name assert_equal Time.at(1320539392), c.expires, c.name } no_domain_cookies = cookies.select { |c| c.value == 'no_domain' } assert_equal 3, no_domain_cookies.size no_domain_cookies.each { |c| assert !c.for_domain?, c.name assert_equal c.domain, url.host, c.name assert_equal Time.at(1320539393), c.expires, c.name } assert cookies.find { |c| c.name == 'expired' } end def test_parse_valid_cookie url = URI.parse('http://rubyforge.org/') cookie_params = @cookie_params cookie_value = '12345%7D=ASDFWEE345%3DASda' cookie_params.keys.combine.each do |keys| cookie_text = [cookie_value, *keys.map { |key| cookie_params[key] }].join('; ') cookie, = HTTP::Cookie.parse(cookie_text, url) assert_equal('12345%7D=ASDFWEE345%3DASda', cookie.to_s) assert_equal('/', cookie.path) assert_equal(keys.include?('expires') ? @expires : nil, cookie.expires) assert_equal(keys.include?('httponly'), cookie.httponly?) end end def test_parse_valid_cookie_empty_value url = URI.parse('http://rubyforge.org/') cookie_params = @cookie_params cookie_value = '12345%7D=' cookie_params.keys.combine.each do |keys| cookie_text = [cookie_value, *keys.map { |key| cookie_params[key] }].join('; ') cookie, = HTTP::Cookie.parse(cookie_text, url) assert_equal('12345%7D=', cookie.to_s) assert_equal('', cookie.value) assert_equal('/', cookie.path) assert_equal(keys.include?('expires') ? @expires : nil, cookie.expires) assert_equal(keys.include?('httponly'), cookie.httponly?) end end # If no path was given, use the one from the URL def test_cookie_using_url_path url = URI.parse('http://rubyforge.org/login.php') cookie_params = @cookie_params cookie_value = '12345%7D=ASDFWEE345%3DASda' cookie_params.keys.combine.each do |keys| next if keys.include?('path') cookie_text = [cookie_value, *keys.map { |key| cookie_params[key] }].join('; ') cookie, = HTTP::Cookie.parse(cookie_text, url) assert_equal('12345%7D=ASDFWEE345%3DASda', cookie.to_s) assert_equal('/', cookie.path) assert_equal(keys.include?('expires') ? @expires : nil, cookie.expires) assert_equal(keys.include?('httponly'), cookie.httponly?) end end # Test using secure cookies def test_cookie_with_secure url = URI.parse('http://rubyforge.org/') cookie_params = @cookie_params.merge('secure' => 'secure') cookie_value = '12345%7D=ASDFWEE345%3DASda' cookie_params.keys.combine.each do |keys| next unless keys.include?('secure') cookie_text = [cookie_value, *keys.map { |key| cookie_params[key] }].join('; ') cookie, = HTTP::Cookie.parse(cookie_text, url) assert_equal('12345%7D=ASDFWEE345%3DASda', cookie.to_s) assert_equal('/', cookie.path) assert_equal(true, cookie.secure) assert_equal(keys.include?('expires') ? @expires : nil, cookie.expires) assert_equal(keys.include?('httponly'), cookie.httponly?) end end def test_cookie_value [ ['foo="bar baz"', 'bar baz'], ['foo="bar\"; \"baz"', 'bar"; "baz'], ].each { |cookie_value, value| cookie = HTTP::Cookie.new('foo', value) assert_equal(cookie_value, cookie.cookie_value) } pairs = [ ['Foo', 'value1'], ['Bar', 'value 2'], ['Baz', 'value3'], ['Bar', 'value"4'], ['Quux', 'x, value=5'], ] cookie_value = HTTP::Cookie.cookie_value(pairs.map { |name, value| HTTP::Cookie.new(:name => name, :value => value) }) assert_equal 'Foo=value1; Bar="value 2"; Baz=value3; Bar="value\\"4"; Quux="x, value=5"', cookie_value hash = HTTP::Cookie.cookie_value_to_hash(cookie_value) assert_equal pairs.map(&:first).uniq.size, hash.size hash.each_pair { |name, value| _, pvalue = pairs.assoc(name) assert_equal pvalue, value } # Do not treat comma in a Cookie header value as separator; see CVE-2016-7401 hash = HTTP::Cookie.cookie_value_to_hash('Quux=x, value=5; Foo=value1; Bar="value 2"; Baz=value3; Bar="value\\"4"') assert_equal pairs.map(&:first).uniq.size, hash.size hash.each_pair { |name, value| _, pvalue = pairs.assoc(name) assert_equal pvalue, value } end def test_set_cookie_value url = URI.parse('http://rubyforge.org/path/') [ HTTP::Cookie.new('a', 'b', :domain => 'rubyforge.org', :path => '/path/'), HTTP::Cookie.new('a', 'b', :origin => url), ].each { |cookie| cookie.set_cookie_value } [ HTTP::Cookie.new('a', 'b', :domain => 'rubyforge.org'), HTTP::Cookie.new('a', 'b', :for_domain => true, :path => '/path/'), ].each { |cookie| assert_raises(RuntimeError) { cookie.set_cookie_value } } ['foo=bar', 'foo="bar"', 'foo="ba\"r baz"'].each { |cookie_value| cookie_params = @cookie_params.merge('path' => '/path/', 'secure' => 'secure', 'max-age' => 'Max-Age=1000') date = Time.at(Time.now.to_i) cookie_params.keys.combine.each do |keys| cookie_text = [cookie_value, *keys.map { |key| cookie_params[key] }].join('; ') cookie, = HTTP::Cookie.parse(cookie_text, url, :created_at => date) cookie2, = HTTP::Cookie.parse(cookie.set_cookie_value, url, :created_at => date) assert_equal(cookie.name, cookie2.name) assert_equal(cookie.value, cookie2.value) assert_equal(cookie.domain, cookie2.domain) assert_equal(cookie.for_domain?, cookie2.for_domain?) assert_equal(cookie.path, cookie2.path) assert_equal(cookie.expires, cookie2.expires) if keys.include?('max-age') assert_equal(date + 1000, cookie2.expires) elsif keys.include?('expires') assert_equal(@expires, cookie2.expires) else assert_equal(nil, cookie2.expires) end assert_equal(cookie.secure?, cookie2.secure?) assert_equal(cookie.httponly?, cookie2.httponly?) end } end def test_parse_cookie_no_spaces url = URI.parse('http://rubyforge.org/') cookie_params = @cookie_params cookie_value = '12345%7D=ASDFWEE345%3DASda' cookie_params.keys.combine.each do |keys| cookie_text = [cookie_value, *keys.map { |key| cookie_params[key] }].join(';') cookie, = HTTP::Cookie.parse(cookie_text, url) assert_equal('12345%7D=ASDFWEE345%3DASda', cookie.to_s) assert_equal('/', cookie.path) assert_equal(keys.include?('expires') ? @expires : nil, cookie.expires) assert_equal(keys.include?('httponly'), cookie.httponly?) end end def test_new cookie = HTTP::Cookie.new('key', 'value') assert_equal 'key', cookie.name assert_equal 'value', cookie.value assert_equal nil, cookie.expires assert_raises(RuntimeError) { cookie.acceptable? } # Minimum unit for the expires attribute is second expires = Time.at((Time.now + 3600).to_i) cookie = HTTP::Cookie.new('key', 'value', :expires => expires.dup) assert_equal 'key', cookie.name assert_equal 'value', cookie.value assert_equal expires, cookie.expires assert_raises(RuntimeError) { cookie.acceptable? } # various keywords [ ["Expires", /use downcased symbol/], ].each { |key, pattern| assert_warning(pattern, "warn of key: #{key.inspect}") { cookie = HTTP::Cookie.new(:value => 'value', :name => 'key', key => expires.dup) assert_equal 'key', cookie.name assert_equal 'value', cookie.value assert_equal expires, cookie.expires, "key: #{key.inspect}" } } [ [:Expires, /unknown attribute name/], [:expires?, /unknown attribute name/], [[:expires], /invalid keyword/], ].each { |key, pattern| assert_warning(pattern, "warn of key: #{key.inspect}") { cookie = HTTP::Cookie.new(:value => 'value', :name => 'key', key => expires.dup) assert_equal 'key', cookie.name assert_equal 'value', cookie.value assert_equal nil, cookie.expires, "key: #{key.inspect}" } } cookie = HTTP::Cookie.new(:value => 'value', :name => 'key', :expires => expires.dup) assert_equal 'key', cookie.name assert_equal 'value', cookie.value assert_equal expires, cookie.expires assert_equal false, cookie.for_domain? assert_raises(RuntimeError) { # domain and path are missing cookie.acceptable? } cookie = HTTP::Cookie.new(:value => 'value', :name => 'key', :expires => expires.dup, :domain => '.example.com') assert_equal 'key', cookie.name assert_equal 'value', cookie.value assert_equal expires, cookie.expires assert_equal true, cookie.for_domain? assert_raises(RuntimeError) { # path is missing cookie.acceptable? } cookie = HTTP::Cookie.new(:value => 'value', :name => 'key', :expires => expires.dup, :domain => 'example.com', :for_domain => false) assert_equal 'key', cookie.name assert_equal 'value', cookie.value assert_equal expires, cookie.expires assert_equal false, cookie.for_domain? assert_raises(RuntimeError) { # path is missing cookie.acceptable? } cookie = HTTP::Cookie.new(:value => 'value', :name => 'key', :expires => expires.dup, :domain => 'example.org', :for_domain? => true) assert_equal 'key', cookie.name assert_equal 'value', cookie.value assert_equal expires, cookie.expires assert_equal 'example.org', cookie.domain assert_equal true, cookie.for_domain? assert_raises(RuntimeError) { # path is missing cookie.acceptable? } assert_raises(ArgumentError) { HTTP::Cookie.new() } assert_raises(ArgumentError) { HTTP::Cookie.new(:value => 'value') } assert_raises(ArgumentError) { HTTP::Cookie.new('', 'value') } assert_raises(ArgumentError) { HTTP::Cookie.new('key=key', 'value') } assert_raises(ArgumentError) { HTTP::Cookie.new("key\tkey", 'value') } assert_raises(ArgumentError) { HTTP::Cookie.new('key', 'value', 'something') } assert_raises(ArgumentError) { HTTP::Cookie.new('key', 'value', {}, 'something') } [ HTTP::Cookie.new(:name => 'name'), HTTP::Cookie.new("key", nil, :for_domain => true), HTTP::Cookie.new("key", nil), HTTP::Cookie.new("key", :secure => true), HTTP::Cookie.new("key"), ].each { |cookie| assert_equal '', cookie.value assert_equal true, cookie.expired? } [ HTTP::Cookie.new(:name => 'name', :max_age => 3600), HTTP::Cookie.new("key", nil, :expires => Time.now + 3600), HTTP::Cookie.new("key", :expires => Time.now + 3600), HTTP::Cookie.new("key", :expires => Time.now + 3600, :value => nil), ].each { |cookie| assert_equal '', cookie.value assert_equal false, cookie.expired? } end def cookie_values(options = {}) { :name => 'Foo', :value => 'Bar', :path => '/', :expires => Time.now + (10 * 86400), :for_domain => true, :domain => 'rubyforge.org', :origin => 'http://rubyforge.org/' }.merge(options) end def test_bad_name [ "a\tb", "a\vb", "a\rb", "a\nb", 'a b', "a\\b", 'a"b', # 'a:b', 'a/b', 'a[b]', 'a=b', 'a,b', 'a;b', ].each { |name| assert_raises(ArgumentError) { HTTP::Cookie.new(cookie_values(:name => name)) } cookie = HTTP::Cookie.new(cookie_values) assert_raises(ArgumentError) { cookie.name = name } } end def test_bad_value [ "a\tb", "a\vb", "a\rb", "a\nb", "a\\b", 'a"b', # 'a:b', 'a/b', 'a[b]', ].each { |name| assert_raises(ArgumentError) { HTTP::Cookie.new(cookie_values(:name => name)) } cookie = HTTP::Cookie.new(cookie_values) assert_raises(ArgumentError) { cookie.name = name } } end def test_compare time = Time.now cookies = [ { :created_at => time + 1 }, { :created_at => time - 1 }, { :created_at => time }, { :created_at => time, :path => '/foo/bar/' }, { :created_at => time, :path => '/foo/' }, { :created_at => time, :path => '/foo' }, ].map { |attrs| HTTP::Cookie.new(cookie_values(attrs)) } assert_equal([3, 4, 5, 1, 2, 0], cookies.sort.map { |i| cookies.find_index { |j| j.equal?(i) } }) end def test_expiration cookie = HTTP::Cookie.new(cookie_values) assert_equal false, cookie.expired? assert_equal true, cookie.expired?(cookie.expires + 1) assert_equal false, cookie.expired?(cookie.expires - 1) cookie.expire! assert_equal true, cookie.expired? end def test_max_age= cookie = HTTP::Cookie.new(cookie_values) expires = cookie.expires assert_raises(ArgumentError) { cookie.max_age = "+1" } # make sure #expires is not destroyed assert_equal expires, cookie.expires assert_raises(ArgumentError) { cookie.max_age = "1.5" } # make sure #expires is not destroyed assert_equal expires, cookie.expires assert_raises(ArgumentError) { cookie.max_age = "1 day" } # make sure #expires is not destroyed assert_equal expires, cookie.expires assert_raises(TypeError) { cookie.max_age = [1] } # make sure #expires is not destroyed assert_equal expires, cookie.expires cookie.max_age = "12" assert_equal 12, cookie.max_age cookie.max_age = -3 assert_equal -3, cookie.max_age end def test_session cookie = HTTP::Cookie.new(cookie_values) assert_equal false, cookie.session? assert_equal nil, cookie.max_age cookie.expires = nil assert_equal true, cookie.session? assert_equal nil, cookie.max_age cookie.expires = Time.now + 3600 assert_equal false, cookie.session? assert_equal nil, cookie.max_age cookie.max_age = 3600 assert_equal false, cookie.session? assert_equal cookie.created_at + 3600, cookie.expires cookie.max_age = nil assert_equal true, cookie.session? assert_equal nil, cookie.expires end def test_equal assert_not_equal(HTTP::Cookie.new(cookie_values), HTTP::Cookie.new(cookie_values(:value => 'bar'))) end def test_new_tld_domain url = URI 'http://rubyforge.org/' tld_cookie1 = HTTP::Cookie.new(cookie_values(:domain => 'org', :origin => url)) assert_equal false, tld_cookie1.for_domain? assert_equal 'org', tld_cookie1.domain assert_equal false, tld_cookie1.acceptable? tld_cookie2 = HTTP::Cookie.new(cookie_values(:domain => '.org', :origin => url)) assert_equal false, tld_cookie1.for_domain? assert_equal 'org', tld_cookie2.domain assert_equal false, tld_cookie2.acceptable? end def test_new_tld_domain_from_tld url = URI 'http://org/' tld_cookie1 = HTTP::Cookie.new(cookie_values(:domain => 'org', :origin => url)) assert_equal false, tld_cookie1.for_domain? assert_equal 'org', tld_cookie1.domain assert_equal true, tld_cookie1.acceptable? tld_cookie2 = HTTP::Cookie.new(cookie_values(:domain => '.org', :origin => url)) assert_equal false, tld_cookie1.for_domain? assert_equal 'org', tld_cookie2.domain assert_equal true, tld_cookie2.acceptable? end def test_fall_back_rules_for_local_domains url = URI 'http://www.example.local' tld_cookie = HTTP::Cookie.new(cookie_values(:domain => '.local', :origin => url)) assert_equal false, tld_cookie.acceptable? sld_cookie = HTTP::Cookie.new(cookie_values(:domain => '.example.local', :origin => url)) assert_equal true, sld_cookie.acceptable? end def test_new_rejects_cookies_with_ipv4_address_subdomain url = URI 'http://192.168.0.1/' cookie = HTTP::Cookie.new(cookie_values(:domain => '.0.1', :origin => url)) assert_equal false, cookie.acceptable? end def test_value cookie = HTTP::Cookie.new('name', 'value') assert_equal 'value', cookie.value cookie.value = 'new value' assert_equal 'new value', cookie.value assert_raises(ArgumentError) { cookie.value = "a\tb" } assert_raises(ArgumentError) { cookie.value = "a\nb" } assert_equal false, cookie.expired? cookie.value = nil assert_equal '', cookie.value assert_equal true, cookie.expired? end def test_path uri = URI.parse('http://example.com/foo/bar') assert_equal '/foo/bar', uri.path cookie_str = 'a=b' cookie = HTTP::Cookie.parse(cookie_str, uri).first assert '/foo/', cookie.path cookie_str = 'a=b; path=/foo' cookie = HTTP::Cookie.parse(cookie_str, uri).first assert '/foo', cookie.path uri = URI.parse('http://example.com') assert_equal '', uri.path cookie_str = 'a=b' cookie = HTTP::Cookie.parse(cookie_str, uri).first assert '/', cookie.path cookie_str = 'a=b; path=/foo' cookie = HTTP::Cookie.parse(cookie_str, uri).first assert '/foo', cookie.path end def test_domain_nil cookie = HTTP::Cookie.new('a', 'b') assert_raises(RuntimeError) { cookie.valid_for_uri?('http://example.com/') } end def test_domain= url = URI.parse('http://host.dom.example.com:8080/') cookie_str = 'a=b; domain=Example.Com' cookie = HTTP::Cookie.parse(cookie_str, url).first assert 'example.com', cookie.domain cookie.domain = DomainName(url.host) assert 'host.dom.example.com', cookie.domain cookie.domain = 'Dom.example.com' assert 'dom.example.com', cookie.domain cookie.domain = Object.new.tap { |o| def o.to_str 'Example.com' end } assert 'example.com', cookie.domain url = URI 'http://rubyforge.org/' [nil, '', '.'].each { |d| cookie = HTTP::Cookie.new('Foo', 'Bar', :path => '/') cookie.domain = d assert_equal nil, cookie.domain, "domain=#{d.inspect}" assert_equal nil, cookie.domain_name, "domain=#{d.inspect}" assert_raises(RuntimeError) { cookie.acceptable? } cookie = HTTP::Cookie.new('Foo', 'Bar', :path => '/') cookie.origin = url cookie.domain = d assert_equal url.host, cookie.domain, "domain=#{d.inspect}" assert_equal true, cookie.acceptable?, "domain=#{d.inspect}" } end def test_origin= url = URI.parse('http://example.com/path/') cookie = HTTP::Cookie.new('a', 'b') assert_raises(ArgumentError) { cookie.origin = 123 } cookie.origin = url assert_equal '/path/', cookie.path assert_equal 'example.com', cookie.domain assert_equal false, cookie.for_domain assert_raises(ArgumentError) { # cannot change the origin once set cookie.origin = URI.parse('http://www.example.com/') } cookie = HTTP::Cookie.new('a', 'b', :domain => '.example.com', :path => '/') cookie.origin = url assert_equal '/', cookie.path assert_equal 'example.com', cookie.domain assert_equal true, cookie.for_domain assert_raises(ArgumentError) { # cannot change the origin once set cookie.origin = URI.parse('http://www.example.com/') } cookie = HTTP::Cookie.new('a', 'b', :domain => '.example.com') cookie.origin = URI.parse('http://example.org/') assert_equal false, cookie.acceptable? cookie = HTTP::Cookie.new('a', 'b', :domain => '.example.com') cookie.origin = 'file:///tmp/test.html' assert_equal nil, cookie.path cookie = HTTP::Cookie.new('a', 'b', :domain => '.example.com', :path => '/') cookie.origin = 'file:///tmp/test.html' assert_equal false, cookie.acceptable? end def test_acceptable_from_uri? cookie = HTTP::Cookie.new(cookie_values( :domain => 'uk', :for_domain => true, :origin => nil)) assert_equal false, cookie.for_domain? assert_equal true, cookie.acceptable_from_uri?('http://uk/') assert_equal false, cookie.acceptable_from_uri?('http://foo.uk/') end def test_valid_for_uri? { HTTP::Cookie.parse('a1=b', 'http://example.com/dir/file.html').first => { true => [ 'http://example.com/dir/', 'http://example.com/dir/test.html', 'https://example.com/dir/', 'https://example.com/dir/test.html', ], false => [ 'file:///dir/test.html', 'http://example.com/dir', 'http://example.com/dir2/test.html', 'http://www.example.com/dir/test.html', 'http://www.example.com/dir2/test.html', 'https://example.com/dir', 'https://example.com/dir2/test.html', 'https://www.example.com/dir/test.html', 'https://www.example.com/dir2/test.html', ] }, HTTP::Cookie.parse('a2=b; path=/dir2/', 'http://example.com/dir/file.html').first => { true => [ 'http://example.com/dir2/', 'http://example.com/dir2/test.html', 'https://example.com/dir2/', 'https://example.com/dir2/test.html', ], false => [ 'file:///dir/test.html', 'http://example.com/dir/test.html', 'http://www.example.com/dir/test.html', 'http://www.example.com/dir2', 'http://www.example.com/dir2/test.html', 'https://example.com/dir/test.html', 'https://www.example.com/dir/test.html', 'https://www.example.com/dir2', 'https://www.example.com/dir2/test.html', ] }, HTTP::Cookie.parse('a4=b; domain=example.com; path=/dir2/', URI('http://example.com/dir/file.html')).first => { true => [ 'https://example.com/dir2/test.html', 'http://example.com/dir2/test.html', 'https://www.example.com/dir2/test.html', 'http://www.example.com/dir2/test.html', ], false => [ 'https://example.com/dir/test.html', 'http://example.com/dir/test.html', 'https://www.example.com/dir/test.html', 'http://www.example.com/dir/test.html', 'file:///dir2/test.html', ] }, HTTP::Cookie.parse('a4=b; secure', URI('https://example.com/dir/file.html')).first => { true => [ 'https://example.com/dir/test.html', ], false => [ 'http://example.com/dir/test.html', 'https://example.com/dir2/test.html', 'http://example.com/dir2/test.html', 'file:///dir2/test.html', ] }, HTTP::Cookie.parse('a5=b', URI('https://example.com/')).first => { true => [ 'https://example.com', ], false => [ 'file:///', ] }, HTTP::Cookie.parse('a6=b; path=/dir', 'http://example.com/dir/file.html').first => { true => [ 'http://example.com/dir', 'http://example.com/dir/', 'http://example.com/dir/test.html', 'https://example.com/dir', 'https://example.com/dir/', 'https://example.com/dir/test.html', ], false => [ 'file:///dir/test.html', 'http://example.com/dir2', 'http://example.com/dir2/test.html', 'http://www.example.com/dir/test.html', 'http://www.example.com/dir2/test.html', 'https://example.com/dir2', 'https://example.com/dir2/test.html', 'https://www.example.com/dir/test.html', 'https://www.example.com/dir2/test.html', ] }, }.each { |cookie, hash| hash.each { |expected, urls| urls.each { |url| assert_equal expected, cookie.valid_for_uri?(url), '%s: %s' % [cookie.name, url] assert_equal expected, cookie.valid_for_uri?(URI(url)), "%s: URI(%s)" % [cookie.name, url] } } } end if YAML.name == 'Psych' && Psych::VERSION >= '3.1' private def load_yaml(yaml) YAML.safe_load(yaml, :permitted_classes => %w[Time HTTP::Cookie Mechanize::Cookie DomainName], :aliases => true) end else private def load_yaml(yaml) YAML.load(yaml) end end def test_yaml_expires require 'yaml' cookie = HTTP::Cookie.new(cookie_values) assert_equal false, cookie.session? assert_equal nil, cookie.max_age ycookie = load_yaml(cookie.to_yaml) assert_equal false, ycookie.session? assert_equal nil, ycookie.max_age assert_in_delta cookie.expires, ycookie.expires, 1 cookie.expires = nil ycookie = load_yaml(cookie.to_yaml) assert_equal true, ycookie.session? assert_equal nil, ycookie.max_age cookie.expires = Time.now + 3600 ycookie = load_yaml(cookie.to_yaml) assert_equal false, ycookie.session? assert_equal nil, ycookie.max_age assert_in_delta cookie.expires, ycookie.expires, 1 cookie.max_age = 3600 ycookie = load_yaml(cookie.to_yaml) assert_equal false, ycookie.session? assert_in_delta cookie.created_at + 3600, ycookie.expires, 1 cookie.max_age = nil ycookie = load_yaml(cookie.to_yaml) assert_equal true, ycookie.session? assert_equal nil, ycookie.expires end def test_s_path_match? assert_equal true, HTTP::Cookie.path_match?('/admin/', '/admin/index') assert_equal false, HTTP::Cookie.path_match?('/admin/', '/Admin/index') assert_equal true, HTTP::Cookie.path_match?('/admin/', '/admin/') assert_equal false, HTTP::Cookie.path_match?('/admin/', '/admin') assert_equal true, HTTP::Cookie.path_match?('/admin', '/admin') assert_equal false, HTTP::Cookie.path_match?('/admin', '/Admin') assert_equal false, HTTP::Cookie.path_match?('/admin', '/admins') assert_equal true, HTTP::Cookie.path_match?('/admin', '/admin/') assert_equal true, HTTP::Cookie.path_match?('/admin', '/admin/index') end end http-cookie-1.0.5/test/test_http_cookie_jar.rb 0000644 0000041 0000041 00000077466 14246426325 021536 0 ustar www-data www-data require File.expand_path('helper', File.dirname(__FILE__)) require 'tmpdir' module TestHTTPCookieJar class TestAutoloading < Test::Unit::TestCase def test_nonexistent_store assert_raises(NameError) { HTTP::CookieJar::NonexistentStore } end def test_erroneous_store Dir.mktmpdir { |dir| Dir.mkdir(File.join(dir, 'http')) Dir.mkdir(File.join(dir, 'http', 'cookie_jar')) rb = File.join(dir, 'http', 'cookie_jar', 'erroneous_store.rb') File.open(rb, 'w').close $LOAD_PATH.unshift(dir) assert_raises(NameError) { HTTP::CookieJar::ErroneousStore } assert($LOADED_FEATURES.any? { |file| FileTest.identical?(file, rb) }) } end def test_nonexistent_saver assert_raises(NameError) { HTTP::CookieJar::NonexistentSaver } end def test_erroneous_saver Dir.mktmpdir { |dir| Dir.mkdir(File.join(dir, 'http')) Dir.mkdir(File.join(dir, 'http', 'cookie_jar')) rb = File.join(dir, 'http', 'cookie_jar', 'erroneous_saver.rb') File.open(rb, 'w').close $LOAD_PATH.unshift(dir) assert_raises(NameError) { HTTP::CookieJar::ErroneousSaver } assert($LOADED_FEATURES.any? { |file| FileTest.identical?(file, rb) }) } end end module CommonTests def setup(options = nil, options2 = nil) default_options = { :store => :hash, :gc_threshold => 1500, # increased by 10 for shorter test time } new_options = default_options.merge(options || {}) new_options2 = new_options.merge(options2 || {}) @store_type = new_options[:store] @gc_threshold = new_options[:gc_threshold] @jar = HTTP::CookieJar.new(new_options) @jar2 = HTTP::CookieJar.new(new_options2) end #def hash_store? # @store_type == :hash #end def mozilla_store? @store_type == :mozilla end def cookie_values(options = {}) { :name => 'Foo', :value => 'Bar', :path => '/', :expires => Time.at(Time.now.to_i + 10 * 86400), # to_i is important here :for_domain => true, :domain => 'rubyforge.org', :origin => 'http://rubyforge.org/' }.merge(options) end def test_empty? assert_equal true, @jar.empty? cookie = HTTP::Cookie.new(cookie_values) @jar.add(cookie) assert_equal false, @jar.empty? assert_equal false, @jar.empty?('http://rubyforge.org/') assert_equal true, @jar.empty?('http://example.local/') end def test_two_cookies_same_domain_and_name_different_paths url = URI 'http://rubyforge.org/' cookie = HTTP::Cookie.new(cookie_values) @jar.add(cookie) @jar.add(HTTP::Cookie.new(cookie_values(:path => '/onetwo'))) assert_equal(1, @jar.cookies(url).length) assert_equal 2, @jar.cookies(URI('http://rubyforge.org/onetwo')).length end def test_domain_case url = URI 'http://rubyforge.org/' # Add one cookie with an expiration date in the future cookie = HTTP::Cookie.new(cookie_values) @jar.add(cookie) assert_equal(1, @jar.cookies(url).length) @jar.add(HTTP::Cookie.new(cookie_values(:domain => 'RuByForge.Org', :name => 'aaron'))) assert_equal(2, @jar.cookies(url).length) url2 = URI 'http://RuByFoRgE.oRg/' assert_equal(2, @jar.cookies(url2).length) end def test_host_only url = URI.parse('http://rubyforge.org/') @jar.add(HTTP::Cookie.new( cookie_values(:domain => 'rubyforge.org', :for_domain => false))) assert_equal(1, @jar.cookies(url).length) assert_equal(1, @jar.cookies(URI('http://RubyForge.org/')).length) assert_equal(1, @jar.cookies(URI('https://RubyForge.org/')).length) assert_equal(0, @jar.cookies(URI('http://www.rubyforge.org/')).length) end def test_host_only_with_unqualified_hostname @jar.add(HTTP::Cookie.new(cookie_values( :origin => 'http://localhost/', :domain => 'localhost', :for_domain => false))) assert_equal(1, @jar.cookies(URI('http://localhost/')).length) assert_equal(1, @jar.cookies(URI('http://Localhost/')).length) assert_equal(1, @jar.cookies(URI('https://Localhost/')).length) end def test_empty_value url = URI 'http://rubyforge.org/' values = cookie_values(:value => "") # Add one cookie with an expiration date in the future cookie = HTTP::Cookie.new(values) @jar.add(cookie) assert_equal(1, @jar.cookies(url).length) @jar.add HTTP::Cookie.new(values.merge(:domain => 'RuByForge.Org', :name => 'aaron')) assert_equal(2, @jar.cookies(url).length) url2 = URI 'http://RuByFoRgE.oRg/' assert_equal(2, @jar.cookies(url2).length) end def test_add_future_cookies url = URI 'http://rubyforge.org/' # Add one cookie with an expiration date in the future cookie = HTTP::Cookie.new(cookie_values) @jar.add(cookie) assert_equal(1, @jar.cookies(url).length) # Add the same cookie, and we should still only have one @jar.add(HTTP::Cookie.new(cookie_values)) assert_equal(1, @jar.cookies(url).length) # Make sure we can get the cookie from different paths assert_equal(1, @jar.cookies(URI('http://rubyforge.org/login')).length) # Make sure we can't get the cookie from different domains assert_equal(0, @jar.cookies(URI('http://google.com/')).length) end def test_add_multiple_cookies url = URI 'http://rubyforge.org/' # Add one cookie with an expiration date in the future cookie = HTTP::Cookie.new(cookie_values) @jar.add(cookie) assert_equal(1, @jar.cookies(url).length) # Add the same cookie, and we should still only have one @jar.add(HTTP::Cookie.new(cookie_values(:name => 'Baz'))) assert_equal(2, @jar.cookies(url).length) # Make sure we can get the cookie from different paths assert_equal(2, @jar.cookies(URI('http://rubyforge.org/login')).length) # Make sure we can't get the cookie from different domains assert_equal(0, @jar.cookies(URI('http://google.com/')).length) end def test_add_multiple_cookies_with_the_same_name now = Time.now cookies = [ { :value => 'a', :path => '/', }, { :value => 'b', :path => '/abc/def/', :created_at => now - 1 }, { :value => 'c', :path => '/abc/def/', :domain => 'www.rubyforge.org', :origin => 'http://www.rubyforge.org/abc/def/', :created_at => now }, { :value => 'd', :path => '/abc/' }, ].map { |attrs| HTTP::Cookie.new(cookie_values(attrs)) } url = URI 'http://www.rubyforge.org/abc/def/ghi' cookies.permutation(cookies.size) { |shuffled| @jar.clear shuffled.each { |cookie| @jar.add(cookie) } assert_equal %w[b c d a], @jar.cookies(url).map { |cookie| cookie.value } } end def test_fall_back_rules_for_local_domains url = URI 'http://www.example.local' sld_cookie = HTTP::Cookie.new(cookie_values(:domain => '.example.local', :origin => url)) @jar.add(sld_cookie) assert_equal(1, @jar.cookies(url).length) end def test_add_makes_exception_for_localhost url = URI 'http://localhost' tld_cookie = HTTP::Cookie.new(cookie_values(:domain => 'localhost', :origin => url)) @jar.add(tld_cookie) assert_equal(1, @jar.cookies(url).length) end def test_add_cookie_for_the_parent_domain url = URI 'http://x.foo.com' cookie = HTTP::Cookie.new(cookie_values(:domain => '.foo.com', :origin => url)) @jar.add(cookie) assert_equal(1, @jar.cookies(url).length) end def test_add_rejects_cookies_with_unknown_domain_or_path cookie = HTTP::Cookie.new(cookie_values.reject { |k,v| [:origin, :domain].include?(k) }) assert_raises(ArgumentError) { @jar.add(cookie) } cookie = HTTP::Cookie.new(cookie_values.reject { |k,v| [:origin, :path].include?(k) }) assert_raises(ArgumentError) { @jar.add(cookie) } end def test_add_does_not_reject_cookies_from_a_nested_subdomain url = URI 'http://y.x.foo.com' cookie = HTTP::Cookie.new(cookie_values(:domain => '.foo.com', :origin => url)) @jar.add(cookie) assert_equal(1, @jar.cookies(url).length) end def test_cookie_without_leading_dot_does_not_cause_substring_match url = URI 'http://arubyforge.org/' cookie = HTTP::Cookie.new(cookie_values(:domain => 'rubyforge.org')) @jar.add(cookie) assert_equal(0, @jar.cookies(url).length) end def test_cookie_without_leading_dot_matches_subdomains url = URI 'http://admin.rubyforge.org/' cookie = HTTP::Cookie.new(cookie_values(:domain => 'rubyforge.org', :origin => url)) @jar.add(cookie) assert_equal(1, @jar.cookies(url).length) end def test_cookies_with_leading_dot_match_subdomains url = URI 'http://admin.rubyforge.org/' @jar.add(HTTP::Cookie.new(cookie_values(:domain => '.rubyforge.org', :origin => url))) assert_equal(1, @jar.cookies(url).length) end def test_cookies_with_leading_dot_match_parent_domains url = URI 'http://rubyforge.org/' @jar.add(HTTP::Cookie.new(cookie_values(:domain => '.rubyforge.org', :origin => url))) assert_equal(1, @jar.cookies(url).length) end def test_cookies_with_leading_dot_match_parent_domains_exactly url = URI 'http://arubyforge.org/' @jar.add(HTTP::Cookie.new(cookie_values(:domain => '.rubyforge.org'))) assert_equal(0, @jar.cookies(url).length) end def test_cookie_for_ipv4_address_matches_the_exact_ipaddress url = URI 'http://192.168.0.1/' cookie = HTTP::Cookie.new(cookie_values(:domain => '192.168.0.1', :origin => url)) @jar.add(cookie) assert_equal(1, @jar.cookies(url).length) end def test_cookie_for_ipv6_address_matches_the_exact_ipaddress url = URI 'http://[fe80::0123:4567:89ab:cdef]/' cookie = HTTP::Cookie.new(cookie_values(:domain => '[fe80::0123:4567:89ab:cdef]', :origin => url)) @jar.add(cookie) assert_equal(1, @jar.cookies(url).length) end def test_cookies_dot url = URI 'http://www.host.example/' @jar.add(HTTP::Cookie.new(cookie_values(:domain => 'www.host.example', :origin => url))) url = URI 'http://wwwxhost.example/' assert_equal(0, @jar.cookies(url).length) end def test_cookies_no_host url = URI 'file:///path/' @jar.add(HTTP::Cookie.new(cookie_values(:origin => url))) assert_equal(0, @jar.cookies(url).length) end def test_clear url = URI 'http://rubyforge.org/' # Add one cookie with an expiration date in the future cookie = HTTP::Cookie.new(cookie_values(:origin => url)) @jar.add(cookie) @jar.add(HTTP::Cookie.new(cookie_values(:name => 'Baz', :origin => url))) assert_equal(2, @jar.cookies(url).length) @jar.clear assert_equal(0, @jar.cookies(url).length) end def test_save_cookies_yaml url = URI 'http://rubyforge.org/' # Add one cookie with an expiration date in the future cookie = HTTP::Cookie.new(cookie_values(:origin => url)) s_cookie = HTTP::Cookie.new(cookie_values(:name => 'Bar', :expires => nil, :origin => url)) @jar.add(cookie) @jar.add(s_cookie) @jar.add(HTTP::Cookie.new(cookie_values(:name => 'Baz', :for_domain => false, :origin => url))) assert_equal(3, @jar.cookies(url).length) Dir.mktmpdir do |dir| value = @jar.save(File.join(dir, "cookies.yml")) assert_same @jar, value @jar2.load(File.join(dir, "cookies.yml")) cookies = @jar2.cookies(url).sort_by { |cookie| cookie.name } assert_equal(2, cookies.length) assert_equal('Baz', cookies[0].name) assert_equal(false, cookies[0].for_domain) assert_equal('Foo', cookies[1].name) assert_equal(true, cookies[1].for_domain) end assert_equal(3, @jar.cookies(url).length) end def test_save_load_signature Dir.mktmpdir { |dir| filename = File.join(dir, "cookies.yml") @jar.save(filename, :format => :cookiestxt, :session => true) @jar.save(filename, :format => :cookiestxt, :session => true) @jar.save(filename, :format => :cookiestxt) @jar.save(filename, :cookiestxt, :session => true) @jar.save(filename, :cookiestxt) @jar.save(filename, HTTP::CookieJar::CookiestxtSaver) @jar.save(filename, HTTP::CookieJar::CookiestxtSaver.new) @jar.save(filename, :session => true) @jar.save(filename) assert_raises(ArgumentError) { @jar.save() } assert_raises(ArgumentError) { @jar.save(filename, :nonexistent) } assert_raises(TypeError) { @jar.save(filename, { :format => :cookiestxt }, { :session => true }) } assert_raises(ArgumentError) { @jar.save(filename, :cookiestxt, { :session => true }, { :format => :cookiestxt }) } @jar.load(filename, :format => :cookiestxt, :linefeed => "\n") @jar.load(filename, :format => :cookiestxt, :linefeed => "\n") @jar.load(filename, :format => :cookiestxt) @jar.load(filename, HTTP::CookieJar::CookiestxtSaver) @jar.load(filename, HTTP::CookieJar::CookiestxtSaver.new) @jar.load(filename, :cookiestxt, :linefeed => "\n") @jar.load(filename, :cookiestxt) @jar.load(filename, :linefeed => "\n") @jar.load(filename) assert_raises(ArgumentError) { @jar.load() } assert_raises(ArgumentError) { @jar.load(filename, :nonexistent) } assert_raises(TypeError) { @jar.load(filename, { :format => :cookiestxt }, { :linefeed => "\n" }) } assert_raises(ArgumentError) { @jar.load(filename, :cookiestxt, { :linefeed => "\n" }, { :format => :cookiestxt }) } } end def test_save_session_cookies_yaml url = URI 'http://rubyforge.org/' # Add one cookie with an expiration date in the future cookie = HTTP::Cookie.new(cookie_values) s_cookie = HTTP::Cookie.new(cookie_values(:name => 'Bar', :expires => nil)) @jar.add(cookie) @jar.add(s_cookie) @jar.add(HTTP::Cookie.new(cookie_values(:name => 'Baz'))) assert_equal(3, @jar.cookies(url).length) Dir.mktmpdir do |dir| @jar.save(File.join(dir, "cookies.yml"), :format => :yaml, :session => true) @jar2.load(File.join(dir, "cookies.yml")) assert_equal(3, @jar2.cookies(url).length) end assert_equal(3, @jar.cookies(url).length) end def test_save_and_read_cookiestxt url = URI 'http://rubyforge.org/foo/' # Add one cookie with an expiration date in the future cookie = HTTP::Cookie.new(cookie_values) expires = cookie.expires s_cookie = HTTP::Cookie.new(cookie_values(:name => 'Bar', :expires => nil)) cookie2 = HTTP::Cookie.new(cookie_values(:name => 'Baz', :value => 'Foo#Baz', :path => '/foo/', :for_domain => false)) h_cookie = HTTP::Cookie.new(cookie_values(:name => 'Quux', :value => 'Foo#Quux', :httponly => true)) ma_cookie = HTTP::Cookie.new(cookie_values(:name => 'Maxage', :value => 'Foo#Maxage', :max_age => 15000)) @jar.add(cookie) @jar.add(s_cookie) @jar.add(cookie2) @jar.add(h_cookie) @jar.add(ma_cookie) assert_equal(5, @jar.cookies(url).length) Dir.mktmpdir do |dir| filename = File.join(dir, "cookies.txt") @jar.save(filename, :cookiestxt) content = File.read(filename) filename2 = File.join(dir, "cookies2.txt") open(filename2, 'w') { |w| w.puts '# HTTP Cookie File' @jar.save(w, :cookiestxt, :header => nil) } assert_equal content, File.read(filename2) assert_match(/^\.rubyforge\.org\t.*\tFoo\t/, content) assert_match(/^rubyforge\.org\t.*\tBaz\t/, content) assert_match(/^#HttpOnly_\.rubyforge\.org\t/, content) @jar2.load(filename, :cookiestxt) # HACK test the format cookies = @jar2.cookies(url) assert_equal(4, cookies.length) cookies.each { |cookie| case cookie.name when 'Foo' assert_equal 'Bar', 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 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? when 'Maxage' assert_equal 'Foo#Maxage', cookie.value assert_equal nil, cookie.max_age assert_in_delta ma_cookie.expires, cookie.expires, 1 else raise end } end assert_equal(5, @jar.cookies(url).length) end def test_load_yaml_mechanize @jar.load(test_file('mechanize.yml'), :yaml) assert_equal 4, @jar.to_a.size com_nid, com_pref = @jar.cookies('http://www.google.com/') assert_equal 'NID', com_nid.name assert_equal 'Sun, 23 Sep 2063 08:20:15 GMT', com_nid.expires.httpdate assert_equal 'google.com', com_nid.domain_name.hostname assert_equal 'PREF', com_pref.name assert_equal 'Tue, 24 Mar 2065 08:20:15 GMT', com_pref.expires.httpdate assert_equal 'google.com', com_pref.domain_name.hostname cojp_nid, cojp_pref = @jar.cookies('http://www.google.co.jp/') assert_equal 'NID', cojp_nid.name assert_equal 'Sun, 23 Sep 2063 08:20:16 GMT', cojp_nid.expires.httpdate assert_equal 'google.co.jp', cojp_nid.domain_name.hostname assert_equal 'PREF', cojp_pref.name assert_equal 'Tue, 24 Mar 2065 08:20:16 GMT', cojp_pref.expires.httpdate assert_equal 'google.co.jp', cojp_pref.domain_name.hostname end def test_expire_cookies url = URI 'http://rubyforge.org/' # Add one cookie with an expiration date in the future cookie = HTTP::Cookie.new(cookie_values) @jar.add(cookie) assert_equal(1, @jar.cookies(url).length) # Add a second cookie @jar.add(HTTP::Cookie.new(cookie_values(:name => 'Baz'))) assert_equal(2, @jar.cookies(url).length) # Make sure we can get the cookie from different paths assert_equal(2, @jar.cookies(URI('http://rubyforge.org/login')).length) # Expire the first cookie @jar.add(HTTP::Cookie.new(cookie_values(:expires => Time.now - (10 * 86400)))) assert_equal(1, @jar.cookies(url).length) # Expire the second cookie @jar.add(HTTP::Cookie.new(cookie_values( :name => 'Baz', :expires => Time.now - (10 * 86400)))) assert_equal(0, @jar.cookies(url).length) end def test_session_cookies values = cookie_values(:expires => nil) url = URI 'http://rubyforge.org/' # Add one cookie with an expiration date in the future cookie = HTTP::Cookie.new(values) @jar.add(cookie) assert_equal(1, @jar.cookies(url).length) # Add a second cookie @jar.add(HTTP::Cookie.new(values.merge(:name => 'Baz'))) assert_equal(2, @jar.cookies(url).length) # Make sure we can get the cookie from different paths assert_equal(2, @jar.cookies(URI('http://rubyforge.org/login')).length) # Expire the first cookie @jar.add(HTTP::Cookie.new(values.merge(:expires => Time.now - (10 * 86400)))) assert_equal(1, @jar.cookies(url).length) # Expire the second cookie @jar.add(HTTP::Cookie.new(values.merge(:name => 'Baz', :expires => Time.now - (10 * 86400)))) assert_equal(0, @jar.cookies(url).length) # When given a URI with a blank path, CookieJar#cookies should return # cookies with the path '/': url = URI 'http://rubyforge.org' assert_equal '', url.path assert_equal(0, @jar.cookies(url).length) # Now add a cookie with the path set to '/': @jar.add(HTTP::Cookie.new(values.merge(:name => 'has_root_path', :path => '/'))) assert_equal(1, @jar.cookies(url).length) end def test_paths url = URI 'http://rubyforge.org/login' values = cookie_values(:path => "/login", :expires => nil, :origin => url) # Add one cookie with an expiration date in the future cookie = HTTP::Cookie.new(values) @jar.add(cookie) assert_equal(1, @jar.cookies(url).length) # Add a second cookie @jar.add(HTTP::Cookie.new(values.merge( :name => 'Baz' ))) assert_equal(2, @jar.cookies(url).length) # Make sure we don't get the cookie in a different path assert_equal(0, @jar.cookies(URI('http://rubyforge.org/hello')).length) assert_equal(0, @jar.cookies(URI('http://rubyforge.org/')).length) # Expire the first cookie @jar.add(HTTP::Cookie.new(values.merge( :expires => Time.now - (10 * 86400)))) assert_equal(1, @jar.cookies(url).length) # Expire the second cookie @jar.add(HTTP::Cookie.new(values.merge( :name => 'Baz', :expires => Time.now - (10 * 86400)))) assert_equal(0, @jar.cookies(url).length) end def test_ssl_cookies # thanks to michal "ocher" ochman for reporting the bug responsible for this test. values = cookie_values(:expires => nil) values_ssl = values.merge(:name => 'Baz', :domain => "#{values[:domain]}:443") url = URI 'https://rubyforge.org/login' cookie = HTTP::Cookie.new(values) @jar.add(cookie) assert_equal(1, @jar.cookies(url).length, "did not handle SSL cookie") cookie = HTTP::Cookie.new(values_ssl) @jar.add(cookie) assert_equal(2, @jar.cookies(url).length, "did not handle SSL cookie with :443") end def test_secure_cookie nurl = URI 'http://rubyforge.org/login' surl = URI 'https://rubyforge.org/login' nncookie = HTTP::Cookie.new(cookie_values(:name => 'Foo1', :origin => nurl)) sncookie = HTTP::Cookie.new(cookie_values(:name => 'Foo1', :origin => surl)) nscookie = HTTP::Cookie.new(cookie_values(:name => 'Foo2', :secure => true, :origin => nurl)) sscookie = HTTP::Cookie.new(cookie_values(:name => 'Foo2', :secure => true, :origin => surl)) @jar.add(nncookie) @jar.add(sncookie) @jar.add(nscookie) @jar.add(sscookie) assert_equal('Foo1', @jar.cookies(nurl).map { |c| c.name }.sort.join(' ') ) assert_equal('Foo1 Foo2', @jar.cookies(surl).map { |c| c.name }.sort.join(' ') ) end def test_delete cookie1 = HTTP::Cookie.new(cookie_values) cookie2 = HTTP::Cookie.new(:name => 'Foo', :value => '', :domain => 'rubyforge.org', :for_domain => false, :path => '/') cookie3 = HTTP::Cookie.new(:name => 'Foo', :value => '', :domain => 'rubyforge.org', :for_domain => true, :path => '/') @jar.add(cookie1) @jar.delete(cookie2) if mozilla_store? assert_equal(1, @jar.to_a.length) @jar.delete(cookie3) end assert_equal(0, @jar.to_a.length) end def test_accessed_at orig = HTTP::Cookie.new(cookie_values(:expires => nil)) @jar.add(orig) time = orig.accessed_at assert_in_delta 1.0, time, Time.now, "accessed_at is initialized to the current time" cookie, = @jar.to_a assert_equal time, cookie.accessed_at, "accessed_at is not updated by each()" cookie, = @jar.cookies("http://rubyforge.org/") assert_send [cookie.accessed_at, :>, time], "accessed_at is not updated by each(url)" end def test_max_cookies slimit = HTTP::Cookie::MAX_COOKIES_TOTAL + @gc_threshold limit_per_domain = HTTP::Cookie::MAX_COOKIES_PER_DOMAIN uri = URI('http://www.example.org/') date = Time.at(Time.now.to_i + 86400) (1..(limit_per_domain + 1)).each { |i| @jar << HTTP::Cookie.new(cookie_values( :name => 'Foo%d' % i, :value => 'Bar%d' % i, :domain => uri.host, :for_domain => true, :path => '/dir%d/' % (i / 2), :origin => uri )).tap { |cookie| cookie.created_at = i == 42 ? date - i : date } } assert_equal limit_per_domain + 1, @jar.to_a.size @jar.cleanup count = @jar.to_a.size assert_equal limit_per_domain, count assert_equal [*1..(limit_per_domain + 1)] - [42], @jar.map { |cookie| cookie.name[/(\d+)$/].to_i }.sort hlimit = HTTP::Cookie::MAX_COOKIES_TOTAL n = hlimit / limit_per_domain * 2 (1..n).each { |i| (1..(limit_per_domain + 1)).each { |j| uri = URI('http://www%d.example.jp/' % i) @jar << HTTP::Cookie.new(cookie_values( :name => 'Baz%d' % j, :value => 'www%d.example.jp' % j, :domain => uri.host, :for_domain => true, :path => '/dir%d/' % (i / 2), :origin => uri )).tap { |cookie| cookie.created_at = i == j ? date - i : date } count += 1 } } assert_send [count, :>, slimit] assert_send [@jar.to_a.size, :<=, slimit] @jar.cleanup assert_equal hlimit, @jar.to_a.size assert_equal false, @jar.any? { |cookie| cookie.domain == cookie.value } end def test_parse set_cookie = [ "name=Akinori; Domain=rubyforge.org; Expires=Sun, 08 Aug 2076 19:00:00 GMT; Path=/", "country=Japan; Domain=rubyforge.org; Expires=Sun, 08 Aug 2076 19:00:00 GMT; Path=/", "city=Tokyo; Domain=rubyforge.org; Expires=Sun, 08 Aug 2076 19:00:00 GMT; Path=/", ].join(', ') cookies = @jar.parse(set_cookie, 'http://rubyforge.org/') assert_equal %w[Akinori Japan Tokyo], cookies.map { |c| c.value } assert_equal %w[Tokyo Japan Akinori], @jar.to_a.sort_by { |c| c.name }.map { |c| c.value } end def test_parse_with_block set_cookie = [ "name=Akinori; Domain=rubyforge.org; Expires=Sun, 08 Aug 2076 19:00:00 GMT; Path=/", "country=Japan; Domain=rubyforge.org; Expires=Sun, 08 Aug 2076 19:00:00 GMT; Path=/", "city=Tokyo; Domain=rubyforge.org; Expires=Sun, 08 Aug 2076 19:00:00 GMT; Path=/", ].join(', ') cookies = @jar.parse(set_cookie, 'http://rubyforge.org/') { |c| c.name != 'city' } assert_equal %w[Akinori Japan], cookies.map { |c| c.value } assert_equal %w[Japan Akinori], @jar.to_a.sort_by { |c| c.name }.map { |c| c.value } end def test_expire_by_each_and_cleanup uri = URI('http://www.example.org/') ts = Time.now.to_f if ts % 1 > 0.5 sleep 0.5 ts += 0.5 end expires = Time.at(ts.floor) time = expires if mozilla_store? # MozillaStore only has the time precision of seconds. time = expires expires -= 1 end 0.upto(2) { |i| c = HTTP::Cookie.new('Foo%d' % (3 - i), 'Bar', :expires => expires + i, :origin => uri) @jar << c @jar2 << c } assert_equal %w[Foo1 Foo2], @jar.cookies.map(&:name) assert_equal %w[Foo1 Foo2], @jar2.cookies(uri).map(&:name) sleep_until time + 1 assert_equal %w[Foo1], @jar.cookies.map(&:name) assert_equal %w[Foo1], @jar2.cookies(uri).map(&:name) sleep_until time + 2 @jar.cleanup @jar2.cleanup assert_send [@jar, :empty?] assert_send [@jar2, :empty?] end end class WithHashStore < Test::Unit::TestCase include CommonTests def test_new jar = HTTP::CookieJar.new(:store => :hash) assert_instance_of HTTP::CookieJar::HashStore, jar.store assert_raises(ArgumentError) { jar = HTTP::CookieJar.new(:store => :nonexistent) } jar = HTTP::CookieJar.new(:store => HTTP::CookieJar::HashStore.new) assert_instance_of HTTP::CookieJar::HashStore, jar.store jar = HTTP::CookieJar.new(:store => HTTP::CookieJar::HashStore) end def test_clone jar = @jar.clone assert_not_send [ @jar.store, :equal?, jar.store ] assert_not_send [ @jar.store.instance_variable_get(:@jar), :equal?, jar.store.instance_variable_get(:@jar) ] assert_equal @jar.cookies, jar.cookies end end class WithMozillaStore < Test::Unit::TestCase include CommonTests def setup super( { :store => :mozilla, :filename => ":memory:" }, { :store => :mozilla, :filename => ":memory:" }) end def add_and_delete(jar) jar.parse("name=Akinori; Domain=rubyforge.org; Expires=Sun, 08 Aug 2076 19:00:00 GMT; Path=/", 'http://rubyforge.org/') jar.parse("country=Japan; Domain=rubyforge.org; Expires=Sun, 08 Aug 2076 19:00:00 GMT; Path=/", 'http://rubyforge.org/') jar.delete(HTTP::Cookie.new("name", :domain => 'rubyforge.org')) end def test_clone assert_raises(TypeError) { @jar.clone } end def test_close add_and_delete(@jar) assert_not_send [@jar.store, :closed?] @jar.store.close assert_send [@jar.store, :closed?] @jar.store.close # should do nothing assert_send [@jar.store, :closed?] end def test_finalizer db = nil loop { jar = HTTP::CookieJar.new(:store => :mozilla, :filename => ':memory:') add_and_delete(jar) db = jar.store.instance_variable_get(:@db) class << db alias close_orig close def close STDERR.print "[finalizer is called]" STDERR.flush close_orig end end break } end def test_upgrade_mozillastore Dir.mktmpdir { |dir| filename = File.join(dir, 'cookies.sqlite') sqlite = SQLite3::Database.new(filename) sqlite.execute(<<-'SQL') CREATE TABLE moz_cookies ( id INTEGER PRIMARY KEY, name TEXT, value TEXT, host TEXT, path TEXT, expiry INTEGER, isSecure INTEGER, isHttpOnly INTEGER) SQL sqlite.execute(<<-'SQL') PRAGMA user_version = 1 SQL begin st_insert = sqlite.prepare(<<-'SQL') INSERT INTO moz_cookies ( id, name, value, host, path, expiry, isSecure, isHttpOnly ) VALUES (?, ?, ?, ?, ?, ?, ?, ?) SQL st_insert.execute(1, 'name1', 'value1', '.example.co.jp', '/', 2312085765, 0, 0) st_insert.execute(2, 'name1', 'value2', '.example.co.jp', '/', 2312085765, 0, 0) st_insert.execute(3, 'name1', 'value3', 'www.example.co.jp', '/', 2312085765, 0, 0) ensure st_insert.close if st_insert end sqlite.close jar = HTTP::CookieJar.new(:store => :mozilla, :filename => filename) assert_equal 2, jar.to_a.size assert_equal 2, jar.cookies('http://www.example.co.jp/').size cookie, *rest = jar.cookies('http://host.example.co.jp/') assert_send [rest, :empty?] assert_equal 'value2', cookie.value } end end if begin require 'sqlite3' true rescue LoadError STDERR.puts 'sqlite3 missing?' false end end http-cookie-1.0.5/test/simplecov_start.rb 0000644 0000041 0000041 00000000044 14246426325 020523 0 ustar www-data www-data require 'simplecov' SimpleCov.start http-cookie-1.0.5/README.md 0000644 0000041 0000041 00000015604 14246426325 015270 0 ustar www-data www-data # HTTP::Cookie HTTP::Cookie is a ruby library to handle HTTP cookies in a way both compliant with RFCs and compatible with today's major browsers. It was originally a part of the [Mechanize](https://github.com/sparklemotion/mechanize) library, separated as an independent library in the hope of serving as a common component that is reusable from any HTTP related piece of software. The following is an incomplete list of its features: * Its behavior is highly compatible with that of today's major web browsers. * It is based on and conforms to RFC 6265 (the latest standard for the HTTP cookie mechanism) to a high extent, with real world conventions deeply in mind. * It takes eTLD (effective TLD, also known as "Public Suffix") into account just as major browsers do, to reject cookies with an eTLD domain like "org", "co.jp", or "appspot.com". This feature is brought to you by the domain_name gem. * The number of cookies and the size are properly capped so that a cookie store does not get flooded. * It supports the legacy Netscape cookies.txt format for serialization, maximizing the interoperability with other implementations. * It supports the cookies.sqlite format adopted by Mozilla Firefox for backend store database which can be shared among multiple program instances. * It is relatively easy to add a new serialization format or a backend store because of its modular API. ## Installation Add this line to your application's `Gemfile`: gem 'http-cookie' And then execute: $ bundle Or install it yourself as: $ gem install http-cookie ## Usage ######################## # Client side example 1 ######################## # Initialize a cookie jar jar = HTTP::CookieJar.new # Load from a file jar.load(filename) if File.exist?(filename) # Store received cookies, where uri is the origin of this header header["Set-Cookie"].each { |value| jar.parse(value, uri) } # ... # Set the Cookie header value, where uri is the destination URI header["Cookie"] = HTTP::Cookie.cookie_value(jar.cookies(uri)) # Save to a file jar.save(filename) ######################## # Client side example 2 ######################## # Initialize a cookie jar using a Mozilla compatible SQLite3 backend jar = HTTP::CookieJar.new(store: :mozilla, filename: 'cookies.sqlite') # There is no need for load & save in this backend. # Store received cookies, where uri is the origin of this header header["Set-Cookie"].each { |value| jar.parse(value, uri) } # ... # Set the Cookie header value, where uri is the destination URI header["Cookie"] = HTTP::Cookie.cookie_value(jar.cookies(uri)) ######################## # Server side example ######################## # Generate a domain cookie cookie1 = HTTP::Cookie.new("uid", "u12345", domain: 'example.org', for_domain: true, path: '/', max_age: 7*86400) # Add it to the Set-Cookie response header header['Set-Cookie'] = cookie1.set_cookie_value # Generate a host-only cookie cookie2 = HTTP::Cookie.new("aid", "a12345", origin: my_url, path: '/', max_age: 7*86400) # Add it to the Set-Cookie response header header['Set-Cookie'] = cookie2.set_cookie_value ## Incompatibilities with Mechanize::Cookie/CookieJar There are several incompatibilities between Mechanize::Cookie/CookieJar and HTTP::Cookie/CookieJar. Below is how to rewrite existing code written for Mechanize::Cookie with equivalent using HTTP::Cookie: - Mechanize::Cookie.parse The parameter order changed in HTTP::Cookie.parse. # before cookies1 = Mechanize::Cookie.parse(uri, set_cookie1) cookies2 = Mechanize::Cookie.parse(uri, set_cookie2, log) # after cookies1 = HTTP::Cookie.parse(set_cookie1, uri_or_url) cookies2 = HTTP::Cookie.parse(set_cookie2, uri_or_url, logger: log) # or you can directly store parsed cookies in your jar jar.parse(set_cookie1, uri_or_url) jar.parse(set_cookie1, uri_or_url, logger: log) - Mechanize::Cookie#version, #version= There is no longer a sense of version in the HTTP cookie specification. The only version number ever defined was zero, and there will be no other version defined since the version attribute has been removed in RFC 6265. - Mechanize::Cookie#comment, #comment= Ditto. The comment attribute has been removed in RFC 6265. - Mechanize::Cookie#set_domain This method was unintentionally made public. Simply use HTTP::Cookie#domain=. # before cookie.set_domain(domain) # after cookie.domain = domain - Mechanize::CookieJar#add, #add! Always use HTTP::CookieJar#add. # before jar.add!(cookie1) jar.add(uri, cookie2) # after jar.add(cookie1) cookie2.origin = uri; jar.add(cookie2) # or specify origin in parse() or new() - Mechanize::CookieJar#clear! Use HTTP::Cookiejar#clear. # before jar.clear! # after jar.clear - Mechanize::CookieJar#save_as Use HTTP::CookieJar#save. # before jar.save_as(file) # after jar.save(file) - Mechanize::CookieJar#jar There is no direct access to the internal hash in HTTP::CookieJar since it has introduced an abstract store layer. If you want to tweak the internals of the hash store, try creating a new store class referring to the default store class HTTP::CookieJar::HashStore. If you desperately need it you can access it by `jar.store.instance_variable_get(:@jar)`, but there is no guarantee that it will remain available in the future. HTTP::Cookie/CookieJar raise runtime errors to help migration, so after replacing the class names, try running your test code once to find out how to fix your code base. ### File formats The YAML serialization format has changed, and HTTP::CookieJar#load cannot import what is written in a YAML file saved by Mechanize::CookieJar#save_as. HTTP::CookieJar#load will not raise an exception if an incompatible YAML file is given, but the content is silently ignored. Note that there is (obviously) no forward compatibillity with this. Trying to load a YAML file saved by HTTP::CookieJar with Mechanize::CookieJar will fail in runtime error. On the other hand, there has been (and will ever be) no change in the cookies.txt format, so use it instead if compatibility is significant. ## Contributing 1. Fork it 2. Create your feature branch (`git checkout -b my-new-feature`) 3. Commit your changes (`git commit -am 'Add some feature'`) 4. Push to the branch (`git push origin my-new-feature`) 5. Create new Pull Request http-cookie-1.0.5/CHANGELOG.md 0000644 0000041 0000041 00000001531 14246426325 015614 0 ustar www-data www-data ## 1.0.5 (2022-05-25) - Silence SQLite3 warnings ## 1.0.4 (2021-06-07) - Support Mozilla's cookie storage format up to version 7. - Fix the time representation with creationTime and lastAccessed in MozillaStore. (#8) ## 1.0.3 (2016-09-30) - Treat comma as normal character in HTTP::Cookie.cookie_value_to_hash instead of key-value pair separator. This should fix the problem described in CVE-2016-7401. ## 1.0.2 (2013-09-10) - Fix HTTP::Cookie.parse so that it does not raise ArgumentError when it finds a bad name or value that is parsable but considered invalid. ## 1.0.1 (2013-04-21) - Minor error handling improvements and documentation updates. - Argument error regarding specifying store/saver classes no longer raises IndexError, but either ArgumentError or TypeError. ## 1.0.0 (2013-04-17) - Initial Release. http-cookie-1.0.5/.gitignore 0000644 0000041 0000041 00000000232 14246426325 015770 0 ustar www-data www-data *.gem *.rbc .bundle .config .yardoc Gemfile.lock InstalledFiles _yardoc coverage doc/ lib/bundler/man pkg rdoc spec/reports test/tmp test/version_tmp tmp http-cookie-1.0.5/Rakefile 0000644 0000041 0000041 00000001005 14246426325 015444 0 ustar www-data www-data require 'bundler/gem_tasks' require 'rake/testtask' Rake::TestTask.new(:test) do |test| test.ruby_opts << '-r./test/simplecov_start.rb' if RUBY_VERSION >= '1.9' test.pattern = 'test/**/test_*.rb' test.verbose = true end task :default => :test require 'rdoc/task' Rake::RDocTask.new do |rdoc| version = HTTP::Cookie::VERSION rdoc.rdoc_dir = 'rdoc' rdoc.title = "http-cookie #{version}" rdoc.rdoc_files.include('lib/**/*.rb') rdoc.rdoc_files.include(Bundler::GemHelper.gemspec.extra_rdoc_files) end http-cookie-1.0.5/lib/ 0000755 0000041 0000041 00000000000 14246426325 014551 5 ustar www-data www-data http-cookie-1.0.5/lib/http-cookie.rb 0000644 0000041 0000041 00000000026 14246426325 017322 0 ustar www-data www-data require 'http/cookie' http-cookie-1.0.5/lib/http/ 0000755 0000041 0000041 00000000000 14246426325 015530 5 ustar www-data www-data http-cookie-1.0.5/lib/http/cookie_jar.rb 0000644 0000041 0000041 00000023123 14246426325 020163 0 ustar www-data www-data # :markup: markdown require 'http/cookie' ## # This class is used to manage the Cookies that have been returned from # any particular website. class HTTP::CookieJar class << self def const_missing(name) case name.to_s when /\A([A-Za-z]+)Store\z/ file = 'http/cookie_jar/%s_store' % $1.downcase when /\A([A-Za-z]+)Saver\z/ file = 'http/cookie_jar/%s_saver' % $1.downcase end begin require file rescue LoadError raise NameError, 'can\'t resolve constant %s; failed to load %s' % [name, file] end if const_defined?(name) const_get(name) else raise NameError, 'can\'t resolve constant %s after loading %s' % [name, file] end end end attr_reader :store def get_impl(base, value, *args) case value when base value when Symbol begin base.implementation(value).new(*args) rescue IndexError => e raise ArgumentError, e.message end when Class if base >= value value.new(*args) else raise TypeError, 'not a subclass of %s: %s' % [base, value] end else raise TypeError, 'invalid object: %s' % value.inspect end end private :get_impl # Generates a new cookie jar. # # Available option keywords are as below: # # :store # : The store class that backs this jar. (default: `:hash`) # A symbol addressing a store class, a store class, or an instance # of a store class is accepted. Symbols are mapped to store # classes, like `:hash` to HTTP::CookieJar::HashStore and `:mozilla` # to HTTP::CookieJar::MozillaStore. # # Any options given are passed through to the initializer of the # specified store class. For example, the `:mozilla` # (HTTP::CookieJar::MozillaStore) store class requires a `:filename` # option. See individual store classes for details. def initialize(options = nil) opthash = { :store => :hash, } opthash.update(options) if options @store = get_impl(AbstractStore, opthash[:store], opthash) end # The copy constructor. Not all backend store classes support cloning. def initialize_copy(other) @store = other.instance_eval { @store.dup } end # Adds a cookie to the jar if it is acceptable, and returns self in # any case. A given cookie must have domain and path attributes # set, or ArgumentError is raised. # # Whether a cookie with the `for_domain` flag on overwrites another # with the flag off or vice versa depends on the store used. See # individual store classes for that matter. # # ### Compatibility Note for Mechanize::Cookie users # # In HTTP::Cookie, each cookie object can store its origin URI # (cf. #origin). While the origin URI of a cookie can be set # manually by #origin=, one is typically given in its generation. # To be more specific, HTTP::Cookie.new takes an `:origin` option # and HTTP::Cookie.parse takes one via the second argument. # # # Mechanize::Cookie # jar.add(origin, cookie) # jar.add!(cookie) # no acceptance check is performed # # # HTTP::Cookie # jar.origin = origin # jar.add(cookie) # acceptance check is performed def add(cookie) @store.add(cookie) if begin cookie.acceptable? rescue RuntimeError => e raise ArgumentError, e.message end self end alias << add # Deletes a cookie that has the same name, domain and path as a # given cookie from the jar and returns self. # # How the `for_domain` flag value affects the set of deleted cookies # depends on the store used. See individual store classes for that # matter. def delete(cookie) @store.delete(cookie) self end # Gets an array of cookies sorted by the path and creation time. If # `url` is given, only ones that should be sent to the URL/URI are # selected, with the access time of each of them updated. def cookies(url = nil) each(url).sort end # Tests if the jar is empty. If `url` is given, tests if there is # no cookie for the URL. def empty?(url = nil) if url each(url) { return false } return true else @store.empty? end end # Iterates over all cookies that are not expired in no particular # order. # # An optional argument `uri` specifies a URI/URL indicating the # destination of the cookies being selected. Every cookie yielded # should be good to send to the given URI, # i.e. cookie.valid_for_uri?(uri) evaluates to true. # # If (and only if) the `uri` option is given, last access time of # each cookie is updated to the current time. def each(uri = nil, &block) # :yield: cookie block_given? or return enum_for(__method__, uri) if uri uri = URI(uri) return self unless URI::HTTP === uri && uri.host end @store.each(uri, &block) self end include Enumerable # Parses a Set-Cookie field value `set_cookie` assuming that it is # sent from a source URL/URI `origin`, and adds the cookies parsed # as valid and considered acceptable to the jar. Returns an array # of cookies that have been added. # # If a block is given, it is called for each cookie and the cookie # is added only if the block returns a true value. # # `jar.parse(set_cookie, origin)` is a shorthand for this: # # HTTP::Cookie.parse(set_cookie, origin) { |cookie| # jar.add(cookie) # } # # See HTTP::Cookie.parse for available options. def parse(set_cookie, origin, options = nil) # :yield: cookie if block_given? HTTP::Cookie.parse(set_cookie, origin, options).tap { |cookies| cookies.select! { |cookie| yield(cookie) && add(cookie) } } else HTTP::Cookie.parse(set_cookie, origin, options) { |cookie| add(cookie) } end end # call-seq: # jar.save(filename_or_io, **options) # jar.save(filename_or_io, format = :yaml, **options) # # Saves the cookie jar into a file or an IO in the format specified # and returns self. If a given object responds to #write it is # taken as an IO, or taken as a filename otherwise. # # Available option keywords are below: # # * `:format` # # Specifies the format for saving. A saver class, a symbol # addressing a saver class, or a pre-generated instance of a # saver class is accepted. # #