cookie_store 0.1.4 → 0.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 2fa62b0946bb98fb4646dd6d5a12cf0470ccca8c
4
- data.tar.gz: 7c60534b13a7e21151635f0985083edba439215f
2
+ SHA256:
3
+ metadata.gz: ed1b21def909112649960bb17b6e9f15291b27a45e1121111ba7fac8bc6944ca
4
+ data.tar.gz: 2c8066581ac182115e759ddf0421ce9e2a3ecc8c3bc6feab292efa9a2c9a3c16
5
5
  SHA512:
6
- metadata.gz: 4933dd902e5701f015ffc4f8b5c95ae869311505d3d3a054027c6aa31b96bb1b5d14751f751c2b6664e5c095faf1ae3912301b7640f5f18f70a20f59d1aa5385
7
- data.tar.gz: fec53203a8553011616023c165ca20217dad219cce3c713e22ab28f791034112aca8335502e77e66f7653ec8344b5ffa7afe6df77e6356da67f85e29ad1c0956
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
@@ -0,0 +1,5 @@
1
+ .DS_Store
2
+ *.gem
3
+ .byebug_history
4
+ Gemfile.lock
5
+ coverage/
data/.tm_properties ADDED
@@ -0,0 +1 @@
1
+ exclude = '{$exclude,log,tmp,.tm_properties,coverage}'
data/cookie_store.gemspec CHANGED
@@ -1,9 +1,8 @@
1
- # -*- encoding: utf-8 -*-
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 = '0.1.4'
5
+ s.version = CookieStore::VERSION
7
6
  s.authors = ["Jon Bracy"]
8
7
  s.email = ["jonbracy@gmail.com"]
9
8
  s.homepage = "https://github.com/malomalo/cookie_store"
@@ -14,8 +13,11 @@ Gem::Specification.new do |s|
14
13
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
15
14
  s.require_paths = ["lib"]
16
15
 
16
+ s.add_runtime_dependency 'stream_parser', '>= 0.2'
17
+
17
18
  # Developoment
18
19
  s.add_development_dependency 'rake'
20
+ s.add_development_dependency 'byebug'
19
21
  # s.add_development_dependency 'rdoc'
20
22
  # s.add_development_dependency 'sdoc'
21
23
  s.add_development_dependency 'minitest'
@@ -24,4 +26,5 @@ Gem::Specification.new do |s|
24
26
  s.add_development_dependency 'faker'
25
27
  s.add_development_dependency 'webmock'
26
28
  s.add_development_dependency 'activesupport'
29
+ s.add_development_dependency 'simplecov'
27
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
@@ -15,14 +17,14 @@ class CookieStore
15
17
  def set_cookie(request_uri, set_cookie_value)
16
18
  request_uri = URI.parse(request_uri)
17
19
 
18
- CookieStore::Cookie.parse_cookies(request_uri, set_cookie_value).each do |cookie|
20
+ CookieStore::Cookie.parse_cookies(request_uri, set_cookie_value) do |cookie|
19
21
  # reject as per RFC2965 Section 3.3.2
20
22
  return if !cookie.request_match?(request_uri) || !(cookie.domain =~ /.+\..+/ || cookie.domain == 'localhost')
21
23
 
22
24
  # reject cookies over the max-bytes
23
25
  return if cookie.to_s.size > MAX_COOKIE_LENGTH
24
26
 
25
- add(cookie)
27
+ add(cookie)
26
28
  end
27
29
  end
28
30
 
@@ -1,37 +1,7 @@
1
1
  class CookieStore::Cookie
2
2
 
3
- QUOTED_PAIR = "\\\\[\\x00-\\x7F]"
4
- LWS = "\\r\\n(?:[ \\t]+)"
5
- QDTEXT = "[\\t\\x20-\\x21\\x23-\\x3A\\x3C-\\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}|[^,;\\s]+)"
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}|[-+]\d{4})'
12
- NUMERICAL_TIMEZONE = /[-+]\d{4}$/
13
-
14
-
15
- COOKIE = /(?<name>#{TOKEN})=(?:"(?<quoted_value>#{QUOTED_TEXT})"|(?<value>#{VALUE}))(?<attributes>.*)/n
16
- COOKIE_AV = %r{
17
- ;\s+
18
- (?<key>#{TOKEN})
19
- (?:
20
- =
21
- (?:
22
- "(?<quoted_value>#{QUOTED_TEXT})"
23
- |
24
- (?<value>#{EXPIRES_AT_VALUE}|#{VALUE})
25
- )
26
- ){0,1}
27
- }nx
28
- COOKIES = %r{
29
- #{TOKEN}=(?:"#{QUOTED_TEXT}"|#{VALUE})
30
- (?:;\s+#{TOKEN}(?:=(?:"#{QUOTED_TEXT}"|(?:#{EXPIRES_AT_VALUE}|#{VALUE}))){0,1})*
31
- }nx
32
-
3
+ IPADDR = /\A#{URI::REGEXP::PATTERN::IPV4ADDR}\Z|\A#{URI::REGEXP::PATTERN::IPV6ADDR}\Z/
33
4
 
34
-
35
5
  # [String] The name of the cookie.
36
6
  attr_reader :name
37
7
 
@@ -87,7 +57,7 @@ class CookieStore::Cookie
87
57
  # [Time] Time when this cookie was first evaluated and created.
88
58
  attr_reader :created_at
89
59
 
90
- def initialize(name, value, options={})
60
+ def initialize(name, value, attributes={})
91
61
  @name = name
92
62
  @value = value
93
63
  @secure = false
@@ -96,8 +66,12 @@ class CookieStore::Cookie
96
66
  @discard = false
97
67
  @created_at = Time.now
98
68
 
99
- options.each do |attr_name, attr_value|
100
- self.instance_variable_set(:"@#{attr_name}", attr_value)
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
101
75
  end
102
76
  end
103
77
 
@@ -186,70 +160,28 @@ class CookieStore::Cookie
186
160
  ports.include?(request_port)
187
161
  end
188
162
 
189
- def self.parse_cookies(request_uri, set_cookie_value)
190
- uri = request_uri.is_a?(URI) ? request_uri : URI.parse(request_uri)
191
- cookies = []
192
- set_cookie_value.scan(COOKIES) do |cookie|
193
- cookies << parse(uri, cookie)
194
- end
195
- cookies
163
+ def self.parse(request_uri, set_cookie_value)
164
+ parse_cookies(request_uri, set_cookie_value).first
196
165
  end
197
166
 
198
- def self.parse(request_uri, set_cookie_value)
167
+ def self.parse_cookies(request_uri, set_cookie_value)
199
168
  uri = request_uri.is_a?(URI) ? request_uri : URI.parse(request_uri)
200
- data = COOKIE.match(set_cookie_value)
201
- options = {}
202
-
203
- if !data
204
- raise Net::HTTPHeaderSyntaxError.new("Invalid Set-Cookie header format")
205
- end
206
169
 
207
- if data[:attributes]
208
- data[:attributes].scan(COOKIE_AV) do |key, quoted_value, value|
209
- value = quoted_value.gsub(/\\(.)/, '\1') if !value && quoted_value
170
+ cookies = []
171
+ CookieStore::CookieParser.parse(set_cookie_value) do |parsed|
172
+ parsed[:attributes][:domain] ||= uri.host.downcase
173
+ parsed[:attributes][:path] ||= uri.path
174
+
175
+ cookie = CookieStore::Cookie.new(parsed[:key], parsed[:value], parsed[:attributes])
210
176
 
211
- # RFC 2109 4.1, Attributes (names) are case-insensitive
212
- case key.downcase
213
- when 'comment'
214
- options[:comment] = value
215
- when 'commenturl'
216
- options[:comment_url] = value
217
- when 'discard'
218
- options[:discard] = true
219
- when 'domain'
220
- if value =~ IPADDR
221
- options[:domain] = value
222
- else
223
- # As per RFC2965 if a host name contains no dots, the effective host name is
224
- # that name with the string .local appended to it.
225
- value = "#{value}.local" if !value.include?('.')
226
- options[:domain] = (value.start_with?('.') ? value : ".#{value}").downcase
227
- end
228
- when 'expires'
229
- if value.include?('-') && !value.match(NUMERICAL_TIMEZONE)
230
- options[:expires] = DateTime.strptime(value, '%a, %d-%b-%Y %H:%M:%S %Z')
231
- else
232
- options[:expires] = DateTime.strptime(value, '%a, %d %b %Y %H:%M:%S %Z')
233
- end
234
- when 'max-age'
235
- options[:max_age] = value.to_i
236
- when 'path'
237
- options[:path] = value
238
- when 'port'
239
- options[:ports] = value.split(',').map(&:to_i)
240
- when 'secure'
241
- options[:secure] = true
242
- when 'httponly'
243
- options[:http_only] = true
244
- when 'version'
245
- options[:version] = value.to_i
246
- end
177
+ cookies << if block_given?
178
+ yield(cookie)
179
+ else
180
+ cookie
247
181
  end
248
182
  end
249
- options[:domain] ||= uri.host.downcase
250
- options[:path] ||= uri.path
251
-
252
- CookieStore::Cookie.new(data[:name], data[:value] || data[:quoted_value].gsub(/\\(.)/, '\1'), options)
183
+
184
+ cookies
253
185
  end
254
186
 
255
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
@@ -0,0 +1,3 @@
1
+ class CookieStore
2
+ VERSION = '0.2'
3
+ 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', :domain => 'test.com')
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', :domain => cookie_host)
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', :domain => cookie_host)
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', :path => cookie_path)
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', :path => cookie_path)
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', :ports => [80, 8700])
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
- assert_equal nil, cookie.expires_at
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,13 @@ 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
- assert_equal nil, cookie.comment
192
- assert_equal nil, cookie.comment_url
196
+ assert_nil cookie.comment
197
+ assert_nil cookie.comment_url
193
198
  assert_equal 1, cookie.version
194
199
  assert_equal false, cookie.discard
195
- assert_equal nil, cookie.ports
196
- assert_equal nil, cookie.expires
197
- assert_equal nil, cookie.max_age
200
+ assert_nil cookie.ports
201
+ assert_nil cookie.expires
202
+ assert_nil cookie.max_age
198
203
  end
199
204
 
200
205
  test "::parse a cookie with options" do
@@ -206,13 +211,13 @@ class CookieStore::CookieTest < Minitest::Test
206
211
  assert_equal '/', cookie.path
207
212
  assert_equal false, cookie.secure
208
213
  assert_equal true, cookie.http_only
209
- assert_equal nil, cookie.comment
210
- assert_equal nil, cookie.comment_url
214
+ assert_nil cookie.comment
215
+ assert_nil cookie.comment_url
211
216
  assert_equal 1, cookie.version
212
217
  assert_equal false, cookie.discard
213
- assert_equal nil, cookie.ports
214
- assert_equal nil, cookie.expires
215
- assert_equal nil, cookie.max_age
218
+ assert_nil cookie.ports
219
+ assert_nil cookie.expires
220
+ assert_nil cookie.max_age
216
221
  end
217
222
 
218
223
  test "::parse normalizes the request domain" do
@@ -234,9 +239,9 @@ class CookieStore::CookieTest < Minitest::Test
234
239
  test "::parse a simple quoted cookie" do
235
240
  cookie = CookieStore::Cookie.parse('http://google.com/test', 'foo="b\"ar"')
236
241
 
237
- assert_equal 'google.com', cookie.domain
238
- assert_equal 'foo', cookie.name
239
- assert_equal 'b"ar', cookie.value
242
+ assert_equal 'google.com', cookie.domain
243
+ assert_equal 'foo', cookie.name
244
+ assert_equal 'b"ar', cookie.value
240
245
  end
241
246
 
242
247
  test "::parse domain attribute without leading ." do
@@ -312,6 +317,19 @@ class CookieStore::CookieTest < Minitest::Test
312
317
  cookie = CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar; Expires="Wed, 13 Jan 2021 22:23:01 GMT"')
313
318
  assert_equal DateTime.new(2021, 1, 13, 22, 23, 1, 0), cookie.expires
314
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
+
315
333
  # Wed, 13-Jan-2021 22:23:01 GMT format
316
334
  cookie = CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar; Expires=Wed, 13-Jan-2021 22:23:01 GMT')
317
335
  assert_equal DateTime.new(2021, 1, 13, 22, 23, 1, 0), cookie.expires
@@ -319,12 +337,38 @@ class CookieStore::CookieTest < Minitest::Test
319
337
  cookie = CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar; Expires="Wed, 13-Jan-2021 22:23:01 GMT"')
320
338
  assert_equal DateTime.new(2021, 1, 13, 22, 23, 1, 0), cookie.expires
321
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
+
322
353
  # Wed, 13 Jan 2021 22:23:01 -0000 format
323
354
  cookie = CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar; Expires=Wed, 13 Jan 2021 22:23:01 -0000')
324
355
  assert_equal DateTime.new(2021, 1, 13, 22, 23, 1, 0), cookie.expires
325
356
 
326
357
  cookie = CookieStore::Cookie.parse('http://google.com/test/this', 'foo=bar; Expires="Wed, 13 Jan 2021 22:23:01 +0000"')
327
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
328
372
  end
329
373
 
330
374
  test "::parse max_age attribute" do
@@ -354,7 +398,15 @@ class CookieStore::CookieTest < Minitest::Test
354
398
  assert_equal true, cookies[1].http_only
355
399
  end
356
400
 
357
- # TODO: test expires_at, based on expires attribute
358
- # TODO: test expires_at, based on max-age attribute
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
359
411
 
360
412
  end
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,12 +16,18 @@ require 'minitest/reporters'
13
16
  require 'faker'
14
17
  require 'webmock/minitest'
15
18
  require "mocha"
16
- require "mocha/mini_test"
19
+ require "mocha/minitest"
17
20
  require 'active_support/time'
18
21
  require 'active_support/testing/time_helpers'
22
+ require "byebug"
19
23
 
20
24
  Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new
21
25
 
26
+
27
+
28
+
29
+ $debug = false
30
+
22
31
  # File 'lib/active_support/testing/declarative.rb', somewhere in rails....
23
32
  class Minitest::Test
24
33
  include ActiveSupport::Testing::TimeHelpers
@@ -36,4 +45,12 @@ class Minitest::Test
36
45
  end
37
46
  end
38
47
 
48
+ def debug
49
+ $debug = true
50
+ puts '=========================='
51
+ yield
52
+ ensure
53
+ puts '=========================='
54
+ $debug = false
55
+ end
39
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.1.4
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: 2015-06-30 00:00:00.000000000 Z
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
@@ -108,6 +136,20 @@ dependencies:
108
136
  - - ">="
109
137
  - !ruby/object:Gem::Version
110
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'
111
153
  description: A Ruby library to handle client-side HTTP cookies
112
154
  email:
113
155
  - jonbracy@gmail.com
@@ -115,15 +157,19 @@ executables: []
115
157
  extensions: []
116
158
  extra_rdoc_files: []
117
159
  files:
160
+ - ".github/workflows/ci.yml"
161
+ - ".gitignore"
162
+ - ".tm_properties"
118
163
  - Gemfile
119
- - Gemfile.lock
120
164
  - LICENSE
121
165
  - README.md
122
166
  - Rakefile
123
167
  - cookie_store.gemspec
124
168
  - lib/cookie_store.rb
125
169
  - lib/cookie_store/cookie.rb
170
+ - lib/cookie_store/cookie_parser.rb
126
171
  - lib/cookie_store/hash_store.rb
172
+ - lib/cookie_store/version.rb
127
173
  - test/cookie_store/cookie_test.rb
128
174
  - test/cookie_store/hash_store_test.rb
129
175
  - test/cookie_store_test.rb
@@ -131,7 +177,7 @@ files:
131
177
  homepage: https://github.com/malomalo/cookie_store
132
178
  licenses: []
133
179
  metadata: {}
134
- post_install_message:
180
+ post_install_message:
135
181
  rdoc_options: []
136
182
  require_paths:
137
183
  - lib
@@ -146,9 +192,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
146
192
  - !ruby/object:Gem::Version
147
193
  version: '0'
148
194
  requirements: []
149
- rubyforge_project:
150
- rubygems_version: 2.4.5
151
- signing_key:
195
+ rubygems_version: 3.2.3
196
+ signing_key:
152
197
  specification_version: 4
153
198
  summary: A Ruby library to handle client-side HTTP cookies
154
199
  test_files:
data/Gemfile.lock DELETED
@@ -1,57 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- cookie_store (0.1.4)
5
-
6
- GEM
7
- remote: https://rubygems.org/
8
- specs:
9
- activesupport (4.1.8)
10
- i18n (~> 0.6, >= 0.6.9)
11
- json (~> 1.7, >= 1.7.7)
12
- minitest (~> 5.1)
13
- thread_safe (~> 0.1)
14
- tzinfo (~> 1.1)
15
- addressable (2.3.6)
16
- ansi (1.4.3)
17
- builder (3.2.2)
18
- crack (0.4.2)
19
- safe_yaml (~> 1.0.0)
20
- faker (1.4.3)
21
- i18n (~> 0.5)
22
- i18n (0.6.11)
23
- json (1.8.1)
24
- metaclass (0.0.4)
25
- minitest (5.5.0)
26
- minitest-reporters (1.0.8)
27
- ansi
28
- builder
29
- minitest (>= 5.0)
30
- ruby-progressbar
31
- mocha (1.1.0)
32
- metaclass (~> 0.0.1)
33
- rake (10.4.2)
34
- ruby-progressbar (1.7.0)
35
- safe_yaml (1.0.4)
36
- thread_safe (0.3.4)
37
- tzinfo (1.2.2)
38
- thread_safe (~> 0.1)
39
- webmock (1.20.4)
40
- addressable (>= 2.3.6)
41
- crack (>= 0.3.2)
42
-
43
- PLATFORMS
44
- ruby
45
-
46
- DEPENDENCIES
47
- activesupport
48
- cookie_store!
49
- faker
50
- minitest
51
- minitest-reporters
52
- mocha
53
- rake
54
- webmock
55
-
56
- BUNDLED WITH
57
- 1.10.4