cookie_store 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +4 -0
- data/Rakefile +20 -0
- data/cookie_store.gemspec +25 -0
- data/lib/cookie_store.rb +67 -0
- data/lib/cookie_store/cookie.rb +238 -0
- data/lib/cookie_store/hash_store.rb +52 -0
- data/test/cookie_store/cookie_test.rb +313 -0
- data/test/cookie_store/hash_store_test.rb +78 -0
- data/test/cookie_store_test.rb +88 -0
- data/test/test_helper.rb +38 -0
- metadata +116 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 03f6d983ab27d0ae52b8af6468da9a131e815e4c
|
4
|
+
data.tar.gz: b235fd0ecfba2b57d10d121cca4bace173e56b08
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c74560238d8e3ec19ccf3d987bea2c8dcb1f516fa45ec58eaeddacb43553557736f54e2c92f6e2e87daf0234d1ec3acee2346b291e63f583718432d7bf735774
|
7
|
+
data.tar.gz: 3a4f46c5276009ca3203ea6bdf1b6597fa872f1e3ad4ab731cae18e719fc15bb03f721439ec5f3a177c065f65b7b10a93c7cc3ab74f7a1c2dc7b17f05264c13f
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2014 Jonathan Bracy
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require "bundler/gem_tasks"
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rdoc/task'
|
5
|
+
|
6
|
+
task :console do
|
7
|
+
exec 'irb -Ilib -r cookie_store.rb'
|
8
|
+
end
|
9
|
+
task :c => :console
|
10
|
+
|
11
|
+
|
12
|
+
Rake::TestTask.new do |t|
|
13
|
+
t.libs << 'lib' << 'test'
|
14
|
+
t.test_files = FileList['test/**/*_test.rb']
|
15
|
+
# t.warning = true
|
16
|
+
# t.verbose = true
|
17
|
+
end
|
18
|
+
|
19
|
+
desc "Run tests"
|
20
|
+
task :default => :test
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "cookie_store"
|
6
|
+
s.version = '0.1.0'
|
7
|
+
s.licenses = ['MIT']
|
8
|
+
s.authors = ["Jon Bracy"]
|
9
|
+
s.email = ["jonbracy@gmail.com"]
|
10
|
+
s.homepage = "https://github.com/malomalo/cookie_store"
|
11
|
+
s.summary = %q{A Ruby library to handle client-side HTTP cookies}
|
12
|
+
s.description = %q{A Ruby library to handle and store client-side HTTP cookies}
|
13
|
+
|
14
|
+
s.files = `git ls-files`.split("\n")
|
15
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
16
|
+
s.require_paths = ["lib"]
|
17
|
+
|
18
|
+
# Developoment
|
19
|
+
s.add_development_dependency 'rake'
|
20
|
+
# s.add_development_dependency 'rdoc'
|
21
|
+
# s.add_development_dependency 'sdoc'
|
22
|
+
s.add_development_dependency 'minitest'
|
23
|
+
s.add_development_dependency 'minitest-reporters'
|
24
|
+
s.add_development_dependency 'mocha'
|
25
|
+
end
|
data/lib/cookie_store.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
class CookieStore
|
4
|
+
|
5
|
+
# Maximum number of bytes per cookie (RFC 6265 6.1 requires at least 4096)
|
6
|
+
MAX_COOKIE_LENGTH = 4096
|
7
|
+
|
8
|
+
# Maximum number of cookies per domain (RFC 6265 6.1 requires 50 at least)
|
9
|
+
MAX_COOKIES_PER_DOMAIN = 50
|
10
|
+
|
11
|
+
# Maximum number of cookies total (RFC 6265 6.1 requires 3000 at least)
|
12
|
+
MAX_COOKIES_TOTAL = 3000
|
13
|
+
|
14
|
+
# Read and set the cookie from the Set-Cookie header
|
15
|
+
def set_cookie(request_uri, set_cookie_value)
|
16
|
+
request_uri = URI.parse(request_uri)
|
17
|
+
cookie = CookieStore::Cookie.parse(request_uri, set_cookie_value)
|
18
|
+
|
19
|
+
# reject as per RFC2965 Section 3.3.2
|
20
|
+
return if !cookie.request_match?(request_uri) || !(cookie.domain =~ /.+\..+/)
|
21
|
+
|
22
|
+
# reject cookies over the max-bytes
|
23
|
+
return if cookie.to_s.size > MAX_COOKIE_LENGTH
|
24
|
+
|
25
|
+
add(cookie)
|
26
|
+
end
|
27
|
+
|
28
|
+
def cookie_header_for(request_uri)
|
29
|
+
cookies_for(request_uri).map(&:to_s).join('; ')
|
30
|
+
end
|
31
|
+
|
32
|
+
# (RFC 2965, section 1)
|
33
|
+
def search_domains_for(domain)
|
34
|
+
domain.downcase!
|
35
|
+
serach_domains = []
|
36
|
+
|
37
|
+
if domain =~ CookieStore::Cookie::IPADDR
|
38
|
+
serach_domains << domain
|
39
|
+
else
|
40
|
+
domain = domain + '.local' if !(domain =~ /.\../)
|
41
|
+
serach_domains << domain
|
42
|
+
serach_domains << ".#{domain}"
|
43
|
+
|
44
|
+
# H is the host domain name of a host; and,
|
45
|
+
# H has the form A.B; and
|
46
|
+
if domain =~ /[^\.]+(\..+)/
|
47
|
+
reach = $1
|
48
|
+
# B has at least one embedded dot
|
49
|
+
if reach =~ /.[\.:]./
|
50
|
+
# B has at least one embedded dot, or B is the string "local".
|
51
|
+
# then the reach of H is .B.
|
52
|
+
serach_domains << reach
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
serach_domains
|
58
|
+
end
|
59
|
+
|
60
|
+
def close_session
|
61
|
+
gc(true)
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
require 'cookie_store/cookie'
|
67
|
+
require 'cookie_store/hash_store'
|
@@ -0,0 +1,238 @@
|
|
1
|
+
class CookieStore::Cookie
|
2
|
+
|
3
|
+
QUOTED_PAIR = "\\\\[\\x00-\\x7F]"
|
4
|
+
LWS = "\\r\\n(?:[ \\t]+)"
|
5
|
+
QDTEXT = "[\\t\\x20-\\x21\\x23-\\x7E\\x80-\\xFF]|(?:#{LWS})"
|
6
|
+
QUOTED_TEXT = "(?:#{QUOTED_PAIR}|#{QDTEXT})*"
|
7
|
+
IPADDR = /\A#{URI::REGEXP::PATTERN::IPV4ADDR}\Z|\A#{URI::REGEXP::PATTERN::IPV6ADDR}\Z/
|
8
|
+
|
9
|
+
TOKEN = '[^(),\/<>@;:\\\"\[\]?={}\s]+'
|
10
|
+
VALUE = "(?:#{TOKEN}|#{IPADDR}|#{QUOTED_TEXT})"
|
11
|
+
EXPIRES_AT_VALUE = '[A-Za-z]{3},\ \d{2}[-\ ][A-Za-z]{3}[-\ ]\d{4}\ \d{2}:\d{2}:\d{2}\ [A-Z]{3}'
|
12
|
+
|
13
|
+
COOKIE = /(?<name>#{TOKEN})=(?:"(?<quoted_value>#{QUOTED_TEXT})"|(?<value>#{VALUE}))(?<attributes>.*)/n
|
14
|
+
COOKIE_AV = %r{
|
15
|
+
;\s+
|
16
|
+
(?<key>#{TOKEN})
|
17
|
+
(?:
|
18
|
+
=
|
19
|
+
(?:
|
20
|
+
"(?<quoted_value>#{QUOTED_TEXT})"
|
21
|
+
|
|
22
|
+
(?<value>#{EXPIRES_AT_VALUE}|#{VALUE})
|
23
|
+
)
|
24
|
+
){0,1}
|
25
|
+
}nx
|
26
|
+
|
27
|
+
# [String] The name of the cookie.
|
28
|
+
attr_reader :name
|
29
|
+
|
30
|
+
# [String] The value of the cookie, without any attempts at decoding.
|
31
|
+
attr_reader :value
|
32
|
+
|
33
|
+
# [String] The domain scope of the cookie. Follows the RFC 2965
|
34
|
+
# 'effective host' rules. A 'dot' prefix indicates that it applies both
|
35
|
+
# to the non-dotted domain and child domains, while no prefix indicates
|
36
|
+
# that only exact matches of the domain are in scope.
|
37
|
+
attr_reader :domain
|
38
|
+
|
39
|
+
# [String] The path scope of the cookie. The cookie applies to URI paths
|
40
|
+
# that prefix match this value.
|
41
|
+
attr_reader :path
|
42
|
+
|
43
|
+
# [Boolean] The secure flag is set to indicate that the cookie should
|
44
|
+
# only be sent securely. Nearly all HTTP User Agent implementations assume
|
45
|
+
# this to mean that the cookie should only be sent over a
|
46
|
+
# SSL/TLS-protected connection
|
47
|
+
attr_reader :secure
|
48
|
+
|
49
|
+
# [Boolean] Popular browser extension to mark a cookie as invisible
|
50
|
+
# to code running within the browser, such as JavaScript
|
51
|
+
attr_reader :http_only
|
52
|
+
|
53
|
+
# [Fixnum] Version indicator, currently either
|
54
|
+
# * 0 for netscape cookies
|
55
|
+
# * 1 for RFC 2965 cookies
|
56
|
+
attr_reader :version
|
57
|
+
|
58
|
+
# [String, nil] RFC 2965 field for indicating comment (or a location)
|
59
|
+
# describing the cookie to a usesr agent.
|
60
|
+
attr_reader :comment, :comment_url
|
61
|
+
|
62
|
+
# [Boolean] RFC 2965 field for indicating session lifetime for a cookie
|
63
|
+
attr_reader :discard
|
64
|
+
|
65
|
+
# [Array<FixNum>, nil] RFC 2965 port scope for the cookie. If not nil,
|
66
|
+
# indicates specific ports on the HTTP server which should receive this
|
67
|
+
# cookie if contacted.
|
68
|
+
attr_reader :ports
|
69
|
+
|
70
|
+
# [DateTime] The Expires directive tells the browser when to delete the cookie.
|
71
|
+
# Derived from the format used in RFC 1123
|
72
|
+
attr_reader :expires
|
73
|
+
|
74
|
+
# [Fixnum] RFC 6265 allows the use of the Max-Age attribute to set the
|
75
|
+
# cookie’s expiration as an interval of seconds in the future, relative
|
76
|
+
# to the time the browser received the cookie.
|
77
|
+
attr_reader :max_age
|
78
|
+
|
79
|
+
# [Time] Time when this cookie was first evaluated and created.
|
80
|
+
attr_reader :created_at
|
81
|
+
|
82
|
+
def initialize(name, value, options={})
|
83
|
+
@name = name
|
84
|
+
@value = value
|
85
|
+
@secure = false
|
86
|
+
@http_only = false
|
87
|
+
@version = 1
|
88
|
+
@discard = false
|
89
|
+
@created_at = Time.now
|
90
|
+
|
91
|
+
options.each do |attr_name, attr_value|
|
92
|
+
self.instance_variable_set(:"@#{attr_name}", attr_value)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# Evaluate when this cookie will expire. Uses the original cookie fields
|
97
|
+
# for a max-age or expires
|
98
|
+
#
|
99
|
+
# @return [Time, nil] Time of expiry, if this cookie has an expiry set
|
100
|
+
def expires_at
|
101
|
+
if max_age
|
102
|
+
created_at + max_age
|
103
|
+
else
|
104
|
+
expires
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# Indicates whether the cookie is currently considered valid
|
109
|
+
#
|
110
|
+
# @return [Boolean]
|
111
|
+
def expired?
|
112
|
+
expires_at && Time.now > expires_at
|
113
|
+
end
|
114
|
+
|
115
|
+
# Indicates whether the cookie will be considered invalid after the end
|
116
|
+
# of the current user session
|
117
|
+
# @return [Boolean]
|
118
|
+
def session?
|
119
|
+
!expires_at || discard
|
120
|
+
end
|
121
|
+
|
122
|
+
def to_s
|
123
|
+
if value.include?('"')
|
124
|
+
"#{name}=\"#{value.gsub('"', '\\"')}\""
|
125
|
+
else
|
126
|
+
"#{name}=#{value}"
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# Returns a true if the request_uri is a domain-match, a path-match, and a
|
131
|
+
# port-match
|
132
|
+
def request_match?(request_uri)
|
133
|
+
uri = request_uri.is_a?(URI) ? request_uri : URI.parse(request_uri)
|
134
|
+
domain_match(uri.host) && path_match(uri.path) && port_match(uri.port)
|
135
|
+
end
|
136
|
+
|
137
|
+
# From RFC2965 Section 1.
|
138
|
+
#
|
139
|
+
# For two strings that represent paths, P1 and P2, P1 path-matches P2
|
140
|
+
# if P2 is a prefix of P1 (including the case where P1 and P2 string-
|
141
|
+
# compare equal). Thus, the string /tec/waldo path-matches /tec.
|
142
|
+
def path_match(request_path)
|
143
|
+
request_path.start_with?(path)
|
144
|
+
end
|
145
|
+
|
146
|
+
# From RFC2965 Section 1.
|
147
|
+
#
|
148
|
+
# Host A's name domain-matches host B's if
|
149
|
+
#
|
150
|
+
# * their host name strings string-compare equal; or
|
151
|
+
#
|
152
|
+
# * A is a HDN string and has the form NB, where N is a non-empty
|
153
|
+
# name string, B has the form .B', and B' is a HDN string. (So,
|
154
|
+
# x.y.com domain-matches .Y.com but not Y.com.)
|
155
|
+
def domain_match(request_domain)
|
156
|
+
request_domain = request_domain.downcase
|
157
|
+
|
158
|
+
return true if domain == request_domain
|
159
|
+
|
160
|
+
return false if request_domain =~ IPADDR
|
161
|
+
|
162
|
+
return true if domain == ".#{request_domain}"
|
163
|
+
|
164
|
+
return false if !domain.include?('.') && domain != 'local'
|
165
|
+
|
166
|
+
return false if !request_domain.end_with?(domain)
|
167
|
+
|
168
|
+
return !(request_domain[0...-domain.length].count('.') > (request_domain[-domain.length-1] == '.' ? 1 : 0))
|
169
|
+
end
|
170
|
+
|
171
|
+
# From RFC2965 Section 3.3
|
172
|
+
#
|
173
|
+
# The default behavior is that a cookie MAY be returned to any request-port.
|
174
|
+
#
|
175
|
+
# If the port attribute is set the port must be in the port-list.
|
176
|
+
def port_match(request_port)
|
177
|
+
return true unless ports
|
178
|
+
ports.include?(request_port)
|
179
|
+
end
|
180
|
+
|
181
|
+
def self.parse(request_uri, set_cookie_value)
|
182
|
+
uri = request_uri.is_a?(URI) ? request_uri : URI.parse(request_uri)
|
183
|
+
data = COOKIE.match(set_cookie_value)
|
184
|
+
options = {}
|
185
|
+
|
186
|
+
if !data
|
187
|
+
raise Net::HTTPHeaderSyntaxError.new("Invalid Set-Cookie header format")
|
188
|
+
end
|
189
|
+
|
190
|
+
if data[:attributes]
|
191
|
+
data[:attributes].scan(COOKIE_AV) do |key, quoted_value, value|
|
192
|
+
value = quoted_value.gsub(/\\(.)/, '\1') if !value && quoted_value
|
193
|
+
|
194
|
+
# RFC 2109 4.1, Attributes (names) are case-insensitive
|
195
|
+
case key.downcase
|
196
|
+
when 'comment'
|
197
|
+
options[:comment] = value
|
198
|
+
when 'commenturl'
|
199
|
+
options[:comment_url] = value
|
200
|
+
when 'discard'
|
201
|
+
options[:discard] = true
|
202
|
+
when 'domain'
|
203
|
+
if value =~ IPADDR
|
204
|
+
options[:domain] = value
|
205
|
+
else
|
206
|
+
# As per RFC2965 if a host name contains no dots, the effective host name is
|
207
|
+
# that name with the string .local appended to it.
|
208
|
+
value = "#{value}.local" if !value.include?('.')
|
209
|
+
options[:domain] = (value.start_with?('.') ? value : ".#{value}").downcase
|
210
|
+
end
|
211
|
+
when 'expires'
|
212
|
+
if value.include?('-')
|
213
|
+
options[:expires] = DateTime.strptime(value, '%a, %d-%b-%Y %H:%M:%S %Z')
|
214
|
+
else
|
215
|
+
options[:expires] = DateTime.strptime(value, '%a, %d %b %Y %H:%M:%S %Z')
|
216
|
+
end
|
217
|
+
when 'max-age'
|
218
|
+
options[:max_age] = value.to_i
|
219
|
+
when 'path'
|
220
|
+
options[:path] = value
|
221
|
+
when 'port'
|
222
|
+
options[:ports] = value.split(',').map(&:to_i)
|
223
|
+
when 'secure'
|
224
|
+
options[:secure] = true
|
225
|
+
when 'httponly'
|
226
|
+
options[:http_only] = true
|
227
|
+
when 'version'
|
228
|
+
options[:version] = value.to_i
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
options[:domain] ||= uri.host.downcase
|
233
|
+
options[:path] ||= uri.path
|
234
|
+
|
235
|
+
CookieStore::Cookie.new(data[:name], data[:value] || data[:quoted_value].gsub(/\\(.)/, '\1'), options)
|
236
|
+
end
|
237
|
+
|
238
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
class CookieStore::HashStore < CookieStore
|
2
|
+
|
3
|
+
def initialize
|
4
|
+
@domains = {}
|
5
|
+
end
|
6
|
+
|
7
|
+
def add(cookie)
|
8
|
+
#TODO: check for MAX_COOKIES_PER_DOMAIN && MAX_COOKIES_TOTAL, think remove the MAX_COOKIES_TOTAL tho
|
9
|
+
@domains[cookie.domain] ||= {}
|
10
|
+
@domains[cookie.domain][cookie.path] ||= {}
|
11
|
+
@domains[cookie.domain][cookie.path][cookie.name] = cookie
|
12
|
+
end
|
13
|
+
|
14
|
+
def cookies_for(request_uri)
|
15
|
+
request_uri = URI.parse(request_uri)
|
16
|
+
trigger_gc = false
|
17
|
+
request_cookies = []
|
18
|
+
|
19
|
+
search_domains_for(request_uri.host).each do |domain|
|
20
|
+
next unless @domains[domain]
|
21
|
+
|
22
|
+
@domains[domain].each do |path, cookies|
|
23
|
+
if request_uri.path.start_with?(path)
|
24
|
+
cookies.each do |name, cookie|
|
25
|
+
if cookie.expired?
|
26
|
+
trigger_gc = true
|
27
|
+
elsif cookie.port_match(request_uri.port) && (!cookie.secure || (cookie.secure && request_uri.scheme == 'https'))
|
28
|
+
request_cookies << cookie
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
gc if trigger_gc
|
36
|
+
|
37
|
+
request_cookies
|
38
|
+
end
|
39
|
+
|
40
|
+
def gc(close_session=false)
|
41
|
+
@domains.delete_if do |domain, paths|
|
42
|
+
paths.delete_if do |path, cookies|
|
43
|
+
cookies.delete_if do |cookie_name, cookie|
|
44
|
+
cookie.expired? || (close_session && cookie.session?)
|
45
|
+
end
|
46
|
+
cookies.empty?
|
47
|
+
end
|
48
|
+
paths.empty?
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
@@ -0,0 +1,313 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class CookieStore::CookieTest < Minitest::Test
|
4
|
+
|
5
|
+
# CookieStore::Cookie.new ================================================================
|
6
|
+
|
7
|
+
test "::new(name, value)" do
|
8
|
+
cookie = CookieStore::Cookie.new('foo', 'bar')
|
9
|
+
|
10
|
+
assert_equal 'foo', cookie.name
|
11
|
+
assert_equal 'bar', cookie.value
|
12
|
+
end
|
13
|
+
|
14
|
+
test "::new(name, value, options)" do
|
15
|
+
#TODO: test all options are set
|
16
|
+
cookie = CookieStore::Cookie.new('foo', 'bar', :domain => 'test.com')
|
17
|
+
|
18
|
+
assert_equal 'test.com', cookie.domain
|
19
|
+
end
|
20
|
+
|
21
|
+
# CookieStore::Cookie.domain_match =======================================================
|
22
|
+
|
23
|
+
test "::domain_match(request_domain)" do
|
24
|
+
{
|
25
|
+
'a.com' => 'a.com',
|
26
|
+
'test.com' => '.test.com',
|
27
|
+
'123.456.57.21' => '123.456.57.21'
|
28
|
+
#TODO: not sure how ipv6 works '[E3D7::51F4:9BC8:C0A8:6420]' => '[E3D7::51F4:9BC8:C0A8:6420]'
|
29
|
+
}.each do |host, cookie_host|
|
30
|
+
cookie = CookieStore::Cookie.new('key', 'value', :domain => cookie_host)
|
31
|
+
assert_equal true, cookie.domain_match(host)
|
32
|
+
end
|
33
|
+
|
34
|
+
{
|
35
|
+
'a.com' => 'b.com',
|
36
|
+
'test.com' => '.com',
|
37
|
+
'test.com' => '.com.',
|
38
|
+
'test.com' => 'com',
|
39
|
+
'test.com' => 'com.',
|
40
|
+
'y.x.foo.com' => '.foo.com',
|
41
|
+
'y.x.foo.com' => 'foo.com',
|
42
|
+
'123.456.57.21' => '123.456.57.22',
|
43
|
+
'123.456.57.21' => '.123.456.57.21'
|
44
|
+
#TODO: not sure how ipv6 works '[E3D7::51F4:9BC8:C0A8:6420]' => '[E3D7::51F4:9BC8:C0A8:6421]'
|
45
|
+
}.each do |host, cookie_host|
|
46
|
+
cookie = CookieStore::Cookie.new('key', 'value', :domain => cookie_host)
|
47
|
+
assert_equal false, cookie.domain_match(host)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# CookieStore::Cookie.path_match =========================================================
|
52
|
+
|
53
|
+
test "::path_match(request_path)" do
|
54
|
+
{
|
55
|
+
'/test' => '/',
|
56
|
+
'/this/is/my/url' => '/this/is'
|
57
|
+
}.each do |path, cookie_path|
|
58
|
+
cookie = CookieStore::Cookie.new('key', 'value', :path => cookie_path)
|
59
|
+
assert_equal true, cookie.path_match(path)
|
60
|
+
end
|
61
|
+
|
62
|
+
{
|
63
|
+
'/test' => '/rest',
|
64
|
+
'/' => '/test'
|
65
|
+
}.each do |path, cookie_path|
|
66
|
+
cookie = CookieStore::Cookie.new('key', 'value', :path => cookie_path)
|
67
|
+
assert_equal false, cookie.path_match(path)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# CookieStore::Cookie.port_match =========================================================
|
72
|
+
|
73
|
+
test "::port_match(request_port) without ports attribute set" do
|
74
|
+
cookie = CookieStore::Cookie.new('key', 'value')
|
75
|
+
assert_equal true, cookie.port_match(158)
|
76
|
+
end
|
77
|
+
|
78
|
+
test "::port_match(request_port) with ports attribute set" do
|
79
|
+
cookie = CookieStore::Cookie.new('key', 'value', :ports => [80, 8700])
|
80
|
+
assert_equal true, cookie.port_match(8700)
|
81
|
+
assert_equal false, cookie.port_match(87)
|
82
|
+
end
|
83
|
+
|
84
|
+
# CookieStore::Cookie.expires_at =========================================================
|
85
|
+
|
86
|
+
test "#expires_at based on max-age" do
|
87
|
+
travel_to Time.new(2013, 12, 13, 8, 26, 12, 0) do
|
88
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar; Max-Age=3600')
|
89
|
+
assert_equal Time.new(2013, 12, 13, 9, 26, 12, 0), cookie.expires_at
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
test "#expires_at based on expires attribute" do
|
94
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar; Expires="Wed, 13 Jan 2021 22:23:01 GMT"')
|
95
|
+
assert_equal DateTime.new(2021, 1, 13, 22, 23, 1, 0), cookie.expires_at
|
96
|
+
end
|
97
|
+
|
98
|
+
test "#expires_at perfers max-age to expires" do
|
99
|
+
travel_to Time.new(2013, 12, 13, 8, 26, 12, 0) do
|
100
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar; Max-Age=3600 Expires="Wed, 13 Jan 2021 22:23:01 GMT"')
|
101
|
+
assert_equal Time.new(2013, 12, 13, 9, 26, 12, 0), cookie.expires_at
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
test "#expires_at returns nil if no max-age or expires attribute" do
|
106
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar')
|
107
|
+
assert_equal nil, cookie.expires_at
|
108
|
+
end
|
109
|
+
|
110
|
+
# CookieStore::Cookie.expired? =========================================================
|
111
|
+
|
112
|
+
test "#expired?" do
|
113
|
+
cookie = travel_to Time.new(2013, 12, 13, 8, 26, 12, 0) do
|
114
|
+
CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar; Max-Age=3600')
|
115
|
+
end
|
116
|
+
|
117
|
+
assert_equal true, cookie.expired?
|
118
|
+
|
119
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar; Max-Age=3600')
|
120
|
+
assert_equal false, cookie.expired?
|
121
|
+
end
|
122
|
+
|
123
|
+
# CookieStore::Cookie.session? ===========================================================
|
124
|
+
|
125
|
+
test "#session? true by default" do
|
126
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar')
|
127
|
+
assert_equal true, cookie.session?
|
128
|
+
end
|
129
|
+
|
130
|
+
test "#session? false if on expiration" do
|
131
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar; Max-Age=3600')
|
132
|
+
assert_equal false, cookie.session?
|
133
|
+
end
|
134
|
+
|
135
|
+
test "#session? true if discard attribute is present" do
|
136
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar; Max-Age=3600; Discard')
|
137
|
+
assert_equal true, cookie.session?
|
138
|
+
|
139
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar; Discard')
|
140
|
+
assert_equal true, cookie.session?
|
141
|
+
end
|
142
|
+
|
143
|
+
# CookieStore::Cookie.to_s ===============================================================
|
144
|
+
|
145
|
+
test "#to_s" do
|
146
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar')
|
147
|
+
assert_equal "foo=bar", cookie.to_s
|
148
|
+
end
|
149
|
+
|
150
|
+
test "#to_s with a \" in the value" do
|
151
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test/this', 'foo="ba\"r"')
|
152
|
+
assert_equal "foo=\"ba\\\"r\"", cookie.to_s
|
153
|
+
end
|
154
|
+
|
155
|
+
#TODO: # CookieStore::Cookie.to_h ===============================================================
|
156
|
+
#
|
157
|
+
# test "#to_h" do
|
158
|
+
# cookie = travel_to Time.new(2013, 12, 13, 8, 26, 12, 0) do
|
159
|
+
# CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar; Max-Age=3600; Discard')
|
160
|
+
# end
|
161
|
+
#
|
162
|
+
# assert_equal({
|
163
|
+
# :name => 'foo',
|
164
|
+
# :value => 'bar',
|
165
|
+
# :domain => 'google.com',
|
166
|
+
# :path => '/test/this',
|
167
|
+
# :secure => false,
|
168
|
+
# :http_only => false,
|
169
|
+
# :version => 1,
|
170
|
+
# :comment => nil,
|
171
|
+
# :comment_url => nil,
|
172
|
+
# :discard => true,
|
173
|
+
# :ports => nil,
|
174
|
+
# :expires => nil,
|
175
|
+
# :max_age => 3600,
|
176
|
+
# :created_at => Time.new(2013, 12, 13, 8, 26, 12, 0)
|
177
|
+
# }, cookie.to_h)
|
178
|
+
# end
|
179
|
+
|
180
|
+
# CookieStore::Cookie.parse ==============================================================
|
181
|
+
|
182
|
+
test "::parse a simple cookie" do
|
183
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test', "foo=bar")
|
184
|
+
|
185
|
+
assert_equal 'foo', cookie.name
|
186
|
+
assert_equal 'bar', cookie.value
|
187
|
+
assert_equal 'google.com', cookie.domain
|
188
|
+
assert_equal '/test', cookie.path
|
189
|
+
assert_equal false, cookie.secure
|
190
|
+
assert_equal false, cookie.http_only
|
191
|
+
assert_equal nil, cookie.comment
|
192
|
+
assert_equal nil, cookie.comment_url
|
193
|
+
assert_equal 1, cookie.version
|
194
|
+
assert_equal false, cookie.discard
|
195
|
+
assert_equal nil, cookie.ports
|
196
|
+
assert_equal nil, cookie.expires
|
197
|
+
assert_equal nil, cookie.max_age
|
198
|
+
end
|
199
|
+
|
200
|
+
test "::parse normalizes the request domain" do
|
201
|
+
cookie = CookieStore::Cookie.parse('http://GoOGlE.com/test', "foo=bar")
|
202
|
+
assert_equal 'google.com', cookie.domain
|
203
|
+
end
|
204
|
+
|
205
|
+
test "::parse parth with a ? at the end" do
|
206
|
+
cookie = CookieStore::Cookie.parse('http://GoOGlE.com/test?key=value', "foo=bar")
|
207
|
+
assert_equal '/test', cookie.path
|
208
|
+
end
|
209
|
+
|
210
|
+
|
211
|
+
test "::parse parth with a # at the end" do
|
212
|
+
cookie = CookieStore::Cookie.parse('http://GoOGlE.com/test#anchor', "foo=bar")
|
213
|
+
assert_equal '/test', cookie.path
|
214
|
+
end
|
215
|
+
|
216
|
+
test "::parse a simple quoted cookie" do
|
217
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test', 'foo="b\"ar"')
|
218
|
+
|
219
|
+
assert_equal 'google.com', cookie.domain
|
220
|
+
assert_equal 'foo', cookie.name
|
221
|
+
assert_equal 'b"ar', cookie.value
|
222
|
+
end
|
223
|
+
|
224
|
+
test "::parse domain attribute without leading ." do
|
225
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test', "foo=bar; Domain=google.com")
|
226
|
+
assert_equal '.google.com', cookie.domain
|
227
|
+
end
|
228
|
+
|
229
|
+
test "::parse domain attribute with leading ." do
|
230
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test', "foo=bar; Domain=.google.com")
|
231
|
+
assert_equal '.google.com', cookie.domain
|
232
|
+
end
|
233
|
+
|
234
|
+
test "::parse domain attribute that is the superdomain" do
|
235
|
+
cookie = CookieStore::Cookie.parse('http://site.google.com/test', "foo=bar; Domain=google.com")
|
236
|
+
assert_equal '.google.com', cookie.domain
|
237
|
+
end
|
238
|
+
|
239
|
+
test "::parse domain attribute as ip" do
|
240
|
+
cookie = CookieStore::Cookie.parse('http://123.456.57.21/test', "foo=bar; Domain=123.456.57.21")
|
241
|
+
|
242
|
+
assert_equal '123.456.57.21', cookie.domain
|
243
|
+
end
|
244
|
+
|
245
|
+
test "::parse path attribute" do
|
246
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar; Path="/"')
|
247
|
+
|
248
|
+
assert_equal '/', cookie.path
|
249
|
+
end
|
250
|
+
|
251
|
+
test "::parse secure attribute" do
|
252
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar; Secure')
|
253
|
+
assert_equal true, cookie.secure
|
254
|
+
end
|
255
|
+
|
256
|
+
test "::parse http_only attribute" do
|
257
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar; HttpOnly')
|
258
|
+
assert_equal true, cookie.http_only
|
259
|
+
end
|
260
|
+
|
261
|
+
test "::parse comment attribute" do
|
262
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar; Comment="the c\"omment"')
|
263
|
+
assert_equal 'the c"omment', cookie.comment
|
264
|
+
end
|
265
|
+
|
266
|
+
test "::parse coment_url attribute" do
|
267
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar; CommentURL="http://google.com/url"')
|
268
|
+
assert_equal "http://google.com/url", cookie.comment_url
|
269
|
+
end
|
270
|
+
|
271
|
+
test "::parse version attribute" do
|
272
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar; Version=0')
|
273
|
+
assert_equal 0, cookie.version
|
274
|
+
end
|
275
|
+
|
276
|
+
test "::parse discard attribute" do
|
277
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar; Discard')
|
278
|
+
assert_equal true, cookie.discard
|
279
|
+
end
|
280
|
+
|
281
|
+
test "::parse port attribute" do
|
282
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar; Port="80"')
|
283
|
+
assert_equal [80], cookie.ports
|
284
|
+
|
285
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar; Port="80,8080"')
|
286
|
+
assert_equal [80, 8080], cookie.ports
|
287
|
+
end
|
288
|
+
|
289
|
+
test "::parse expires attribute" do
|
290
|
+
# Wed, 13 Jan 2021 22:23:01 GMT format
|
291
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar; Expires=Wed, 13 Jan 2021 22:23:01 GMT')
|
292
|
+
assert_equal DateTime.new(2021, 1, 13, 22, 23, 1, 0), cookie.expires
|
293
|
+
|
294
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar; Expires="Wed, 13 Jan 2021 22:23:01 GMT"')
|
295
|
+
assert_equal DateTime.new(2021, 1, 13, 22, 23, 1, 0), cookie.expires
|
296
|
+
|
297
|
+
# Wed, 13-Jan-2021 22:23:01 GMT format
|
298
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar; Expires=Wed, 13-Jan-2021 22:23:01 GMT')
|
299
|
+
assert_equal DateTime.new(2021, 1, 13, 22, 23, 1, 0), cookie.expires
|
300
|
+
|
301
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar; Expires="Wed, 13-Jan-2021 22:23:01 GMT"')
|
302
|
+
assert_equal DateTime.new(2021, 1, 13, 22, 23, 1, 0), cookie.expires
|
303
|
+
end
|
304
|
+
|
305
|
+
test "::parse max_age attribute" do
|
306
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar; Max-Age=3660')
|
307
|
+
assert_equal 3660, cookie.max_age
|
308
|
+
end
|
309
|
+
|
310
|
+
# TODO: test expires_at, based on expires attribute
|
311
|
+
# TODO: test expires_at, based on max-age attribute
|
312
|
+
|
313
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class CookieStore::HashStoreTest < Minitest::Test
|
4
|
+
|
5
|
+
test "#cookies_for" do
|
6
|
+
store = CookieStore::HashStore.new
|
7
|
+
|
8
|
+
store.add(CookieStore::Cookie.new('a','value', :domain => 'google.com', :path => '/'))
|
9
|
+
store.add(CookieStore::Cookie.new('b','value', :domain => '.google.com', :path => '/'))
|
10
|
+
store.add(CookieStore::Cookie.new('c','value', :domain => 'www.google.com', :path => '/'))
|
11
|
+
store.add(CookieStore::Cookie.new('d','value', :domain => 'random.com', :path => '/'))
|
12
|
+
|
13
|
+
store.add(CookieStore::Cookie.new('e','value', :domain => '.google.com', :path => '/'))
|
14
|
+
store.add(CookieStore::Cookie.new('f','value', :domain => '.google.com', :path => '/test'))
|
15
|
+
|
16
|
+
store.add(CookieStore::Cookie.new('g','value', :domain => '.google.com', :path => '/', :max_age => 3660))
|
17
|
+
store.add(CookieStore::Cookie.new('h','value', :domain => '.google.com', :path => '/', :max_age => 0))
|
18
|
+
|
19
|
+
store.add(CookieStore::Cookie.new('i','value', :domain => '.google.com', :path => '/', :ports => [80,8080]))
|
20
|
+
store.add(CookieStore::Cookie.new('j','value', :domain => '.google.com', :path => '/', :ports => [80,8080], :secure => true))
|
21
|
+
|
22
|
+
store.add(CookieStore::Cookie.new('k','value', :domain => '.google.com', :path => '/', :secure => true))
|
23
|
+
|
24
|
+
assert_equal %w(a b e g i), store.cookies_for('http://google.com/').map(&:name).sort
|
25
|
+
assert_equal %w(b e g i), store.cookies_for('http://test.google.com/').map(&:name).sort
|
26
|
+
assert_equal %w(b c e g i), store.cookies_for('http://www.google.com/').map(&:name).sort
|
27
|
+
|
28
|
+
assert_equal %w(b c e g i), store.cookies_for('http://www.google.com/rest').map(&:name).sort
|
29
|
+
assert_equal %w(b c e f g i), store.cookies_for('http://www.google.com/test').map(&:name).sort
|
30
|
+
|
31
|
+
assert_equal %w(b c e f g k), store.cookies_for('https://www.google.com/test').map(&:name).sort
|
32
|
+
end
|
33
|
+
|
34
|
+
test '#cookies_for removes expired cookies while iterating' do
|
35
|
+
store = CookieStore::HashStore.new
|
36
|
+
store.expects(:gc).once
|
37
|
+
|
38
|
+
store.add(CookieStore::Cookie.new('h','value', :domain => '.google.com', :path => '/', :max_age => 0))
|
39
|
+
store.cookies_for('http://google.com/')
|
40
|
+
end
|
41
|
+
|
42
|
+
test '#gc clears out expired cookies' do
|
43
|
+
store = CookieStore::HashStore.new
|
44
|
+
|
45
|
+
store.add(CookieStore::Cookie.new('h','value', :domain => '.google.com', :path => '/', :max_age => 0))
|
46
|
+
store.gc
|
47
|
+
assert_equal({}, store.instance_variable_get(:@domains))
|
48
|
+
|
49
|
+
store.add(CookieStore::Cookie.new('h','value', :domain => '.google.com', :path => '/', :max_age => 0))
|
50
|
+
store.add(CookieStore::Cookie.new('h','value', :domain => '.google.com', :path => '/'))
|
51
|
+
store.gc
|
52
|
+
assert_equal 1, store.instance_variable_get(:@domains).size
|
53
|
+
assert_equal 1, store.instance_variable_get(:@domains)['.google.com'].size
|
54
|
+
assert_equal 1, store.instance_variable_get(:@domains)['.google.com']['/'].size
|
55
|
+
end
|
56
|
+
|
57
|
+
test "#gc doesn't clears out session cookies when not out the session" do
|
58
|
+
store = CookieStore::HashStore.new
|
59
|
+
|
60
|
+
store.add(CookieStore::Cookie.new('h','value', :domain => '.google.com', :path => '/', :max_age => 0))
|
61
|
+
store.add(CookieStore::Cookie.new('h','value', :domain => '.google.com', :path => '/', :discard => true))
|
62
|
+
|
63
|
+
store.gc
|
64
|
+
assert_equal 1, store.instance_variable_get(:@domains).size
|
65
|
+
assert_equal 1, store.instance_variable_get(:@domains)['.google.com'].size
|
66
|
+
assert_equal 1, store.instance_variable_get(:@domains)['.google.com']['/'].size
|
67
|
+
end
|
68
|
+
|
69
|
+
test '#gc clears out session cookies when closing out the session' do
|
70
|
+
store = CookieStore::HashStore.new
|
71
|
+
|
72
|
+
store.add(CookieStore::Cookie.new('h','value', :domain => '.google.com', :path => '/', :discard => true))
|
73
|
+
|
74
|
+
store.gc(true)
|
75
|
+
assert_equal({}, store.instance_variable_get(:@domains))
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class CookieStoreTest < Minitest::Test
|
4
|
+
|
5
|
+
# Cookie.set_cookie =========================================================
|
6
|
+
|
7
|
+
test "#set_cookie" do
|
8
|
+
store = CookieStore.new
|
9
|
+
store.expects(:add)
|
10
|
+
|
11
|
+
store.set_cookie('http://google.com/test/this', 'foo=bar; Max-Age=3600')
|
12
|
+
end
|
13
|
+
|
14
|
+
test "#set_cookie rejects cookies where the value for the Domain attribute contains no embedded dots" do
|
15
|
+
store = CookieStore.new
|
16
|
+
store.expects(:add).never
|
17
|
+
|
18
|
+
store.set_cookie('http://google.com/test', 'foo=bar; Domain=com')
|
19
|
+
store.set_cookie('http://google.com/test', 'foo=bar; Domain=.com')
|
20
|
+
store.set_cookie('http://google.com/test', 'foo=bar; Domain=com.')
|
21
|
+
store.set_cookie('http://google.com/test', 'foo=bar; Domain=.com.')
|
22
|
+
end
|
23
|
+
|
24
|
+
test "#set_cookie rejects cookies that do not domain-match" do
|
25
|
+
store = CookieStore.new
|
26
|
+
store.expects(:add).never
|
27
|
+
|
28
|
+
store.set_cookie('http://google.com/test', 'foo=bar; Domain=gobble.com')
|
29
|
+
store.set_cookie('http://y.x.foo.com/test', 'foo=bar; Domain=.foo.com')
|
30
|
+
store.set_cookie('http://y.x.foo.com/test', 'foo=bar; Domain=foo.com')
|
31
|
+
store.set_cookie('http://123.456.57.21/test', 'foo=bar; Domain=123.456.57.22')
|
32
|
+
store.set_cookie('http://123.456.57.21/test', 'foo=bar; Domain=.123.456.57.21')
|
33
|
+
#TODO: not sure how ipv6 works '' => '[E3D7::51F4:9BC8:C0A8:6421]'
|
34
|
+
end
|
35
|
+
|
36
|
+
test "#set_cookie rejects cookies that do not path-match" do
|
37
|
+
store = CookieStore.new
|
38
|
+
store.expects(:add).never
|
39
|
+
|
40
|
+
store.set_cookie('http://google.com/test', 'foo=bar; Path=/text')
|
41
|
+
store.set_cookie('http://google.com/test', 'foo=bar; Path=/test/mykey')
|
42
|
+
end
|
43
|
+
|
44
|
+
test "#set_cookie rejects cookies that do not port-match" do
|
45
|
+
store = CookieStore.new
|
46
|
+
store.expects(:add).never
|
47
|
+
|
48
|
+
store.set_cookie('http://google.com:97/test', 'foo=bar; Port="80,8080"')
|
49
|
+
end
|
50
|
+
|
51
|
+
test "#set_cookie rejects cookies that are over the byte limit" do
|
52
|
+
store = CookieStore.new
|
53
|
+
store.expects(:add).never
|
54
|
+
|
55
|
+
store.set_cookie('http://google.com/test', "foo=#{'k'*(CookieStore::MAX_COOKIE_LENGTH-3)}; Max-Age=3600")
|
56
|
+
end
|
57
|
+
|
58
|
+
test "#search_domains_for" do
|
59
|
+
store = CookieStore.new
|
60
|
+
|
61
|
+
assert_equal ['google.com', '.google.com'], store.search_domains_for('google.com')
|
62
|
+
assert_equal ["www.google.com", ".www.google.com", ".google.com"], store.search_domains_for('www.google.com')
|
63
|
+
assert_equal ["com.local", ".com.local"], store.search_domains_for('com')
|
64
|
+
assert_equal ["123.456.57.22"], store.search_domains_for('123.456.57.22')
|
65
|
+
#TODO: not sure about ipv6 assert_equal ["com.local", ".com.local"], store.search_domains_for('[E3D7::51F4:9BC8:C0A8:6420]')
|
66
|
+
end
|
67
|
+
|
68
|
+
test "#close_session calls gc(true)" do
|
69
|
+
store = CookieStore.new
|
70
|
+
store.expects(:gc).with(true).once
|
71
|
+
|
72
|
+
store.close_session
|
73
|
+
end
|
74
|
+
|
75
|
+
test "#cookie_header_for" do
|
76
|
+
store = CookieStore.new
|
77
|
+
|
78
|
+
store.expects(:cookies_for).with('url').returns([CookieStore::Cookie.new('key', 'value')])
|
79
|
+
assert_equal 'key=value', store.cookie_header_for('url')
|
80
|
+
|
81
|
+
store.expects(:cookies_for).with('url').returns([CookieStore::Cookie.new('key', 'value'), CookieStore::Cookie.new('foo', 'bar')])
|
82
|
+
assert_equal 'key=value; foo=bar', store.cookie_header_for('url')
|
83
|
+
|
84
|
+
store.expects(:cookies_for).with('url').returns([CookieStore::Cookie.new('key', 'v"alue')])
|
85
|
+
assert_equal 'key="v\"alue"', store.cookie_header_for('url')
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# To make testing/debugging easier, test within this source tree versus an
|
2
|
+
# installed gem
|
3
|
+
dir = File.dirname(__FILE__)
|
4
|
+
root = File.expand_path(File.join(dir, '..'))
|
5
|
+
lib = File.expand_path(File.join(root, 'lib'))
|
6
|
+
|
7
|
+
$LOAD_PATH << lib
|
8
|
+
|
9
|
+
require 'cookie_store'
|
10
|
+
require "minitest/autorun"
|
11
|
+
require 'minitest/unit'
|
12
|
+
require 'minitest/reporters'
|
13
|
+
require 'faker'
|
14
|
+
require 'webmock/minitest'
|
15
|
+
require "mocha"
|
16
|
+
require "mocha/mini_test"
|
17
|
+
require 'active_support/testing/time_helpers'
|
18
|
+
|
19
|
+
Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new
|
20
|
+
|
21
|
+
# File 'lib/active_support/testing/declarative.rb', somewhere in rails....
|
22
|
+
class Minitest::Test
|
23
|
+
include ActiveSupport::Testing::TimeHelpers
|
24
|
+
|
25
|
+
def self.test(name, &block)
|
26
|
+
test_name = "test_#{name.gsub(/\s+/,'_')}".to_sym
|
27
|
+
defined = instance_method(test_name) rescue false
|
28
|
+
raise "#{test_name} is already defined in #{self}" if defined
|
29
|
+
if block_given?
|
30
|
+
define_method(test_name, &block)
|
31
|
+
else
|
32
|
+
define_method(test_name) do
|
33
|
+
flunk "No implementation provided for #{name}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
metadata
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cookie_store
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jon Bracy
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-07-09 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rake
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: minitest
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest-reporters
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: mocha
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: A Ruby library to handle and store client-side HTTP cookies
|
70
|
+
email:
|
71
|
+
- jonbracy@gmail.com
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- LICENSE
|
77
|
+
- README.md
|
78
|
+
- Rakefile
|
79
|
+
- cookie_store.gemspec
|
80
|
+
- lib/cookie_store.rb
|
81
|
+
- lib/cookie_store/cookie.rb
|
82
|
+
- lib/cookie_store/hash_store.rb
|
83
|
+
- test/cookie_store/cookie_test.rb
|
84
|
+
- test/cookie_store/hash_store_test.rb
|
85
|
+
- test/cookie_store_test.rb
|
86
|
+
- test/test_helper.rb
|
87
|
+
homepage: https://github.com/malomalo/cookie_store
|
88
|
+
licenses:
|
89
|
+
- MIT
|
90
|
+
metadata: {}
|
91
|
+
post_install_message:
|
92
|
+
rdoc_options: []
|
93
|
+
require_paths:
|
94
|
+
- lib
|
95
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
requirements: []
|
106
|
+
rubyforge_project:
|
107
|
+
rubygems_version: 2.2.2
|
108
|
+
signing_key:
|
109
|
+
specification_version: 4
|
110
|
+
summary: A Ruby library to handle client-side HTTP cookies
|
111
|
+
test_files:
|
112
|
+
- test/cookie_store/cookie_test.rb
|
113
|
+
- test/cookie_store/hash_store_test.rb
|
114
|
+
- test/cookie_store_test.rb
|
115
|
+
- test/test_helper.rb
|
116
|
+
has_rdoc:
|