cookie_store 0.1.0 → 0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/workflows/ci.yml +23 -0
- data/.gitignore +5 -0
- data/.tm_properties +1 -0
- data/Gemfile +4 -0
- data/README.md +1 -1
- data/cookie_store.gemspec +10 -5
- data/lib/cookie_store.rb +10 -7
- data/lib/cookie_store/cookie.rb +25 -76
- data/lib/cookie_store/cookie_parser.rb +110 -0
- data/lib/cookie_store/version.rb +3 -0
- data/test/cookie_store/cookie_test.rb +117 -18
- data/test/cookie_store_test.rb +10 -1
- data/test/test_helper.rb +19 -1
- metadata +98 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ed1b21def909112649960bb17b6e9f15291b27a45e1121111ba7fac8bc6944ca
|
4
|
+
data.tar.gz: 2c8066581ac182115e759ddf0421ce9e2a3ecc8c3bc6feab292efa9a2c9a3c16
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8db6b08273b5324d8866709e52af11eefe89538c891cf5d551160a51df4386a612defb0e8f560e55d406fcbbf15add61b415b56ffb2c933877d66e7ee557589d
|
7
|
+
data.tar.gz: 1049c26606be9fe1585377c983357958416bd842a4e36c41cac7107f8f58841fadd003e29cf2e98cef5ff6f1d67078f0af9461b58783a7f0f0e15632b4d6c63e
|
@@ -0,0 +1,23 @@
|
|
1
|
+
name: CI
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches: [ master ]
|
6
|
+
pull_request:
|
7
|
+
branches: [ master ]
|
8
|
+
|
9
|
+
jobs:
|
10
|
+
stream_parser:
|
11
|
+
name: CookieStore Test
|
12
|
+
runs-on: ubuntu-20.04
|
13
|
+
|
14
|
+
steps:
|
15
|
+
- uses: ruby/setup-ruby@v1
|
16
|
+
with:
|
17
|
+
ruby-version: 3.0
|
18
|
+
|
19
|
+
- uses: actions/checkout@v2
|
20
|
+
|
21
|
+
- run: bundle
|
22
|
+
|
23
|
+
- run: bundle exec rake test
|
data/.gitignore
ADDED
data/.tm_properties
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
exclude = '{$exclude,log,tmp,.tm_properties,coverage}'
|
data/Gemfile
ADDED
data/README.md
CHANGED
data/cookie_store.gemspec
CHANGED
@@ -1,25 +1,30 @@
|
|
1
|
-
|
2
|
-
$:.push File.expand_path("../lib", __FILE__)
|
1
|
+
require_relative 'lib/cookie_store/version'
|
3
2
|
|
4
3
|
Gem::Specification.new do |s|
|
5
4
|
s.name = "cookie_store"
|
6
|
-
s.version =
|
7
|
-
s.licenses = ['MIT']
|
5
|
+
s.version = CookieStore::VERSION
|
8
6
|
s.authors = ["Jon Bracy"]
|
9
7
|
s.email = ["jonbracy@gmail.com"]
|
10
8
|
s.homepage = "https://github.com/malomalo/cookie_store"
|
11
9
|
s.summary = %q{A Ruby library to handle client-side HTTP cookies}
|
12
|
-
s.description = %q{A Ruby library to handle
|
10
|
+
s.description = %q{A Ruby library to handle client-side HTTP cookies}
|
13
11
|
|
14
12
|
s.files = `git ls-files`.split("\n")
|
15
13
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
16
14
|
s.require_paths = ["lib"]
|
17
15
|
|
16
|
+
s.add_runtime_dependency 'stream_parser', '>= 0.2'
|
17
|
+
|
18
18
|
# Developoment
|
19
19
|
s.add_development_dependency 'rake'
|
20
|
+
s.add_development_dependency 'byebug'
|
20
21
|
# s.add_development_dependency 'rdoc'
|
21
22
|
# s.add_development_dependency 'sdoc'
|
22
23
|
s.add_development_dependency 'minitest'
|
23
24
|
s.add_development_dependency 'minitest-reporters'
|
24
25
|
s.add_development_dependency 'mocha'
|
26
|
+
s.add_development_dependency 'faker'
|
27
|
+
s.add_development_dependency 'webmock'
|
28
|
+
s.add_development_dependency 'activesupport'
|
29
|
+
s.add_development_dependency 'simplecov'
|
25
30
|
end
|
data/lib/cookie_store.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'uri'
|
2
2
|
|
3
3
|
class CookieStore
|
4
|
+
|
5
|
+
autoload :CookieParser, 'cookie_store/cookie_parser'
|
4
6
|
|
5
7
|
# Maximum number of bytes per cookie (RFC 6265 6.1 requires at least 4096)
|
6
8
|
MAX_COOKIE_LENGTH = 4096
|
@@ -14,15 +16,16 @@ class CookieStore
|
|
14
16
|
# Read and set the cookie from the Set-Cookie header
|
15
17
|
def set_cookie(request_uri, set_cookie_value)
|
16
18
|
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
19
|
|
22
|
-
|
23
|
-
|
20
|
+
CookieStore::Cookie.parse_cookies(request_uri, set_cookie_value) do |cookie|
|
21
|
+
# reject as per RFC2965 Section 3.3.2
|
22
|
+
return if !cookie.request_match?(request_uri) || !(cookie.domain =~ /.+\..+/ || cookie.domain == 'localhost')
|
24
23
|
|
25
|
-
|
24
|
+
# reject cookies over the max-bytes
|
25
|
+
return if cookie.to_s.size > MAX_COOKIE_LENGTH
|
26
|
+
|
27
|
+
add(cookie)
|
28
|
+
end
|
26
29
|
end
|
27
30
|
|
28
31
|
def cookie_header_for(request_uri)
|
data/lib/cookie_store/cookie.rb
CHANGED
@@ -1,29 +1,7 @@
|
|
1
1
|
class CookieStore::Cookie
|
2
2
|
|
3
|
-
|
4
|
-
|
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
|
-
|
3
|
+
IPADDR = /\A#{URI::REGEXP::PATTERN::IPV4ADDR}\Z|\A#{URI::REGEXP::PATTERN::IPV6ADDR}\Z/
|
4
|
+
|
27
5
|
# [String] The name of the cookie.
|
28
6
|
attr_reader :name
|
29
7
|
|
@@ -79,7 +57,7 @@ class CookieStore::Cookie
|
|
79
57
|
# [Time] Time when this cookie was first evaluated and created.
|
80
58
|
attr_reader :created_at
|
81
59
|
|
82
|
-
def initialize(name, value,
|
60
|
+
def initialize(name, value, attributes={})
|
83
61
|
@name = name
|
84
62
|
@value = value
|
85
63
|
@secure = false
|
@@ -88,8 +66,12 @@ class CookieStore::Cookie
|
|
88
66
|
@discard = false
|
89
67
|
@created_at = Time.now
|
90
68
|
|
91
|
-
|
92
|
-
|
69
|
+
@attributes = attributes
|
70
|
+
|
71
|
+
%i{name value domain path secure http_only version comment comment_url discard ports expires max_age created_at}.each do |attr_name|
|
72
|
+
if attributes.has_key?(attr_name)
|
73
|
+
self.instance_variable_set(:"@#{attr_name}", attributes[attr_name])
|
74
|
+
end
|
93
75
|
end
|
94
76
|
end
|
95
77
|
|
@@ -179,60 +161,27 @@ class CookieStore::Cookie
|
|
179
161
|
end
|
180
162
|
|
181
163
|
def self.parse(request_uri, set_cookie_value)
|
164
|
+
parse_cookies(request_uri, set_cookie_value).first
|
165
|
+
end
|
166
|
+
|
167
|
+
def self.parse_cookies(request_uri, set_cookie_value)
|
182
168
|
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
169
|
|
190
|
-
|
191
|
-
|
192
|
-
|
170
|
+
cookies = []
|
171
|
+
CookieStore::CookieParser.parse(set_cookie_value) do |parsed|
|
172
|
+
parsed[:attributes][:domain] ||= uri.host.downcase
|
173
|
+
parsed[:attributes][:path] ||= uri.path
|
193
174
|
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
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
|
175
|
+
cookie = CookieStore::Cookie.new(parsed[:key], parsed[:value], parsed[:attributes])
|
176
|
+
|
177
|
+
cookies << if block_given?
|
178
|
+
yield(cookie)
|
179
|
+
else
|
180
|
+
cookie
|
230
181
|
end
|
231
182
|
end
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
CookieStore::Cookie.new(data[:name], data[:value] || data[:quoted_value].gsub(/\\(.)/, '\1'), options)
|
183
|
+
|
184
|
+
cookies
|
236
185
|
end
|
237
186
|
|
238
187
|
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'stream_parser'
|
2
|
+
|
3
|
+
class CookieStore::CookieParser
|
4
|
+
|
5
|
+
include StreamParser
|
6
|
+
|
7
|
+
NUMERICAL_TIMEZONE = /[-+]\d{4}\Z/
|
8
|
+
|
9
|
+
def parse
|
10
|
+
cookie = {attributes: {}}
|
11
|
+
|
12
|
+
@stack = [:cookie_name]
|
13
|
+
while !eos?
|
14
|
+
case @stack.last
|
15
|
+
when :cookie_name
|
16
|
+
scan_until(/\s*=\s*/)
|
17
|
+
if match == '='
|
18
|
+
@stack << :cookie_value
|
19
|
+
cookie[:key] = pre_match
|
20
|
+
end
|
21
|
+
when :cookie_value
|
22
|
+
scan_until(/\s*(['";]\s*|\Z)/)
|
23
|
+
if match.strip == '"' || match.strip == "'"
|
24
|
+
cookie[:value] = quoted_value(match.strip)
|
25
|
+
@stack.pop
|
26
|
+
@stack << :cookie_attributes
|
27
|
+
elsif match
|
28
|
+
cookie[:value] = pre_match
|
29
|
+
@stack.pop
|
30
|
+
@stack << :cookie_attributes
|
31
|
+
end
|
32
|
+
when :cookie_attributes
|
33
|
+
# RFC 2109 4.1, Attributes (names) are case-insensitive
|
34
|
+
scan_until(/[,=;]\s*/)
|
35
|
+
if match&.start_with?('=')
|
36
|
+
key = normalize_key(pre_match)
|
37
|
+
scan_until(key == :expires ? /\s*((?<!\w{3}),|['";])\s*/ : /\s*(['";,]\s*|\Z)/)
|
38
|
+
if match =~ /["']\s*\Z/
|
39
|
+
cookie[:attributes][key] = normalize_attribute_value(key, quoted_value(match.strip))
|
40
|
+
elsif match =~ /,\s*\Z/
|
41
|
+
cookie[:attributes][key] = normalize_attribute_value(key, pre_match)
|
42
|
+
yield(cookie)
|
43
|
+
cookie = {attributes: {}}
|
44
|
+
@stack.pop
|
45
|
+
else
|
46
|
+
cookie[:attributes][key] = normalize_attribute_value(key, pre_match)
|
47
|
+
end
|
48
|
+
elsif match&.start_with?(',')
|
49
|
+
yield(cookie)
|
50
|
+
cookie = {attributes: {}}
|
51
|
+
@stack.pop
|
52
|
+
else
|
53
|
+
cookie[:attributes][normalize_key(pre_match)] = true
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
yield(cookie)
|
59
|
+
end
|
60
|
+
|
61
|
+
def normalize_key(key)
|
62
|
+
key = key.downcase.gsub('-','_')
|
63
|
+
if key == 'port'
|
64
|
+
:ports
|
65
|
+
elsif key == 'httponly'
|
66
|
+
:http_only
|
67
|
+
elsif key == 'commenturl'
|
68
|
+
:comment_url
|
69
|
+
else
|
70
|
+
key.to_sym
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def normalize_attribute_value(key, value)
|
75
|
+
case key
|
76
|
+
when :domain
|
77
|
+
if value =~ CookieStore::Cookie::IPADDR
|
78
|
+
value
|
79
|
+
else
|
80
|
+
# As per RFC2965 if a host name contains no dots, the effective host
|
81
|
+
# name is that name with the string .local appended to it.
|
82
|
+
value = "#{value}.local" if !value.include?('.')
|
83
|
+
(value.start_with?('.') ? value : ".#{value}").downcase
|
84
|
+
end
|
85
|
+
when :expires
|
86
|
+
byebug if $debug
|
87
|
+
case value
|
88
|
+
when /\w{3}, \d{2}-\w{3}-\d{2} /
|
89
|
+
DateTime.strptime(value, '%a, %d-%b-%y %H:%M:%S %Z')
|
90
|
+
when /\w{3}, \d{2}-\w{3}-\d{4} /
|
91
|
+
DateTime.strptime(value, '%a, %d-%b-%Y %H:%M:%S %Z')
|
92
|
+
when /\w{3}, \d{2} \w{3} \d{2} /
|
93
|
+
DateTime.strptime(value, '%a, %d %b %y %H:%M:%S %Z')
|
94
|
+
when /\w{3}, \d{2} \w{3} \d{4} /
|
95
|
+
DateTime.strptime(value, '%a, %d %b %Y %H:%M:%S %Z')
|
96
|
+
else
|
97
|
+
DateTime.parse(value)
|
98
|
+
end
|
99
|
+
when :max_age
|
100
|
+
value&.to_i
|
101
|
+
when :ports
|
102
|
+
value.split(',').map(&:to_i)
|
103
|
+
when :version
|
104
|
+
value.to_i
|
105
|
+
else
|
106
|
+
value
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
@@ -13,7 +13,7 @@ class CookieStore::CookieTest < Minitest::Test
|
|
13
13
|
|
14
14
|
test "::new(name, value, options)" do
|
15
15
|
#TODO: test all options are set
|
16
|
-
cookie = CookieStore::Cookie.new('foo', 'bar', :
|
16
|
+
cookie = CookieStore::Cookie.new('foo', 'bar', domain: 'test.com')
|
17
17
|
|
18
18
|
assert_equal 'test.com', cookie.domain
|
19
19
|
end
|
@@ -27,7 +27,7 @@ class CookieStore::CookieTest < Minitest::Test
|
|
27
27
|
'123.456.57.21' => '123.456.57.21'
|
28
28
|
#TODO: not sure how ipv6 works '[E3D7::51F4:9BC8:C0A8:6420]' => '[E3D7::51F4:9BC8:C0A8:6420]'
|
29
29
|
}.each do |host, cookie_host|
|
30
|
-
cookie = CookieStore::Cookie.new('key', 'value', :
|
30
|
+
cookie = CookieStore::Cookie.new('key', 'value', domain: cookie_host)
|
31
31
|
assert_equal true, cookie.domain_match(host)
|
32
32
|
end
|
33
33
|
|
@@ -43,7 +43,7 @@ class CookieStore::CookieTest < Minitest::Test
|
|
43
43
|
'123.456.57.21' => '.123.456.57.21'
|
44
44
|
#TODO: not sure how ipv6 works '[E3D7::51F4:9BC8:C0A8:6420]' => '[E3D7::51F4:9BC8:C0A8:6421]'
|
45
45
|
}.each do |host, cookie_host|
|
46
|
-
cookie = CookieStore::Cookie.new('key', 'value', :
|
46
|
+
cookie = CookieStore::Cookie.new('key', 'value', domain: cookie_host)
|
47
47
|
assert_equal false, cookie.domain_match(host)
|
48
48
|
end
|
49
49
|
end
|
@@ -55,7 +55,7 @@ class CookieStore::CookieTest < Minitest::Test
|
|
55
55
|
'/test' => '/',
|
56
56
|
'/this/is/my/url' => '/this/is'
|
57
57
|
}.each do |path, cookie_path|
|
58
|
-
cookie = CookieStore::Cookie.new('key', 'value', :
|
58
|
+
cookie = CookieStore::Cookie.new('key', 'value', path: cookie_path)
|
59
59
|
assert_equal true, cookie.path_match(path)
|
60
60
|
end
|
61
61
|
|
@@ -63,7 +63,7 @@ class CookieStore::CookieTest < Minitest::Test
|
|
63
63
|
'/test' => '/rest',
|
64
64
|
'/' => '/test'
|
65
65
|
}.each do |path, cookie_path|
|
66
|
-
cookie = CookieStore::Cookie.new('key', 'value', :
|
66
|
+
cookie = CookieStore::Cookie.new('key', 'value', path: cookie_path)
|
67
67
|
assert_equal false, cookie.path_match(path)
|
68
68
|
end
|
69
69
|
end
|
@@ -76,7 +76,7 @@ class CookieStore::CookieTest < Minitest::Test
|
|
76
76
|
end
|
77
77
|
|
78
78
|
test "::port_match(request_port) with ports attribute set" do
|
79
|
-
cookie = CookieStore::Cookie.new('key', 'value', :
|
79
|
+
cookie = CookieStore::Cookie.new('key', 'value', ports: [80, 8700])
|
80
80
|
assert_equal true, cookie.port_match(8700)
|
81
81
|
assert_equal false, cookie.port_match(87)
|
82
82
|
end
|
@@ -97,14 +97,19 @@ class CookieStore::CookieTest < Minitest::Test
|
|
97
97
|
|
98
98
|
test "#expires_at perfers max-age to expires" do
|
99
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"')
|
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
101
|
assert_equal Time.new(2013, 12, 13, 9, 26, 12, 0), cookie.expires_at
|
102
102
|
end
|
103
103
|
end
|
104
104
|
|
105
105
|
test "#expires_at returns nil if no max-age or expires attribute" do
|
106
106
|
cookie = CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar')
|
107
|
-
|
107
|
+
assert_nil cookie.expires_at
|
108
|
+
end
|
109
|
+
|
110
|
+
test "date formats" do
|
111
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test/this', 'foor=bar; expires=Fri, 04-Jun-21 14:13:58 GMT; path=/;')
|
112
|
+
assert_equal DateTime.new(2021, 6, 04, 14, 13, 58, 0), cookie.expires_at
|
108
113
|
end
|
109
114
|
|
110
115
|
# CookieStore::Cookie.expired? =========================================================
|
@@ -188,13 +193,31 @@ class CookieStore::CookieTest < Minitest::Test
|
|
188
193
|
assert_equal '/test', cookie.path
|
189
194
|
assert_equal false, cookie.secure
|
190
195
|
assert_equal false, cookie.http_only
|
191
|
-
|
192
|
-
|
196
|
+
assert_nil cookie.comment
|
197
|
+
assert_nil cookie.comment_url
|
198
|
+
assert_equal 1, cookie.version
|
199
|
+
assert_equal false, cookie.discard
|
200
|
+
assert_nil cookie.ports
|
201
|
+
assert_nil cookie.expires
|
202
|
+
assert_nil cookie.max_age
|
203
|
+
end
|
204
|
+
|
205
|
+
test "::parse a cookie with options" do
|
206
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test', "foo=bar; path=/; HttpOnly")
|
207
|
+
|
208
|
+
assert_equal 'foo', cookie.name
|
209
|
+
assert_equal 'bar', cookie.value
|
210
|
+
assert_equal 'google.com', cookie.domain
|
211
|
+
assert_equal '/', cookie.path
|
212
|
+
assert_equal false, cookie.secure
|
213
|
+
assert_equal true, cookie.http_only
|
214
|
+
assert_nil cookie.comment
|
215
|
+
assert_nil cookie.comment_url
|
193
216
|
assert_equal 1, cookie.version
|
194
217
|
assert_equal false, cookie.discard
|
195
|
-
|
196
|
-
|
197
|
-
|
218
|
+
assert_nil cookie.ports
|
219
|
+
assert_nil cookie.expires
|
220
|
+
assert_nil cookie.max_age
|
198
221
|
end
|
199
222
|
|
200
223
|
test "::parse normalizes the request domain" do
|
@@ -216,9 +239,9 @@ class CookieStore::CookieTest < Minitest::Test
|
|
216
239
|
test "::parse a simple quoted cookie" do
|
217
240
|
cookie = CookieStore::Cookie.parse('http://google.com/test', 'foo="b\"ar"')
|
218
241
|
|
219
|
-
assert_equal 'google.com',
|
220
|
-
assert_equal 'foo',
|
221
|
-
assert_equal 'b"ar',
|
242
|
+
assert_equal 'google.com', cookie.domain
|
243
|
+
assert_equal 'foo', cookie.name
|
244
|
+
assert_equal 'b"ar', cookie.value
|
222
245
|
end
|
223
246
|
|
224
247
|
test "::parse domain attribute without leading ." do
|
@@ -294,20 +317,96 @@ class CookieStore::CookieTest < Minitest::Test
|
|
294
317
|
cookie = CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar; Expires="Wed, 13 Jan 2021 22:23:01 GMT"')
|
295
318
|
assert_equal DateTime.new(2021, 1, 13, 22, 23, 1, 0), cookie.expires
|
296
319
|
|
320
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test/this', "foo=bar; Expires='Wed, 13 Jan 2021 22:23:01 GMT'")
|
321
|
+
assert_equal DateTime.new(2021, 1, 13, 22, 23, 1, 0), cookie.expires
|
322
|
+
|
323
|
+
# Wed, 13 Jan 21 22:23:01 GMT format
|
324
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar; Expires=Wed, 13 Jan 21 22:23:01 GMT')
|
325
|
+
assert_equal DateTime.new(2021, 1, 13, 22, 23, 1, 0), cookie.expires
|
326
|
+
|
327
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar; Expires="Wed, 13 Jan 21 22:23:01 GMT"')
|
328
|
+
assert_equal DateTime.new(2021, 1, 13, 22, 23, 1, 0), cookie.expires
|
329
|
+
|
330
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test/this', "foo=bar; Expires='Wed, 13 Jan 21 22:23:01 GMT'")
|
331
|
+
assert_equal DateTime.new(2021, 1, 13, 22, 23, 1, 0), cookie.expires
|
332
|
+
|
297
333
|
# Wed, 13-Jan-2021 22:23:01 GMT format
|
298
334
|
cookie = CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar; Expires=Wed, 13-Jan-2021 22:23:01 GMT')
|
299
335
|
assert_equal DateTime.new(2021, 1, 13, 22, 23, 1, 0), cookie.expires
|
300
336
|
|
301
337
|
cookie = CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar; Expires="Wed, 13-Jan-2021 22:23:01 GMT"')
|
302
338
|
assert_equal DateTime.new(2021, 1, 13, 22, 23, 1, 0), cookie.expires
|
339
|
+
|
340
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test/this', "foo=bar; Expires='Wed, 13-Jan-2021 22:23:01 GMT'")
|
341
|
+
assert_equal DateTime.new(2021, 1, 13, 22, 23, 1, 0), cookie.expires
|
342
|
+
|
343
|
+
# Wed, 13-Jan-21 22:23:01 GMT format
|
344
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar; Expires=Wed, 13-Jan-21 22:23:01 GMT')
|
345
|
+
assert_equal DateTime.new(2021, 1, 13, 22, 23, 1, 0), cookie.expires
|
346
|
+
|
347
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar; Expires="Wed, 13-Jan-21 22:23:01 GMT"')
|
348
|
+
assert_equal DateTime.new(2021, 1, 13, 22, 23, 1, 0), cookie.expires
|
349
|
+
|
350
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test/this', "foo=bar; Expires='Wed, 13-Jan-21 22:23:01 GMT'")
|
351
|
+
assert_equal DateTime.new(2021, 1, 13, 22, 23, 1, 0), cookie.expires
|
352
|
+
|
353
|
+
# Wed, 13 Jan 2021 22:23:01 -0000 format
|
354
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar; Expires=Wed, 13 Jan 2021 22:23:01 -0000')
|
355
|
+
assert_equal DateTime.new(2021, 1, 13, 22, 23, 1, 0), cookie.expires
|
356
|
+
|
357
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar; Expires="Wed, 13 Jan 2021 22:23:01 +0000"')
|
358
|
+
assert_equal DateTime.new(2021, 1, 13, 22, 23, 1, 0), cookie.expires
|
359
|
+
|
360
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test/this', "foo=bar; Expires='Wed, 13 Jan 2021 22:23:01 +0000'")
|
361
|
+
assert_equal DateTime.new(2021, 1, 13, 22, 23, 1, 0), cookie.expires
|
362
|
+
|
363
|
+
# Wed, 13 Jan 21 22:23:01 -0000 format
|
364
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar; Expires=Wed, 13 Jan 21 22:23:01 -0000')
|
365
|
+
assert_equal DateTime.new(2021, 1, 13, 22, 23, 1, 0), cookie.expires
|
366
|
+
|
367
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar; Expires="Wed, 13 Jan 21 22:23:01 +0000"')
|
368
|
+
assert_equal DateTime.new(2021, 1, 13, 22, 23, 1, 0), cookie.expires
|
369
|
+
|
370
|
+
cookie = CookieStore::Cookie.parse('http://google.com/test/this', "foo=bar; Expires='Wed, 13 Jan 21 22:23:01 +0000'")
|
371
|
+
assert_equal DateTime.new(2021, 1, 13, 22, 23, 1, 0), cookie.expires
|
303
372
|
end
|
304
373
|
|
305
374
|
test "::parse max_age attribute" do
|
306
375
|
cookie = CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar; Max-Age=3660')
|
307
376
|
assert_equal 3660, cookie.max_age
|
308
377
|
end
|
378
|
+
|
379
|
+
test "::parse_cookies with one cookie" do
|
380
|
+
cookies = CookieStore::Cookie.parse_cookies("http://google.com/test/this", "current_account_id=2449; path=/")
|
381
|
+
|
382
|
+
assert_equal "current_account_id", cookies.first.name
|
383
|
+
assert_equal "2449", cookies.first.value
|
384
|
+
assert_equal "/", cookies.first.path
|
385
|
+
end
|
386
|
+
|
387
|
+
test "::parse_cookies with multiple cookies" do
|
388
|
+
cookies = CookieStore::Cookie.parse_cookies("http://google.com/test/this", "current_account_id=2449; path=/, _session=QUZwVE5jNjB; path=/test; expires=Wed, 13-Jan-2021 22:23:01 GMT; HttpOnly")
|
389
|
+
|
390
|
+
assert_equal "current_account_id", cookies.first.name
|
391
|
+
assert_equal "2449", cookies.first.value
|
392
|
+
assert_equal "/", cookies.first.path
|
393
|
+
|
394
|
+
assert_equal "_session", cookies[1].name
|
395
|
+
assert_equal "QUZwVE5jNjB", cookies[1].value
|
396
|
+
assert_equal "/test", cookies[1].path
|
397
|
+
assert_equal DateTime.new(2021, 1, 13, 22, 23, 1, 0), cookies[1].expires
|
398
|
+
assert_equal true, cookies[1].http_only
|
399
|
+
end
|
309
400
|
|
310
|
-
#
|
311
|
-
|
401
|
+
# CookieStore::Cookie parse invalid cookies =========================================================
|
402
|
+
test "unclosed quotes" do
|
403
|
+
assert_raises Net::HTTPHeaderSyntaxError do
|
404
|
+
CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar; Max-Age="3660')
|
405
|
+
end
|
406
|
+
|
407
|
+
assert_raises Net::HTTPHeaderSyntaxError do
|
408
|
+
CookieStore::Cookie.parse('http://google.com/test/this', "foo=bar; Max-Age='3660")
|
409
|
+
end
|
410
|
+
end
|
312
411
|
|
313
412
|
end
|
data/test/cookie_store_test.rb
CHANGED
@@ -6,9 +6,18 @@ class CookieStoreTest < Minitest::Test
|
|
6
6
|
|
7
7
|
test "#set_cookie" do
|
8
8
|
store = CookieStore.new
|
9
|
-
store.expects(:add)
|
9
|
+
store.expects(:add).times(3)
|
10
10
|
|
11
11
|
store.set_cookie('http://google.com/test/this', 'foo=bar; Max-Age=3600')
|
12
|
+
store.set_cookie('http://localhost/test/this', 'foo=bar; Max-Age=3600')
|
13
|
+
store.set_cookie('http://127.0.0.1/test/this', 'foo=bar; Max-Age=3600')
|
14
|
+
end
|
15
|
+
|
16
|
+
test "#set_cookie contains multiple cookies" do
|
17
|
+
store = CookieStore.new
|
18
|
+
store.expects(:add).times(2)
|
19
|
+
|
20
|
+
store.set_cookie("http://google.com/test/this", "current_account_id=2449; path=/, _session=QUZwVE5jNjB; path=/test; expires=Wed, 13-Jan-2021 22:23:01 GMT; HttpOnly")
|
12
21
|
end
|
13
22
|
|
14
23
|
test "#set_cookie rejects cookies where the value for the Domain attribute contains no embedded dots" do
|
data/test/test_helper.rb
CHANGED
@@ -6,6 +6,9 @@ lib = File.expand_path(File.join(root, 'lib'))
|
|
6
6
|
|
7
7
|
$LOAD_PATH << lib
|
8
8
|
|
9
|
+
require 'simplecov'
|
10
|
+
SimpleCov.start
|
11
|
+
|
9
12
|
require 'cookie_store'
|
10
13
|
require "minitest/autorun"
|
11
14
|
require 'minitest/unit'
|
@@ -13,11 +16,18 @@ require 'minitest/reporters'
|
|
13
16
|
require 'faker'
|
14
17
|
require 'webmock/minitest'
|
15
18
|
require "mocha"
|
16
|
-
require "mocha/
|
19
|
+
require "mocha/minitest"
|
20
|
+
require 'active_support/time'
|
17
21
|
require 'active_support/testing/time_helpers'
|
22
|
+
require "byebug"
|
18
23
|
|
19
24
|
Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new
|
20
25
|
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
$debug = false
|
30
|
+
|
21
31
|
# File 'lib/active_support/testing/declarative.rb', somewhere in rails....
|
22
32
|
class Minitest::Test
|
23
33
|
include ActiveSupport::Testing::TimeHelpers
|
@@ -35,4 +45,12 @@ class Minitest::Test
|
|
35
45
|
end
|
36
46
|
end
|
37
47
|
|
48
|
+
def debug
|
49
|
+
$debug = true
|
50
|
+
puts '=========================='
|
51
|
+
yield
|
52
|
+
ensure
|
53
|
+
puts '=========================='
|
54
|
+
$debug = false
|
55
|
+
end
|
38
56
|
end
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cookie_store
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: '0.2'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jon Bracy
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-05-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: stream_parser
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.2'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.2'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: rake
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -24,6 +38,20 @@ dependencies:
|
|
24
38
|
- - ">="
|
25
39
|
- !ruby/object:Gem::Version
|
26
40
|
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: byebug
|
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'
|
27
55
|
- !ruby/object:Gem::Dependency
|
28
56
|
name: minitest
|
29
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -66,29 +94,90 @@ dependencies:
|
|
66
94
|
- - ">="
|
67
95
|
- !ruby/object:Gem::Version
|
68
96
|
version: '0'
|
69
|
-
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: faker
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: webmock
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: activesupport
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: simplecov
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
description: A Ruby library to handle client-side HTTP cookies
|
70
154
|
email:
|
71
155
|
- jonbracy@gmail.com
|
72
156
|
executables: []
|
73
157
|
extensions: []
|
74
158
|
extra_rdoc_files: []
|
75
159
|
files:
|
160
|
+
- ".github/workflows/ci.yml"
|
161
|
+
- ".gitignore"
|
162
|
+
- ".tm_properties"
|
163
|
+
- Gemfile
|
76
164
|
- LICENSE
|
77
165
|
- README.md
|
78
166
|
- Rakefile
|
79
167
|
- cookie_store.gemspec
|
80
168
|
- lib/cookie_store.rb
|
81
169
|
- lib/cookie_store/cookie.rb
|
170
|
+
- lib/cookie_store/cookie_parser.rb
|
82
171
|
- lib/cookie_store/hash_store.rb
|
172
|
+
- lib/cookie_store/version.rb
|
83
173
|
- test/cookie_store/cookie_test.rb
|
84
174
|
- test/cookie_store/hash_store_test.rb
|
85
175
|
- test/cookie_store_test.rb
|
86
176
|
- test/test_helper.rb
|
87
177
|
homepage: https://github.com/malomalo/cookie_store
|
88
|
-
licenses:
|
89
|
-
- MIT
|
178
|
+
licenses: []
|
90
179
|
metadata: {}
|
91
|
-
post_install_message:
|
180
|
+
post_install_message:
|
92
181
|
rdoc_options: []
|
93
182
|
require_paths:
|
94
183
|
- lib
|
@@ -103,9 +192,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
103
192
|
- !ruby/object:Gem::Version
|
104
193
|
version: '0'
|
105
194
|
requirements: []
|
106
|
-
|
107
|
-
|
108
|
-
signing_key:
|
195
|
+
rubygems_version: 3.2.3
|
196
|
+
signing_key:
|
109
197
|
specification_version: 4
|
110
198
|
summary: A Ruby library to handle client-side HTTP cookies
|
111
199
|
test_files:
|
@@ -113,4 +201,3 @@ test_files:
|
|
113
201
|
- test/cookie_store/hash_store_test.rb
|
114
202
|
- test/cookie_store_test.rb
|
115
203
|
- test/test_helper.rb
|
116
|
-
has_rdoc:
|