cookie_store 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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:
|