http-cookie 1.0.2 → 1.0.5
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 +5 -5
- data/.github/workflows/ci.yml +37 -0
- data/CHANGELOG.md +17 -0
- data/http-cookie.gemspec +5 -4
- data/lib/http/cookie/scanner.rb +12 -11
- data/lib/http/cookie/version.rb +1 -1
- data/lib/http/cookie.rb +1 -1
- data/lib/http/cookie_jar/abstract_store.rb +2 -2
- data/lib/http/cookie_jar/hash_store.rb +0 -2
- data/lib/http/cookie_jar/mozilla_store.rb +142 -19
- data/lib/http/cookie_jar/yaml_saver.rb +12 -2
- data/test/test_http_cookie.rb +30 -7
- data/test/test_http_cookie_jar.rb +13 -10
- metadata +26 -27
- data/.travis.yml +0 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 5230b0bd44e032652855e7b9e60e3d994ca56adbd57550c7520930d4dbf734a4
|
4
|
+
data.tar.gz: 65240197f49ac57bac8c6f3d1104cfe4f8fff77e1ac992c05c72d74efbba8300
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7fc5bb2e287d60d060c54eb9fb9ccb6d55c55e84ec35525deff8c088c873d6ac26db86f7f1cf3c03a7cbf05e397b6cd0e3a1e1171c2dcff8848e0345a34b0905
|
7
|
+
data.tar.gz: 1c85e07a65fac1d5440126bea27dbc01160edc9a791f56e021cd3142070eada54bf1ec3cda31c9d9273f23c3a84c8786c308bcdd27e03f7266c203dde4abdd6f
|
@@ -0,0 +1,37 @@
|
|
1
|
+
name: CI
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches:
|
6
|
+
- master
|
7
|
+
pull_request:
|
8
|
+
branches:
|
9
|
+
- "*"
|
10
|
+
|
11
|
+
jobs:
|
12
|
+
test:
|
13
|
+
strategy:
|
14
|
+
fail-fast: false
|
15
|
+
matrix:
|
16
|
+
os: [ubuntu]
|
17
|
+
# We still kind of support Ruby 1.8.7
|
18
|
+
ruby: [2.7, "3.0", 3.1, head, jruby]
|
19
|
+
|
20
|
+
name: >-
|
21
|
+
${{matrix.os}}:ruby-${{matrix.ruby}}
|
22
|
+
runs-on: ${{matrix.os}}-latest
|
23
|
+
continue-on-error: ${{matrix.ruby == 'head' || matrix.ruby == 'jruby'}}
|
24
|
+
|
25
|
+
steps:
|
26
|
+
- name: Check out
|
27
|
+
uses: actions/checkout@v2
|
28
|
+
|
29
|
+
- name: Set up ruby and bundle
|
30
|
+
uses: ruby/setup-ruby@v1
|
31
|
+
with:
|
32
|
+
ruby-version: ${{matrix.ruby}}
|
33
|
+
bundler-cache: true
|
34
|
+
|
35
|
+
- name: Run rake
|
36
|
+
run: |
|
37
|
+
bundle exec rake
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,20 @@
|
|
1
|
+
## 1.0.5 (2022-05-25)
|
2
|
+
|
3
|
+
- Silence SQLite3 warnings
|
4
|
+
|
5
|
+
## 1.0.4 (2021-06-07)
|
6
|
+
|
7
|
+
- Support Mozilla's cookie storage format up to version 7.
|
8
|
+
|
9
|
+
- Fix the time representation with creationTime and lastAccessed in
|
10
|
+
MozillaStore. (#8)
|
11
|
+
|
12
|
+
## 1.0.3 (2016-09-30)
|
13
|
+
|
14
|
+
- Treat comma as normal character in HTTP::Cookie.cookie_value_to_hash
|
15
|
+
instead of key-value pair separator. This should fix the problem
|
16
|
+
described in CVE-2016-7401.
|
17
|
+
|
1
18
|
## 1.0.2 (2013-09-10)
|
2
19
|
|
3
20
|
- Fix HTTP::Cookie.parse so that it does not raise ArgumentError
|
data/http-cookie.gemspec
CHANGED
@@ -25,10 +25,11 @@ Gem::Specification.new do |gem|
|
|
25
25
|
gem.extra_rdoc_files = ['README.md', 'LICENSE.txt']
|
26
26
|
|
27
27
|
gem.add_runtime_dependency("domain_name", ["~> 0.5"])
|
28
|
-
gem.add_development_dependency("sqlite3", ["~> 1.3
|
28
|
+
gem.add_development_dependency("sqlite3", ["~> 1.3"]) unless defined?(JRUBY_VERSION)
|
29
29
|
gem.add_development_dependency("bundler", [">= 1.2.0"])
|
30
|
-
gem.add_development_dependency("test-unit", [">= 2.4.3"])
|
31
|
-
gem.add_development_dependency("rake", [">= 0.9.2.2"])
|
32
|
-
gem.add_development_dependency("rdoc",
|
30
|
+
gem.add_development_dependency("test-unit", [">= 2.4.3", *("< 3" if RUBY_VERSION < "1.9")])
|
31
|
+
gem.add_development_dependency("rake", [">= 0.9.2.2", *("< 11" if RUBY_VERSION < "1.9")])
|
32
|
+
gem.add_development_dependency("rdoc", RUBY_VERSION > "1.9" ? "> 2.4.2" : "~> 2.4.2")
|
33
33
|
gem.add_development_dependency("simplecov", [">= 0"])
|
34
|
+
gem.add_development_dependency("json", ["< 2"]) if RUBY_VERSION < "2.0"
|
34
35
|
end
|
data/lib/http/cookie/scanner.rb
CHANGED
@@ -50,7 +50,7 @@ class HTTP::Cookie::Scanner < StringScanner
|
|
50
50
|
}
|
51
51
|
end
|
52
52
|
|
53
|
-
def scan_value
|
53
|
+
def scan_value(comma_as_separator = false)
|
54
54
|
''.tap { |s|
|
55
55
|
case
|
56
56
|
when scan(/[^,;"]+/)
|
@@ -59,7 +59,9 @@ class HTTP::Cookie::Scanner < StringScanner
|
|
59
59
|
# RFC 6265 2.2
|
60
60
|
# A cookie-value may be DQUOTE'd.
|
61
61
|
s << scan_dquoted
|
62
|
-
when check(
|
62
|
+
when check(/;/)
|
63
|
+
break
|
64
|
+
when comma_as_separator && check(RE_COOKIE_COMMA)
|
63
65
|
break
|
64
66
|
else
|
65
67
|
s << getch
|
@@ -68,12 +70,12 @@ class HTTP::Cookie::Scanner < StringScanner
|
|
68
70
|
}
|
69
71
|
end
|
70
72
|
|
71
|
-
def scan_name_value
|
73
|
+
def scan_name_value(comma_as_separator = false)
|
72
74
|
name = scan_name
|
73
75
|
if skip(/\=/)
|
74
|
-
value = scan_value
|
76
|
+
value = scan_value(comma_as_separator)
|
75
77
|
else
|
76
|
-
scan_value
|
78
|
+
scan_value(comma_as_separator)
|
77
79
|
value = nil
|
78
80
|
end
|
79
81
|
[name, value]
|
@@ -159,7 +161,7 @@ class HTTP::Cookie::Scanner < StringScanner
|
|
159
161
|
|
160
162
|
skip_wsp
|
161
163
|
|
162
|
-
name, value = scan_name_value
|
164
|
+
name, value = scan_name_value(true)
|
163
165
|
if value.nil?
|
164
166
|
@logger.warn("Cookie definition lacks a name-value pair.") if @logger
|
165
167
|
elsif name.empty?
|
@@ -176,7 +178,7 @@ class HTTP::Cookie::Scanner < StringScanner
|
|
176
178
|
break
|
177
179
|
when skip(/;/)
|
178
180
|
skip_wsp
|
179
|
-
aname, avalue = scan_name_value
|
181
|
+
aname, avalue = scan_name_value(true)
|
180
182
|
next if aname.empty? || value.nil?
|
181
183
|
aname.downcase!
|
182
184
|
case aname
|
@@ -218,13 +220,12 @@ class HTTP::Cookie::Scanner < StringScanner
|
|
218
220
|
until eos?
|
219
221
|
skip_wsp
|
220
222
|
|
221
|
-
|
223
|
+
# Do not treat comma in a Cookie header value as separator; see CVE-2016-7401
|
224
|
+
name, value = scan_name_value(false)
|
222
225
|
|
223
226
|
yield name, value if value
|
224
227
|
|
225
|
-
|
226
|
-
# values of a header.
|
227
|
-
skip(/[;,]/)
|
228
|
+
skip(/;/)
|
228
229
|
end
|
229
230
|
end
|
230
231
|
end
|
data/lib/http/cookie/version.rb
CHANGED
data/lib/http/cookie.rb
CHANGED
@@ -128,7 +128,7 @@ class HTTP::Cookie
|
|
128
128
|
# new("name" => "uid", "value" => "a12345", "Domain" => 'www.example.org')
|
129
129
|
#
|
130
130
|
def initialize(*args)
|
131
|
-
@origin = @domain = @path =
|
131
|
+
@name = @origin = @domain = @path =
|
132
132
|
@expires = @max_age = nil
|
133
133
|
@for_domain = @secure = @httponly = false
|
134
134
|
@session = true
|
@@ -17,8 +17,8 @@ class HTTP::CookieJar::AbstractStore
|
|
17
17
|
begin
|
18
18
|
require 'http/cookie_jar/%s_store' % symbol
|
19
19
|
@@class_map.fetch(symbol)
|
20
|
-
rescue LoadError, IndexError
|
21
|
-
raise IndexError, 'cookie store unavailable: %s' % symbol.inspect
|
20
|
+
rescue LoadError, IndexError => e
|
21
|
+
raise IndexError, 'cookie store unavailable: %s, error: %s' % symbol.inspect, e.message
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
@@ -67,10 +67,8 @@ class HTTP::CookieJar
|
|
67
67
|
def each(uri = nil) # :yield: cookie
|
68
68
|
now = Time.now
|
69
69
|
if uri
|
70
|
-
thost = DomainName.new(uri.host)
|
71
70
|
tpath = uri.path
|
72
71
|
@jar.each { |domain, paths|
|
73
|
-
next unless thost.cookie_domain?(domain)
|
74
72
|
paths.each { |path, hash|
|
75
73
|
next unless HTTP::Cookie.path_match?(path, tpath)
|
76
74
|
hash.delete_if { |name, cookie|
|
@@ -10,7 +10,7 @@ class HTTP::CookieJar
|
|
10
10
|
# stored persistently in the SQLite3 database.
|
11
11
|
class MozillaStore < AbstractStore
|
12
12
|
# :stopdoc:
|
13
|
-
SCHEMA_VERSION =
|
13
|
+
SCHEMA_VERSION = 7
|
14
14
|
|
15
15
|
def default_options
|
16
16
|
{
|
@@ -22,14 +22,11 @@ class HTTP::CookieJar
|
|
22
22
|
|
23
23
|
ALL_COLUMNS = %w[
|
24
24
|
baseDomain
|
25
|
-
|
25
|
+
originAttributes
|
26
26
|
name value
|
27
27
|
host path
|
28
28
|
expiry creationTime lastAccessed
|
29
29
|
isSecure isHttpOnly
|
30
|
-
]
|
31
|
-
UK_COLUMNS = %w[
|
32
|
-
name host path
|
33
30
|
appId inBrowserElement
|
34
31
|
]
|
35
32
|
|
@@ -95,6 +92,11 @@ class HTTP::CookieJar
|
|
95
92
|
def initialize(options = nil)
|
96
93
|
super
|
97
94
|
|
95
|
+
@origin_attributes = encode_www_form({}.tap { |params|
|
96
|
+
params['appId'] = @app_id if @app_id.nonzero?
|
97
|
+
params['inBrowserElement'] = 1 if @in_browser_element
|
98
|
+
})
|
99
|
+
|
98
100
|
@filename = options[:filename] or raise ArgumentError, ':filename option is missing'
|
99
101
|
|
100
102
|
@sjar = HTTP::CookieJar::HashStore.new
|
@@ -134,7 +136,7 @@ class HTTP::CookieJar
|
|
134
136
|
|
135
137
|
# Returns the schema version of the database.
|
136
138
|
def schema_version
|
137
|
-
@schema_version ||= @db.execute("PRAGMA user_version").first[
|
139
|
+
@schema_version ||= @db.execute("PRAGMA user_version").first["user_version"]
|
138
140
|
rescue SQLite3::SQLException
|
139
141
|
@logger.warn "couldn't get schema version!" if @logger
|
140
142
|
return nil
|
@@ -147,8 +149,8 @@ class HTTP::CookieJar
|
|
147
149
|
@schema_version = version
|
148
150
|
end
|
149
151
|
|
150
|
-
def
|
151
|
-
self.schema_version =
|
152
|
+
def create_table_v5
|
153
|
+
self.schema_version = 5
|
152
154
|
@db.execute("DROP TABLE IF EXISTS moz_cookies")
|
153
155
|
@db.execute(<<-'SQL')
|
154
156
|
CREATE TABLE moz_cookies (
|
@@ -176,6 +178,62 @@ class HTTP::CookieJar
|
|
176
178
|
SQL
|
177
179
|
end
|
178
180
|
|
181
|
+
def create_table_v6
|
182
|
+
self.schema_version = 6
|
183
|
+
@db.execute("DROP TABLE IF EXISTS moz_cookies")
|
184
|
+
@db.execute(<<-'SQL')
|
185
|
+
CREATE TABLE moz_cookies (
|
186
|
+
id INTEGER PRIMARY KEY,
|
187
|
+
baseDomain TEXT,
|
188
|
+
originAttributes TEXT NOT NULL DEFAULT '',
|
189
|
+
name TEXT,
|
190
|
+
value TEXT,
|
191
|
+
host TEXT,
|
192
|
+
path TEXT,
|
193
|
+
expiry INTEGER,
|
194
|
+
lastAccessed INTEGER,
|
195
|
+
creationTime INTEGER,
|
196
|
+
isSecure INTEGER,
|
197
|
+
isHttpOnly INTEGER,
|
198
|
+
CONSTRAINT moz_uniqueid UNIQUE (name, host, path, originAttributes)
|
199
|
+
)
|
200
|
+
SQL
|
201
|
+
@db.execute(<<-'SQL')
|
202
|
+
CREATE INDEX moz_basedomain
|
203
|
+
ON moz_cookies (baseDomain,
|
204
|
+
originAttributes);
|
205
|
+
SQL
|
206
|
+
end
|
207
|
+
|
208
|
+
def create_table
|
209
|
+
self.schema_version = SCHEMA_VERSION
|
210
|
+
@db.execute("DROP TABLE IF EXISTS moz_cookies")
|
211
|
+
@db.execute(<<-'SQL')
|
212
|
+
CREATE TABLE moz_cookies (
|
213
|
+
id INTEGER PRIMARY KEY,
|
214
|
+
baseDomain TEXT,
|
215
|
+
originAttributes TEXT NOT NULL DEFAULT '',
|
216
|
+
name TEXT,
|
217
|
+
value TEXT,
|
218
|
+
host TEXT,
|
219
|
+
path TEXT,
|
220
|
+
expiry INTEGER,
|
221
|
+
lastAccessed INTEGER,
|
222
|
+
creationTime INTEGER,
|
223
|
+
isSecure INTEGER,
|
224
|
+
isHttpOnly INTEGER,
|
225
|
+
appId INTEGER DEFAULT 0,
|
226
|
+
inBrowserElement INTEGER DEFAULT 0,
|
227
|
+
CONSTRAINT moz_uniqueid UNIQUE (name, host, path, originAttributes)
|
228
|
+
)
|
229
|
+
SQL
|
230
|
+
@db.execute(<<-'SQL')
|
231
|
+
CREATE INDEX moz_basedomain
|
232
|
+
ON moz_cookies (baseDomain,
|
233
|
+
originAttributes);
|
234
|
+
SQL
|
235
|
+
end
|
236
|
+
|
179
237
|
def db_prepare(sql)
|
180
238
|
st = @db.prepare(sql)
|
181
239
|
yield st
|
@@ -226,7 +284,7 @@ class HTTP::CookieJar
|
|
226
284
|
when 4
|
227
285
|
@db.execute("ALTER TABLE moz_cookies RENAME TO moz_cookies_old")
|
228
286
|
@db.execute("DROP INDEX moz_basedomain")
|
229
|
-
|
287
|
+
create_table_v5
|
230
288
|
@db.execute(<<-'SQL')
|
231
289
|
INSERT INTO moz_cookies
|
232
290
|
(baseDomain, appId, inBrowserElement, name, value, host, path, expiry,
|
@@ -236,7 +294,42 @@ class HTTP::CookieJar
|
|
236
294
|
FROM moz_cookies_old
|
237
295
|
SQL
|
238
296
|
@db.execute("DROP TABLE moz_cookies_old")
|
297
|
+
when 5
|
298
|
+
@db.execute("ALTER TABLE moz_cookies RENAME TO moz_cookies_old")
|
299
|
+
@db.execute("DROP INDEX moz_basedomain")
|
300
|
+
create_table_v6
|
301
|
+
@db.create_function('CONVERT_TO_ORIGIN_ATTRIBUTES', 2) { |func, appId, inBrowserElement|
|
302
|
+
params = {}
|
303
|
+
params['appId'] = appId if appId.nonzero?
|
304
|
+
params['inBrowserElement'] = inBrowserElement if inBrowserElement.nonzero?
|
305
|
+
func.result = encode_www_form(params)
|
306
|
+
}
|
307
|
+
@db.execute(<<-'SQL')
|
308
|
+
INSERT INTO moz_cookies
|
309
|
+
(baseDomain, originAttributes, name, value, host, path, expiry,
|
310
|
+
lastAccessed, creationTime, isSecure, isHttpOnly)
|
311
|
+
SELECT baseDomain,
|
312
|
+
CONVERT_TO_ORIGIN_ATTRIBUTES(appId, inBrowserElement),
|
313
|
+
name, value, host, path, expiry, lastAccessed, creationTime,
|
314
|
+
isSecure, isHttpOnly
|
315
|
+
FROM moz_cookies_old
|
316
|
+
SQL
|
317
|
+
@db.execute("DROP TABLE moz_cookies_old")
|
318
|
+
when 6
|
319
|
+
@db.execute("ALTER TABLE moz_cookies ADD appId INTEGER DEFAULT 0")
|
320
|
+
@db.execute("ALTER TABLE moz_cookies ADD inBrowserElement INTEGER DEFAULT 0")
|
321
|
+
@db.create_function('SET_APP_ID', 1) { |func, originAttributes|
|
322
|
+
func.result = get_query_param(originAttributes, 'appId').to_i # nil.to_i == 0
|
323
|
+
}
|
324
|
+
@db.create_function('SET_IN_BROWSER', 1) { |func, originAttributes|
|
325
|
+
func.result = get_query_param(originAttributes, 'inBrowserElement').to_i # nil.to_i == 0
|
326
|
+
}
|
327
|
+
@db.execute(<<-'SQL')
|
328
|
+
UPDATE moz_cookies SET appId = SET_APP_ID(originAttributes),
|
329
|
+
inBrowserElement = SET_IN_BROWSER(originAttributes)
|
330
|
+
SQL
|
239
331
|
@logger.info("Upgraded database to schema version %d" % schema_version) if @logger
|
332
|
+
self.schema_version += 1
|
240
333
|
else
|
241
334
|
break
|
242
335
|
end
|
@@ -259,16 +352,17 @@ class HTTP::CookieJar
|
|
259
352
|
def db_add(cookie)
|
260
353
|
@stmt[:add].execute({
|
261
354
|
:baseDomain => cookie.domain_name.domain || cookie.domain,
|
262
|
-
:
|
263
|
-
:inBrowserElement => @in_browser_element ? 1 : 0,
|
355
|
+
:originAttributes => @origin_attributes,
|
264
356
|
:name => cookie.name, :value => cookie.value,
|
265
357
|
:host => cookie.dot_domain,
|
266
358
|
:path => cookie.path,
|
267
359
|
:expiry => cookie.expires_at.to_i,
|
268
|
-
:creationTime => cookie.created_at
|
269
|
-
:lastAccessed => cookie.accessed_at
|
360
|
+
:creationTime => serialize_usectime(cookie.created_at),
|
361
|
+
:lastAccessed => serialize_usectime(cookie.accessed_at),
|
270
362
|
:isSecure => cookie.secure? ? 1 : 0,
|
271
363
|
:isHttpOnly => cookie.httponly? ? 1 : 0,
|
364
|
+
:appId => @app_id,
|
365
|
+
:inBrowserElement => @in_browser_element ? 1 : 0,
|
272
366
|
})
|
273
367
|
cleanup if (@gc_index += 1) >= @gc_threshold
|
274
368
|
|
@@ -295,6 +389,36 @@ class HTTP::CookieJar
|
|
295
389
|
self
|
296
390
|
end
|
297
391
|
|
392
|
+
if RUBY_VERSION >= '1.9'
|
393
|
+
def encode_www_form(enum)
|
394
|
+
URI.encode_www_form(enum)
|
395
|
+
end
|
396
|
+
|
397
|
+
def get_query_param(str, key)
|
398
|
+
URI.decode_www_form(str).find { |k, v|
|
399
|
+
break v if k == key
|
400
|
+
}
|
401
|
+
end
|
402
|
+
else
|
403
|
+
require 'cgi'
|
404
|
+
|
405
|
+
def encode_www_form(enum)
|
406
|
+
enum.map { |k, v| "#{CGI.escape(k)}=#{CGI.escape(v)}" }.join('&')
|
407
|
+
end
|
408
|
+
|
409
|
+
def get_query_param(str, key)
|
410
|
+
CGI.parse(str)[key].first
|
411
|
+
end
|
412
|
+
end
|
413
|
+
|
414
|
+
def serialize_usectime(time)
|
415
|
+
time ? (time.to_f * 1e6).floor : 0
|
416
|
+
end
|
417
|
+
|
418
|
+
def deserialize_usectime(value)
|
419
|
+
Time.at(value ? value / 1e6 : 0)
|
420
|
+
end
|
421
|
+
|
298
422
|
public
|
299
423
|
|
300
424
|
def add(cookie)
|
@@ -337,7 +461,6 @@ class HTTP::CookieJar
|
|
337
461
|
now = Time.now
|
338
462
|
if uri
|
339
463
|
thost = DomainName.new(uri.host)
|
340
|
-
tpath = uri.path
|
341
464
|
|
342
465
|
@stmt[:cookies_for_domain].execute({
|
343
466
|
:baseDomain => thost.domain || thost.hostname,
|
@@ -355,8 +478,8 @@ class HTTP::CookieJar
|
|
355
478
|
attrs[:domain] = row['host']
|
356
479
|
attrs[:path] = row['path']
|
357
480
|
attrs[:expires_at] = Time.at(row['expiry'])
|
358
|
-
attrs[:accessed_at] =
|
359
|
-
attrs[:created_at] =
|
481
|
+
attrs[:accessed_at] = deserialize_usectime(row['lastAccessed'])
|
482
|
+
attrs[:created_at] = deserialize_usectime(row['creationTime'])
|
360
483
|
attrs[:secure] = secure
|
361
484
|
attrs[:httponly] = row['isHttpOnly'] != 0
|
362
485
|
})
|
@@ -364,7 +487,7 @@ class HTTP::CookieJar
|
|
364
487
|
if cookie.valid_for_uri?(uri)
|
365
488
|
cookie.accessed_at = now
|
366
489
|
@stmt[:update_lastaccessed].execute({
|
367
|
-
'lastAccessed' => now
|
490
|
+
'lastAccessed' => serialize_usectime(now),
|
368
491
|
'id' => row['id'],
|
369
492
|
})
|
370
493
|
yield cookie
|
@@ -383,8 +506,8 @@ class HTTP::CookieJar
|
|
383
506
|
attrs[:domain] = row['host']
|
384
507
|
attrs[:path] = row['path']
|
385
508
|
attrs[:expires_at] = Time.at(row['expiry'])
|
386
|
-
attrs[:accessed_at] =
|
387
|
-
attrs[:created_at] =
|
509
|
+
attrs[:accessed_at] = deserialize_usectime(row['lastAccessed'])
|
510
|
+
attrs[:created_at] = deserialize_usectime(row['creationTime'])
|
388
511
|
attrs[:secure] = row['isSecure'] != 0
|
389
512
|
attrs[:httponly] = row['isHttpOnly'] != 0
|
390
513
|
})
|
@@ -21,7 +21,7 @@ class HTTP::CookieJar::YAMLSaver < HTTP::CookieJar::AbstractSaver
|
|
21
21
|
|
22
22
|
def load(io, jar)
|
23
23
|
begin
|
24
|
-
data =
|
24
|
+
data = load_yaml(io)
|
25
25
|
rescue ArgumentError => e
|
26
26
|
case e.message
|
27
27
|
when %r{\Aundefined class/module Mechanize::}
|
@@ -31,7 +31,7 @@ class HTTP::CookieJar::YAMLSaver < HTTP::CookieJar::AbstractSaver
|
|
31
31
|
yaml = io.read
|
32
32
|
# a gross hack
|
33
33
|
yaml.gsub!(%r{^( [^ ].*:) !ruby/object:Mechanize::Cookie$}, "\\1")
|
34
|
-
data =
|
34
|
+
data = load_yaml(yaml)
|
35
35
|
rescue Errno::ESPIPE
|
36
36
|
@logger.warn "could not rewind the stream for conversion" if @logger
|
37
37
|
rescue ArgumentError
|
@@ -73,4 +73,14 @@ class HTTP::CookieJar::YAMLSaver < HTTP::CookieJar::AbstractSaver
|
|
73
73
|
def default_options
|
74
74
|
{}
|
75
75
|
end
|
76
|
+
|
77
|
+
if YAML.name == 'Psych' && Psych::VERSION >= '3.1'
|
78
|
+
def load_yaml(yaml)
|
79
|
+
YAML.safe_load(yaml, :permitted_classes => %w[Time HTTP::Cookie Mechanize::Cookie DomainName], :aliases => true)
|
80
|
+
end
|
81
|
+
else
|
82
|
+
def load_yaml(yaml)
|
83
|
+
YAML.load(yaml)
|
84
|
+
end
|
85
|
+
end
|
76
86
|
end
|
data/test/test_http_cookie.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
require File.expand_path('helper', File.dirname(__FILE__))
|
3
|
+
require 'psych' if !defined?(YAML) && RUBY_VERSION == "1.9.2"
|
4
|
+
require 'yaml'
|
3
5
|
|
4
6
|
class TestHTTPCookie < Test::Unit::TestCase
|
5
7
|
def setup
|
@@ -441,17 +443,28 @@ class TestHTTPCookie < Test::Unit::TestCase
|
|
441
443
|
['Bar', 'value 2'],
|
442
444
|
['Baz', 'value3'],
|
443
445
|
['Bar', 'value"4'],
|
446
|
+
['Quux', 'x, value=5'],
|
444
447
|
]
|
445
448
|
|
446
449
|
cookie_value = HTTP::Cookie.cookie_value(pairs.map { |name, value|
|
447
450
|
HTTP::Cookie.new(:name => name, :value => value)
|
448
451
|
})
|
449
452
|
|
450
|
-
assert_equal 'Foo=value1; Bar="value 2"; Baz=value3; Bar="value\\"4"', cookie_value
|
453
|
+
assert_equal 'Foo=value1; Bar="value 2"; Baz=value3; Bar="value\\"4"; Quux="x, value=5"', cookie_value
|
451
454
|
|
452
455
|
hash = HTTP::Cookie.cookie_value_to_hash(cookie_value)
|
453
456
|
|
454
|
-
assert_equal
|
457
|
+
assert_equal pairs.map(&:first).uniq.size, hash.size
|
458
|
+
|
459
|
+
hash.each_pair { |name, value|
|
460
|
+
_, pvalue = pairs.assoc(name)
|
461
|
+
assert_equal pvalue, value
|
462
|
+
}
|
463
|
+
|
464
|
+
# Do not treat comma in a Cookie header value as separator; see CVE-2016-7401
|
465
|
+
hash = HTTP::Cookie.cookie_value_to_hash('Quux=x, value=5; Foo=value1; Bar="value 2"; Baz=value3; Bar="value\\"4"')
|
466
|
+
|
467
|
+
assert_equal pairs.map(&:first).uniq.size, hash.size
|
455
468
|
|
456
469
|
hash.each_pair { |name, value|
|
457
470
|
_, pvalue = pairs.assoc(name)
|
@@ -1062,6 +1075,16 @@ class TestHTTPCookie < Test::Unit::TestCase
|
|
1062
1075
|
}
|
1063
1076
|
end
|
1064
1077
|
|
1078
|
+
if YAML.name == 'Psych' && Psych::VERSION >= '3.1'
|
1079
|
+
private def load_yaml(yaml)
|
1080
|
+
YAML.safe_load(yaml, :permitted_classes => %w[Time HTTP::Cookie Mechanize::Cookie DomainName], :aliases => true)
|
1081
|
+
end
|
1082
|
+
else
|
1083
|
+
private def load_yaml(yaml)
|
1084
|
+
YAML.load(yaml)
|
1085
|
+
end
|
1086
|
+
end
|
1087
|
+
|
1065
1088
|
def test_yaml_expires
|
1066
1089
|
require 'yaml'
|
1067
1090
|
cookie = HTTP::Cookie.new(cookie_values)
|
@@ -1069,29 +1092,29 @@ class TestHTTPCookie < Test::Unit::TestCase
|
|
1069
1092
|
assert_equal false, cookie.session?
|
1070
1093
|
assert_equal nil, cookie.max_age
|
1071
1094
|
|
1072
|
-
ycookie =
|
1095
|
+
ycookie = load_yaml(cookie.to_yaml)
|
1073
1096
|
assert_equal false, ycookie.session?
|
1074
1097
|
assert_equal nil, ycookie.max_age
|
1075
1098
|
assert_in_delta cookie.expires, ycookie.expires, 1
|
1076
1099
|
|
1077
1100
|
cookie.expires = nil
|
1078
|
-
ycookie =
|
1101
|
+
ycookie = load_yaml(cookie.to_yaml)
|
1079
1102
|
assert_equal true, ycookie.session?
|
1080
1103
|
assert_equal nil, ycookie.max_age
|
1081
1104
|
|
1082
1105
|
cookie.expires = Time.now + 3600
|
1083
|
-
ycookie =
|
1106
|
+
ycookie = load_yaml(cookie.to_yaml)
|
1084
1107
|
assert_equal false, ycookie.session?
|
1085
1108
|
assert_equal nil, ycookie.max_age
|
1086
1109
|
assert_in_delta cookie.expires, ycookie.expires, 1
|
1087
1110
|
|
1088
1111
|
cookie.max_age = 3600
|
1089
|
-
ycookie =
|
1112
|
+
ycookie = load_yaml(cookie.to_yaml)
|
1090
1113
|
assert_equal false, ycookie.session?
|
1091
1114
|
assert_in_delta cookie.created_at + 3600, ycookie.expires, 1
|
1092
1115
|
|
1093
1116
|
cookie.max_age = nil
|
1094
|
-
ycookie =
|
1117
|
+
ycookie = load_yaml(cookie.to_yaml)
|
1095
1118
|
assert_equal true, ycookie.session?
|
1096
1119
|
assert_equal nil, ycookie.expires
|
1097
1120
|
end
|
@@ -20,11 +20,7 @@ module TestHTTPCookieJar
|
|
20
20
|
assert_raises(NameError) {
|
21
21
|
HTTP::CookieJar::ErroneousStore
|
22
22
|
}
|
23
|
-
|
24
|
-
assert_includes $LOADED_FEATURES, rb
|
25
|
-
else
|
26
|
-
assert_includes $LOADED_FEATURES, rb[(dir.size + 1)..-1]
|
27
|
-
end
|
23
|
+
assert($LOADED_FEATURES.any? { |file| FileTest.identical?(file, rb) })
|
28
24
|
}
|
29
25
|
end
|
30
26
|
|
@@ -45,11 +41,7 @@ module TestHTTPCookieJar
|
|
45
41
|
assert_raises(NameError) {
|
46
42
|
HTTP::CookieJar::ErroneousSaver
|
47
43
|
}
|
48
|
-
|
49
|
-
assert_includes $LOADED_FEATURES, rb
|
50
|
-
else
|
51
|
-
assert_includes $LOADED_FEATURES, rb[(dir.size + 1)..-1]
|
52
|
-
end
|
44
|
+
assert($LOADED_FEATURES.any? { |file| FileTest.identical?(file, rb) })
|
53
45
|
}
|
54
46
|
end
|
55
47
|
end
|
@@ -139,6 +131,17 @@ module TestHTTPCookieJar
|
|
139
131
|
assert_equal(0, @jar.cookies(URI('http://www.rubyforge.org/')).length)
|
140
132
|
end
|
141
133
|
|
134
|
+
def test_host_only_with_unqualified_hostname
|
135
|
+
@jar.add(HTTP::Cookie.new(cookie_values(
|
136
|
+
:origin => 'http://localhost/', :domain => 'localhost', :for_domain => false)))
|
137
|
+
|
138
|
+
assert_equal(1, @jar.cookies(URI('http://localhost/')).length)
|
139
|
+
|
140
|
+
assert_equal(1, @jar.cookies(URI('http://Localhost/')).length)
|
141
|
+
|
142
|
+
assert_equal(1, @jar.cookies(URI('https://Localhost/')).length)
|
143
|
+
end
|
144
|
+
|
142
145
|
def test_empty_value
|
143
146
|
url = URI 'http://rubyforge.org/'
|
144
147
|
values = cookie_values(:value => "")
|
metadata
CHANGED
@@ -1,114 +1,114 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: http-cookie
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Akinori MUSHA
|
8
8
|
- Aaron Patterson
|
9
9
|
- Eric Hodel
|
10
10
|
- Mike Dalessio
|
11
|
-
autorequire:
|
11
|
+
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date:
|
14
|
+
date: 2022-05-25 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: domain_name
|
18
18
|
requirement: !ruby/object:Gem::Requirement
|
19
19
|
requirements:
|
20
|
-
- - ~>
|
20
|
+
- - "~>"
|
21
21
|
- !ruby/object:Gem::Version
|
22
22
|
version: '0.5'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
26
26
|
requirements:
|
27
|
-
- - ~>
|
27
|
+
- - "~>"
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: '0.5'
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
31
|
name: sqlite3
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
33
33
|
requirements:
|
34
|
-
- - ~>
|
34
|
+
- - "~>"
|
35
35
|
- !ruby/object:Gem::Version
|
36
|
-
version: 1.3
|
36
|
+
version: '1.3'
|
37
37
|
type: :development
|
38
38
|
prerelease: false
|
39
39
|
version_requirements: !ruby/object:Gem::Requirement
|
40
40
|
requirements:
|
41
|
-
- - ~>
|
41
|
+
- - "~>"
|
42
42
|
- !ruby/object:Gem::Version
|
43
|
-
version: 1.3
|
43
|
+
version: '1.3'
|
44
44
|
- !ruby/object:Gem::Dependency
|
45
45
|
name: bundler
|
46
46
|
requirement: !ruby/object:Gem::Requirement
|
47
47
|
requirements:
|
48
|
-
- -
|
48
|
+
- - ">="
|
49
49
|
- !ruby/object:Gem::Version
|
50
50
|
version: 1.2.0
|
51
51
|
type: :development
|
52
52
|
prerelease: false
|
53
53
|
version_requirements: !ruby/object:Gem::Requirement
|
54
54
|
requirements:
|
55
|
-
- -
|
55
|
+
- - ">="
|
56
56
|
- !ruby/object:Gem::Version
|
57
57
|
version: 1.2.0
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: test-unit
|
60
60
|
requirement: !ruby/object:Gem::Requirement
|
61
61
|
requirements:
|
62
|
-
- -
|
62
|
+
- - ">="
|
63
63
|
- !ruby/object:Gem::Version
|
64
64
|
version: 2.4.3
|
65
65
|
type: :development
|
66
66
|
prerelease: false
|
67
67
|
version_requirements: !ruby/object:Gem::Requirement
|
68
68
|
requirements:
|
69
|
-
- -
|
69
|
+
- - ">="
|
70
70
|
- !ruby/object:Gem::Version
|
71
71
|
version: 2.4.3
|
72
72
|
- !ruby/object:Gem::Dependency
|
73
73
|
name: rake
|
74
74
|
requirement: !ruby/object:Gem::Requirement
|
75
75
|
requirements:
|
76
|
-
- -
|
76
|
+
- - ">="
|
77
77
|
- !ruby/object:Gem::Version
|
78
78
|
version: 0.9.2.2
|
79
79
|
type: :development
|
80
80
|
prerelease: false
|
81
81
|
version_requirements: !ruby/object:Gem::Requirement
|
82
82
|
requirements:
|
83
|
-
- -
|
83
|
+
- - ">="
|
84
84
|
- !ruby/object:Gem::Version
|
85
85
|
version: 0.9.2.2
|
86
86
|
- !ruby/object:Gem::Dependency
|
87
87
|
name: rdoc
|
88
88
|
requirement: !ruby/object:Gem::Requirement
|
89
89
|
requirements:
|
90
|
-
- -
|
90
|
+
- - ">"
|
91
91
|
- !ruby/object:Gem::Version
|
92
92
|
version: 2.4.2
|
93
93
|
type: :development
|
94
94
|
prerelease: false
|
95
95
|
version_requirements: !ruby/object:Gem::Requirement
|
96
96
|
requirements:
|
97
|
-
- -
|
97
|
+
- - ">"
|
98
98
|
- !ruby/object:Gem::Version
|
99
99
|
version: 2.4.2
|
100
100
|
- !ruby/object:Gem::Dependency
|
101
101
|
name: simplecov
|
102
102
|
requirement: !ruby/object:Gem::Requirement
|
103
103
|
requirements:
|
104
|
-
- -
|
104
|
+
- - ">="
|
105
105
|
- !ruby/object:Gem::Version
|
106
106
|
version: '0'
|
107
107
|
type: :development
|
108
108
|
prerelease: false
|
109
109
|
version_requirements: !ruby/object:Gem::Requirement
|
110
110
|
requirements:
|
111
|
-
- -
|
111
|
+
- - ">="
|
112
112
|
- !ruby/object:Gem::Version
|
113
113
|
version: '0'
|
114
114
|
description: HTTP::Cookie is a Ruby library to handle HTTP Cookies based on RFC 6265. It
|
@@ -127,8 +127,8 @@ extra_rdoc_files:
|
|
127
127
|
- README.md
|
128
128
|
- LICENSE.txt
|
129
129
|
files:
|
130
|
-
- .
|
131
|
-
- .
|
130
|
+
- ".github/workflows/ci.yml"
|
131
|
+
- ".gitignore"
|
132
132
|
- CHANGELOG.md
|
133
133
|
- Gemfile
|
134
134
|
- LICENSE.txt
|
@@ -156,24 +156,23 @@ homepage: https://github.com/sparklemotion/http-cookie
|
|
156
156
|
licenses:
|
157
157
|
- MIT
|
158
158
|
metadata: {}
|
159
|
-
post_install_message:
|
159
|
+
post_install_message:
|
160
160
|
rdoc_options: []
|
161
161
|
require_paths:
|
162
162
|
- lib
|
163
163
|
required_ruby_version: !ruby/object:Gem::Requirement
|
164
164
|
requirements:
|
165
|
-
- -
|
165
|
+
- - ">="
|
166
166
|
- !ruby/object:Gem::Version
|
167
167
|
version: '0'
|
168
168
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
169
169
|
requirements:
|
170
|
-
- -
|
170
|
+
- - ">="
|
171
171
|
- !ruby/object:Gem::Version
|
172
172
|
version: '0'
|
173
173
|
requirements: []
|
174
|
-
|
175
|
-
|
176
|
-
signing_key:
|
174
|
+
rubygems_version: 3.3.14
|
175
|
+
signing_key:
|
177
176
|
specification_version: 4
|
178
177
|
summary: A Ruby library to handle HTTP Cookies based on RFC 6265
|
179
178
|
test_files:
|
data/.travis.yml
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
language: ruby
|
2
|
-
rvm:
|
3
|
-
- 1.8.7
|
4
|
-
- ree
|
5
|
-
- 1.9.3
|
6
|
-
- 2.0.0
|
7
|
-
- ruby-head
|
8
|
-
- jruby-18mode
|
9
|
-
- jruby-19mode
|
10
|
-
- jruby-head
|
11
|
-
- rbx-18mode
|
12
|
-
- rbx-19mode
|
13
|
-
matrix:
|
14
|
-
allow_failures:
|
15
|
-
- rvm: ruby-head
|
16
|
-
- rvm: rbx-18mode
|
17
|
-
- rvm: rbx-19mode
|