http-cookie 1.0.0.pre12 → 1.0.4
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/.travis.yml +12 -8
- data/CHANGELOG.md +29 -0
- data/README.md +28 -0
- data/http-cookie.gemspec +7 -5
- data/lib/http/cookie.rb +37 -32
- data/lib/http/cookie/ruby_compat.rb +5 -1
- data/lib/http/cookie/scanner.rb +12 -25
- data/lib/http/cookie/version.rb +1 -1
- data/lib/http/cookie_jar.rb +57 -35
- data/lib/http/cookie_jar/abstract_saver.rb +16 -2
- data/lib/http/cookie_jar/abstract_store.rb +30 -6
- data/lib/http/cookie_jar/cookiestxt_saver.rb +23 -2
- data/lib/http/cookie_jar/hash_store.rb +6 -15
- data/lib/http/cookie_jar/mozilla_store.rb +147 -33
- data/lib/http/cookie_jar/yaml_saver.rb +29 -4
- data/test/helper.rb +30 -0
- data/test/test_http_cookie.rb +76 -23
- data/test/test_http_cookie_jar.rb +130 -14
- metadata +34 -29
@@ -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
|
|
@@ -68,6 +65,9 @@ class HTTP::CookieJar
|
|
68
65
|
end
|
69
66
|
# :startdoc:
|
70
67
|
|
68
|
+
# :call-seq:
|
69
|
+
# new(**options)
|
70
|
+
#
|
71
71
|
# Generates a Mozilla cookie store. If the file does not exist,
|
72
72
|
# it is created. If it does and its schema is old, it is
|
73
73
|
# automatically upgraded with a new schema keeping the existing
|
@@ -92,6 +92,11 @@ class HTTP::CookieJar
|
|
92
92
|
def initialize(options = nil)
|
93
93
|
super
|
94
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
|
+
|
95
100
|
@filename = options[:filename] or raise ArgumentError, ':filename option is missing'
|
96
101
|
|
97
102
|
@sjar = HTTP::CookieJar::HashStore.new
|
@@ -109,6 +114,7 @@ class HTTP::CookieJar
|
|
109
114
|
@gc_index = 0
|
110
115
|
end
|
111
116
|
|
117
|
+
# Raises TypeError. Cloning is inhibited in this store class.
|
112
118
|
def initialize_copy(other)
|
113
119
|
raise TypeError, 'can\'t clone %s' % self.class
|
114
120
|
end
|
@@ -138,13 +144,13 @@ class HTTP::CookieJar
|
|
138
144
|
|
139
145
|
protected
|
140
146
|
|
141
|
-
def schema_version=
|
147
|
+
def schema_version= version
|
142
148
|
@db.execute("PRAGMA user_version = %d" % version)
|
143
149
|
@schema_version = version
|
144
150
|
end
|
145
151
|
|
146
|
-
def
|
147
|
-
self.schema_version =
|
152
|
+
def create_table_v5
|
153
|
+
self.schema_version = 5
|
148
154
|
@db.execute("DROP TABLE IF EXISTS moz_cookies")
|
149
155
|
@db.execute(<<-'SQL')
|
150
156
|
CREATE TABLE moz_cookies (
|
@@ -172,6 +178,62 @@ class HTTP::CookieJar
|
|
172
178
|
SQL
|
173
179
|
end
|
174
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
|
+
|
175
237
|
def db_prepare(sql)
|
176
238
|
st = @db.prepare(sql)
|
177
239
|
yield st
|
@@ -222,7 +284,7 @@ class HTTP::CookieJar
|
|
222
284
|
when 4
|
223
285
|
@db.execute("ALTER TABLE moz_cookies RENAME TO moz_cookies_old")
|
224
286
|
@db.execute("DROP INDEX moz_basedomain")
|
225
|
-
|
287
|
+
create_table_v5
|
226
288
|
@db.execute(<<-'SQL')
|
227
289
|
INSERT INTO moz_cookies
|
228
290
|
(baseDomain, appId, inBrowserElement, name, value, host, path, expiry,
|
@@ -232,7 +294,42 @@ class HTTP::CookieJar
|
|
232
294
|
FROM moz_cookies_old
|
233
295
|
SQL
|
234
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
|
235
331
|
@logger.info("Upgraded database to schema version %d" % schema_version) if @logger
|
332
|
+
self.schema_version += 1
|
236
333
|
else
|
237
334
|
break
|
238
335
|
end
|
@@ -255,16 +352,17 @@ class HTTP::CookieJar
|
|
255
352
|
def db_add(cookie)
|
256
353
|
@stmt[:add].execute({
|
257
354
|
:baseDomain => cookie.domain_name.domain || cookie.domain,
|
258
|
-
:
|
259
|
-
:inBrowserElement => @in_browser_element ? 1 : 0,
|
355
|
+
:originAttributes => @origin_attributes,
|
260
356
|
:name => cookie.name, :value => cookie.value,
|
261
357
|
:host => cookie.dot_domain,
|
262
358
|
:path => cookie.path,
|
263
359
|
:expiry => cookie.expires_at.to_i,
|
264
|
-
:creationTime => cookie.created_at
|
265
|
-
:lastAccessed => cookie.accessed_at
|
360
|
+
:creationTime => serialize_usectime(cookie.created_at),
|
361
|
+
:lastAccessed => serialize_usectime(cookie.accessed_at),
|
266
362
|
:isSecure => cookie.secure? ? 1 : 0,
|
267
363
|
:isHttpOnly => cookie.httponly? ? 1 : 0,
|
364
|
+
:appId => @app_id,
|
365
|
+
:inBrowserElement => @in_browser_element ? 1 : 0,
|
268
366
|
})
|
269
367
|
cleanup if (@gc_index += 1) >= @gc_threshold
|
270
368
|
|
@@ -291,6 +389,36 @@ class HTTP::CookieJar
|
|
291
389
|
self
|
292
390
|
end
|
293
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
|
+
|
294
422
|
public
|
295
423
|
|
296
424
|
def add(cookie)
|
@@ -329,11 +457,10 @@ class HTTP::CookieJar
|
|
329
457
|
expiry >= :expiry
|
330
458
|
SQL
|
331
459
|
|
332
|
-
def each(uri = nil, &block)
|
460
|
+
def each(uri = nil, &block) # :yield: cookie
|
333
461
|
now = Time.now
|
334
462
|
if uri
|
335
463
|
thost = DomainName.new(uri.host)
|
336
|
-
tpath = uri.path
|
337
464
|
|
338
465
|
@stmt[:cookies_for_domain].execute({
|
339
466
|
:baseDomain => thost.domain || thost.hostname,
|
@@ -351,8 +478,8 @@ class HTTP::CookieJar
|
|
351
478
|
attrs[:domain] = row['host']
|
352
479
|
attrs[:path] = row['path']
|
353
480
|
attrs[:expires_at] = Time.at(row['expiry'])
|
354
|
-
attrs[:accessed_at] =
|
355
|
-
attrs[:created_at] =
|
481
|
+
attrs[:accessed_at] = deserialize_usectime(row['lastAccessed'])
|
482
|
+
attrs[:created_at] = deserialize_usectime(row['creationTime'])
|
356
483
|
attrs[:secure] = secure
|
357
484
|
attrs[:httponly] = row['isHttpOnly'] != 0
|
358
485
|
})
|
@@ -360,7 +487,7 @@ class HTTP::CookieJar
|
|
360
487
|
if cookie.valid_for_uri?(uri)
|
361
488
|
cookie.accessed_at = now
|
362
489
|
@stmt[:update_lastaccessed].execute({
|
363
|
-
'lastAccessed' => now
|
490
|
+
'lastAccessed' => serialize_usectime(now),
|
364
491
|
'id' => row['id'],
|
365
492
|
})
|
366
493
|
yield cookie
|
@@ -379,8 +506,8 @@ class HTTP::CookieJar
|
|
379
506
|
attrs[:domain] = row['host']
|
380
507
|
attrs[:path] = row['path']
|
381
508
|
attrs[:expires_at] = Time.at(row['expiry'])
|
382
|
-
attrs[:accessed_at] =
|
383
|
-
attrs[:created_at] =
|
509
|
+
attrs[:accessed_at] = deserialize_usectime(row['lastAccessed'])
|
510
|
+
attrs[:created_at] = deserialize_usectime(row['creationTime'])
|
384
511
|
attrs[:secure] = row['isSecure'] != 0
|
385
512
|
attrs[:httponly] = row['isHttpOnly'] != 0
|
386
513
|
})
|
@@ -398,19 +525,6 @@ class HTTP::CookieJar
|
|
398
525
|
self
|
399
526
|
end
|
400
527
|
|
401
|
-
SQL[:count] = <<-'SQL'
|
402
|
-
SELECT COUNT(id) FROM moz_cookies
|
403
|
-
SQL
|
404
|
-
|
405
|
-
def count
|
406
|
-
@stmt[:count].execute.first[0]
|
407
|
-
end
|
408
|
-
protected :count
|
409
|
-
|
410
|
-
def empty?
|
411
|
-
@sjar.empty? && count == 0
|
412
|
-
end
|
413
|
-
|
414
528
|
SQL[:delete_expired] = <<-'SQL'
|
415
529
|
DELETE FROM moz_cookies WHERE expiry < :expiry
|
416
530
|
SQL
|
@@ -1,16 +1,27 @@
|
|
1
|
+
# :markup: markdown
|
1
2
|
require 'http/cookie_jar'
|
2
3
|
require 'psych' if !defined?(YAML) && RUBY_VERSION == "1.9.2"
|
3
4
|
require 'yaml'
|
4
5
|
|
5
|
-
# YAMLSaver saves and loads cookies in the YAML format.
|
6
|
+
# YAMLSaver saves and loads cookies in the YAML format. It can load a
|
7
|
+
# YAML file saved by Mechanize, but the saving format is not
|
8
|
+
# compatible with older versions of Mechanize (< 2.7).
|
6
9
|
class HTTP::CookieJar::YAMLSaver < HTTP::CookieJar::AbstractSaver
|
10
|
+
# :singleton-method: new
|
11
|
+
# :call-seq:
|
12
|
+
# new(**options)
|
13
|
+
#
|
14
|
+
# There is no option keyword supported at the moment.
|
15
|
+
|
16
|
+
##
|
17
|
+
|
7
18
|
def save(io, jar)
|
8
19
|
YAML.dump(@session ? jar.to_a : jar.reject(&:session?), io)
|
9
20
|
end
|
10
21
|
|
11
22
|
def load(io, jar)
|
12
23
|
begin
|
13
|
-
data =
|
24
|
+
data = load_yaml(io)
|
14
25
|
rescue ArgumentError => e
|
15
26
|
case e.message
|
16
27
|
when %r{\Aundefined class/module Mechanize::}
|
@@ -20,7 +31,7 @@ class HTTP::CookieJar::YAMLSaver < HTTP::CookieJar::AbstractSaver
|
|
20
31
|
yaml = io.read
|
21
32
|
# a gross hack
|
22
33
|
yaml.gsub!(%r{^( [^ ].*:) !ruby/object:Mechanize::Cookie$}, "\\1")
|
23
|
-
data =
|
34
|
+
data = load_yaml(yaml)
|
24
35
|
rescue Errno::ESPIPE
|
25
36
|
@logger.warn "could not rewind the stream for conversion" if @logger
|
26
37
|
rescue ArgumentError
|
@@ -42,7 +53,11 @@ class HTTP::CookieJar::YAMLSaver < HTTP::CookieJar::AbstractSaver
|
|
42
53
|
# YAML::Object of Syck
|
43
54
|
cookie_hash = cookie_hash.ivars
|
44
55
|
end
|
45
|
-
cookie = HTTP::Cookie.new(
|
56
|
+
cookie = HTTP::Cookie.new({}.tap { |hash|
|
57
|
+
cookie_hash.each_pair { |key, value|
|
58
|
+
hash[key.to_sym] = value
|
59
|
+
}
|
60
|
+
})
|
46
61
|
jar.add(cookie)
|
47
62
|
}
|
48
63
|
}
|
@@ -58,4 +73,14 @@ class HTTP::CookieJar::YAMLSaver < HTTP::CookieJar::AbstractSaver
|
|
58
73
|
def default_options
|
59
74
|
{}
|
60
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
|
61
86
|
end
|
data/test/helper.rb
CHANGED
@@ -3,6 +3,30 @@ require 'test-unit'
|
|
3
3
|
require 'uri'
|
4
4
|
require 'http/cookie'
|
5
5
|
|
6
|
+
module Test
|
7
|
+
module Unit
|
8
|
+
module Assertions
|
9
|
+
def assert_warn(pattern, message = nil, &block)
|
10
|
+
class << (output = "")
|
11
|
+
alias write <<
|
12
|
+
end
|
13
|
+
stderr, $stderr = $stderr, output
|
14
|
+
yield
|
15
|
+
assert_match(pattern, output, message)
|
16
|
+
ensure
|
17
|
+
$stderr = stderr
|
18
|
+
end
|
19
|
+
|
20
|
+
def assert_warning(pattern, message = nil, &block)
|
21
|
+
verbose, $VERBOSE = $VERBOSE, true
|
22
|
+
assert_warn(pattern, message, &block)
|
23
|
+
ensure
|
24
|
+
$VERBOSE = verbose
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
6
30
|
module Enumerable
|
7
31
|
def combine
|
8
32
|
masks = inject([[], 1]){|(ar, m), e| [ar << m, m << 1 ] }[0]
|
@@ -23,3 +47,9 @@ end
|
|
23
47
|
def test_file(filename)
|
24
48
|
File.expand_path(filename, File.dirname(__FILE__))
|
25
49
|
end
|
50
|
+
|
51
|
+
def sleep_until(time)
|
52
|
+
if (s = time - Time.now) > 0
|
53
|
+
sleep s
|
54
|
+
end
|
55
|
+
end
|
data/test/test_http_cookie.rb
CHANGED
@@ -2,13 +2,6 @@
|
|
2
2
|
require File.expand_path('helper', File.dirname(__FILE__))
|
3
3
|
|
4
4
|
class TestHTTPCookie < Test::Unit::TestCase
|
5
|
-
def silently
|
6
|
-
warn_level, $VERBOSE = $VERBOSE, false
|
7
|
-
yield
|
8
|
-
ensure
|
9
|
-
$VERBOSE = warn_level
|
10
|
-
end
|
11
|
-
|
12
5
|
def setup
|
13
6
|
httpdate = 'Sun, 27-Sep-2037 00:00:00 GMT'
|
14
7
|
|
@@ -46,12 +39,10 @@ class TestHTTPCookie < Test::Unit::TestCase
|
|
46
39
|
|
47
40
|
dates.each do |date|
|
48
41
|
cookie = "PREF=1; expires=#{date}"
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
}.size
|
54
|
-
end
|
42
|
+
assert_equal 1, HTTP::Cookie.parse(cookie, url) { |c|
|
43
|
+
assert c.expires, "Tried parsing: #{date}"
|
44
|
+
assert_send [c.expires, :<, yesterday]
|
45
|
+
}.size
|
55
46
|
end
|
56
47
|
|
57
48
|
[
|
@@ -135,6 +126,22 @@ class TestHTTPCookie < Test::Unit::TestCase
|
|
135
126
|
assert_equal 0, HTTP::Cookie.parse(cookie, url).size
|
136
127
|
end
|
137
128
|
|
129
|
+
def test_parse_bad_name
|
130
|
+
cookie = "a\001b=c"
|
131
|
+
url = URI.parse('http://www.example.com/')
|
132
|
+
assert_nothing_raised {
|
133
|
+
assert_equal 0, HTTP::Cookie.parse(cookie, url).size
|
134
|
+
}
|
135
|
+
end
|
136
|
+
|
137
|
+
def test_parse_bad_value
|
138
|
+
cookie = "a=b\001c"
|
139
|
+
url = URI.parse('http://www.example.com/')
|
140
|
+
assert_nothing_raised {
|
141
|
+
assert_equal 0, HTTP::Cookie.parse(cookie, url).size
|
142
|
+
}
|
143
|
+
end
|
144
|
+
|
138
145
|
def test_parse_weird_cookie
|
139
146
|
cookie = 'n/a, ASPSESSIONIDCSRRQDQR=FBLDGHPBNDJCPCGNCPAENELB; path=/'
|
140
147
|
url = URI.parse('http://www.searchinnovation.com/')
|
@@ -177,14 +184,12 @@ class TestHTTPCookie < Test::Unit::TestCase
|
|
177
184
|
"20/06/95 21:07",
|
178
185
|
]
|
179
186
|
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
assert_equal
|
184
|
-
|
185
|
-
|
186
|
-
end
|
187
|
-
end
|
187
|
+
dates.each { |date|
|
188
|
+
cookie = "PREF=1; expires=#{date}"
|
189
|
+
assert_equal 1, HTTP::Cookie.parse(cookie, url) { |c|
|
190
|
+
assert_equal(true, c.expires.nil?)
|
191
|
+
}.size
|
192
|
+
}
|
188
193
|
end
|
189
194
|
|
190
195
|
def test_parse_domain_dot
|
@@ -436,17 +441,28 @@ class TestHTTPCookie < Test::Unit::TestCase
|
|
436
441
|
['Bar', 'value 2'],
|
437
442
|
['Baz', 'value3'],
|
438
443
|
['Bar', 'value"4'],
|
444
|
+
['Quux', 'x, value=5'],
|
439
445
|
]
|
440
446
|
|
441
447
|
cookie_value = HTTP::Cookie.cookie_value(pairs.map { |name, value|
|
442
448
|
HTTP::Cookie.new(:name => name, :value => value)
|
443
449
|
})
|
444
450
|
|
445
|
-
assert_equal 'Foo=value1; Bar="value 2"; Baz=value3; Bar="value\\"4"', cookie_value
|
451
|
+
assert_equal 'Foo=value1; Bar="value 2"; Baz=value3; Bar="value\\"4"; Quux="x, value=5"', cookie_value
|
446
452
|
|
447
453
|
hash = HTTP::Cookie.cookie_value_to_hash(cookie_value)
|
448
454
|
|
449
|
-
assert_equal
|
455
|
+
assert_equal pairs.map(&:first).uniq.size, hash.size
|
456
|
+
|
457
|
+
hash.each_pair { |name, value|
|
458
|
+
_, pvalue = pairs.assoc(name)
|
459
|
+
assert_equal pvalue, value
|
460
|
+
}
|
461
|
+
|
462
|
+
# Do not treat comma in a Cookie header value as separator; see CVE-2016-7401
|
463
|
+
hash = HTTP::Cookie.cookie_value_to_hash('Quux=x, value=5; Foo=value1; Bar="value 2"; Baz=value3; Bar="value\\"4"')
|
464
|
+
|
465
|
+
assert_equal pairs.map(&:first).uniq.size, hash.size
|
450
466
|
|
451
467
|
hash.each_pair { |name, value|
|
452
468
|
_, pvalue = pairs.assoc(name)
|
@@ -537,6 +553,30 @@ class TestHTTPCookie < Test::Unit::TestCase
|
|
537
553
|
cookie.acceptable?
|
538
554
|
}
|
539
555
|
|
556
|
+
# various keywords
|
557
|
+
[
|
558
|
+
["Expires", /use downcased symbol/],
|
559
|
+
].each { |key, pattern|
|
560
|
+
assert_warning(pattern, "warn of key: #{key.inspect}") {
|
561
|
+
cookie = HTTP::Cookie.new(:value => 'value', :name => 'key', key => expires.dup)
|
562
|
+
assert_equal 'key', cookie.name
|
563
|
+
assert_equal 'value', cookie.value
|
564
|
+
assert_equal expires, cookie.expires, "key: #{key.inspect}"
|
565
|
+
}
|
566
|
+
}
|
567
|
+
[
|
568
|
+
[:Expires, /unknown attribute name/],
|
569
|
+
[:expires?, /unknown attribute name/],
|
570
|
+
[[:expires], /invalid keyword/],
|
571
|
+
].each { |key, pattern|
|
572
|
+
assert_warning(pattern, "warn of key: #{key.inspect}") {
|
573
|
+
cookie = HTTP::Cookie.new(:value => 'value', :name => 'key', key => expires.dup)
|
574
|
+
assert_equal 'key', cookie.name
|
575
|
+
assert_equal 'value', cookie.value
|
576
|
+
assert_equal nil, cookie.expires, "key: #{key.inspect}"
|
577
|
+
}
|
578
|
+
}
|
579
|
+
|
540
580
|
cookie = HTTP::Cookie.new(:value => 'value', :name => 'key', :expires => expires.dup)
|
541
581
|
assert_equal 'key', cookie.name
|
542
582
|
assert_equal 'value', cookie.value
|
@@ -679,19 +719,32 @@ class TestHTTPCookie < Test::Unit::TestCase
|
|
679
719
|
|
680
720
|
def test_max_age=
|
681
721
|
cookie = HTTP::Cookie.new(cookie_values)
|
722
|
+
expires = cookie.expires
|
682
723
|
|
683
724
|
assert_raises(ArgumentError) {
|
684
725
|
cookie.max_age = "+1"
|
685
726
|
}
|
727
|
+
# make sure #expires is not destroyed
|
728
|
+
assert_equal expires, cookie.expires
|
729
|
+
|
686
730
|
assert_raises(ArgumentError) {
|
687
731
|
cookie.max_age = "1.5"
|
688
732
|
}
|
733
|
+
# make sure #expires is not destroyed
|
734
|
+
assert_equal expires, cookie.expires
|
735
|
+
|
689
736
|
assert_raises(ArgumentError) {
|
690
737
|
cookie.max_age = "1 day"
|
691
738
|
}
|
739
|
+
# make sure #expires is not destroyed
|
740
|
+
assert_equal expires, cookie.expires
|
741
|
+
|
692
742
|
assert_raises(TypeError) {
|
693
743
|
cookie.max_age = [1]
|
694
744
|
}
|
745
|
+
# make sure #expires is not destroyed
|
746
|
+
assert_equal expires, cookie.expires
|
747
|
+
|
695
748
|
cookie.max_age = "12"
|
696
749
|
assert_equal 12, cookie.max_age
|
697
750
|
|