http-cookie 1.0.0.pre11 → 1.0.0.pre12
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 +4 -4
- data/lib/http/cookie.rb +12 -12
- data/lib/http/cookie/version.rb +1 -1
- data/lib/http/cookie_jar.rb +27 -1
- data/lib/http/cookie_jar/abstract_saver.rb +3 -3
- data/lib/http/cookie_jar/abstract_store.rb +23 -27
- data/lib/http/cookie_jar/mozilla_store.rb +154 -100
- data/lib/http/cookie_jar/yaml_saver.rb +4 -0
- data/test/helper.rb +4 -0
- data/test/mechanize.yml +101 -0
- data/test/test_http_cookie.rb +10 -11
- data/test/test_http_cookie_jar.rb +131 -24
- metadata +3 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2a70ec83e62018ae7621d1eb7ba75f08eea1d696
|
4
|
+
data.tar.gz: 9ed2b81801d89bb7adf3f6d97b087421406f4acf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f1ba260a8757b9076df6645368f761005cc665ef1c4ae357f102982132ed66253ae7cb49d163430bd3070225524c0cd4a988b2abbc4252e3e68e8376eea68542
|
7
|
+
data.tar.gz: bca8c545043e5b4975e32350dcf37f1519a183e3d207bb2692313863104884750ef656ed568106b69beab35e53b0536c36b677846255b1d477af95d022c74bfe
|
data/lib/http/cookie.rb
CHANGED
@@ -344,8 +344,8 @@ class HTTP::Cookie
|
|
344
344
|
|
345
345
|
# See #name.
|
346
346
|
def name=(name)
|
347
|
-
name = String.try_convert(name) or
|
348
|
-
raise TypeError, "#{name.class} is not a String"
|
347
|
+
name = (String.try_convert(name) or
|
348
|
+
raise TypeError, "#{name.class} is not a String")
|
349
349
|
if name.empty?
|
350
350
|
raise ArgumentError, "cookie name cannot be empty"
|
351
351
|
elsif name.match(/[\x00-\x20\x7F,;\\"=]/)
|
@@ -365,8 +365,8 @@ class HTTP::Cookie
|
|
365
365
|
self.expires = UNIX_EPOCH
|
366
366
|
return @value = ''
|
367
367
|
end
|
368
|
-
value = String.try_convert(value) or
|
369
|
-
raise TypeError, "#{value.class} is not a String"
|
368
|
+
value = (String.try_convert(value) or
|
369
|
+
raise TypeError, "#{value.class} is not a String")
|
370
370
|
if value.match(/[\x00-\x1F\x7F]/)
|
371
371
|
raise ArgumentError, "invalid cookie value"
|
372
372
|
end
|
@@ -393,8 +393,8 @@ class HTTP::Cookie
|
|
393
393
|
when DomainName
|
394
394
|
@domain_name = domain
|
395
395
|
else
|
396
|
-
domain = String.try_convert(domain) or
|
397
|
-
raise TypeError, "#{domain.class} is not a String"
|
396
|
+
domain = (String.try_convert(domain) or
|
397
|
+
raise TypeError, "#{domain.class} is not a String")
|
398
398
|
if domain.start_with?('.')
|
399
399
|
for_domain = true
|
400
400
|
domain = domain[1..-1]
|
@@ -438,8 +438,8 @@ class HTTP::Cookie
|
|
438
438
|
|
439
439
|
# See #path.
|
440
440
|
def path=(path)
|
441
|
-
path = String.try_convert(path) or
|
442
|
-
raise TypeError, "#{path.class} is not a String"
|
441
|
+
path = (String.try_convert(path) or
|
442
|
+
raise TypeError, "#{path.class} is not a String")
|
443
443
|
@path = path.start_with?('/') ? path : '/'
|
444
444
|
end
|
445
445
|
|
@@ -564,9 +564,9 @@ class HTTP::Cookie
|
|
564
564
|
def acceptable?
|
565
565
|
case
|
566
566
|
when @domain.nil?
|
567
|
-
raise
|
567
|
+
raise "domain is missing"
|
568
568
|
when @path.nil?
|
569
|
-
raise
|
569
|
+
raise "path is missing"
|
570
570
|
when @origin.nil?
|
571
571
|
true
|
572
572
|
else
|
@@ -574,8 +574,8 @@ class HTTP::Cookie
|
|
574
574
|
end
|
575
575
|
end
|
576
576
|
|
577
|
-
# Tests if it is OK to send this cookie to a given `uri`. A
|
578
|
-
#
|
577
|
+
# Tests if it is OK to send this cookie to a given `uri`. A
|
578
|
+
# RuntimeError is raised if the cookie's domain is unknown.
|
579
579
|
def valid_for_uri?(uri)
|
580
580
|
if @domain.nil?
|
581
581
|
raise "cannot tell if this cookie is valid because the domain is unknown"
|
data/lib/http/cookie/version.rb
CHANGED
data/lib/http/cookie_jar.rb
CHANGED
@@ -9,6 +9,27 @@ class HTTP::CookieJar
|
|
9
9
|
require 'http/cookie_jar/abstract_store'
|
10
10
|
require 'http/cookie_jar/abstract_saver'
|
11
11
|
|
12
|
+
class << self
|
13
|
+
def const_missing(name)
|
14
|
+
case name.to_s
|
15
|
+
when /\A([A-Za-z]+)Store\z/
|
16
|
+
file = 'http/cookie_jar/%s_store' % $1.downcase
|
17
|
+
when /\A([A-Za-z]+)Saver\z/
|
18
|
+
file = 'http/cookie_jar/%s_saver' % $1.downcase
|
19
|
+
end
|
20
|
+
begin
|
21
|
+
require file
|
22
|
+
rescue LoadError => e
|
23
|
+
raise NameError, 'can\'t resolve constant %s; failed to load %s' % [name, file]
|
24
|
+
end
|
25
|
+
if const_defined?(name)
|
26
|
+
const_get(name)
|
27
|
+
else
|
28
|
+
raise NameError, 'can\'t resolve constant %s after loading %s' % [name, file]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
12
33
|
attr_reader :store
|
13
34
|
|
14
35
|
# Generates a new cookie jar.
|
@@ -69,7 +90,12 @@ class HTTP::CookieJar
|
|
69
90
|
# jar.origin = origin
|
70
91
|
# jar.add(cookie) # acceptance check is performed
|
71
92
|
def add(cookie)
|
72
|
-
@store.add(cookie) if
|
93
|
+
@store.add(cookie) if
|
94
|
+
begin
|
95
|
+
cookie.acceptable?
|
96
|
+
rescue RuntimeError => e
|
97
|
+
raise ArgumentError, e.message
|
98
|
+
end
|
73
99
|
self
|
74
100
|
end
|
75
101
|
alias << add
|
@@ -26,7 +26,7 @@ class HTTP::CookieJar::AbstractSaver
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def default_options
|
29
|
-
{}
|
29
|
+
# {}
|
30
30
|
end
|
31
31
|
private :default_options
|
32
32
|
|
@@ -42,10 +42,10 @@ class HTTP::CookieJar::AbstractSaver
|
|
42
42
|
end
|
43
43
|
|
44
44
|
def save(io, jar)
|
45
|
-
|
45
|
+
# self
|
46
46
|
end
|
47
47
|
|
48
48
|
def load(io, jar)
|
49
|
-
|
49
|
+
# self
|
50
50
|
end
|
51
51
|
end
|
@@ -30,7 +30,7 @@ class HTTP::CookieJar::AbstractStore
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def default_options
|
33
|
-
{}
|
33
|
+
# {}
|
34
34
|
end
|
35
35
|
private :default_options
|
36
36
|
|
@@ -46,18 +46,15 @@ class HTTP::CookieJar::AbstractStore
|
|
46
46
|
end
|
47
47
|
|
48
48
|
def initialize_copy(other)
|
49
|
-
|
50
|
-
self
|
49
|
+
# self
|
51
50
|
end
|
52
51
|
|
53
52
|
def add(cookie)
|
54
|
-
|
55
|
-
self
|
53
|
+
# self
|
56
54
|
end
|
57
55
|
|
58
56
|
def delete(cookie)
|
59
|
-
|
60
|
-
self
|
57
|
+
# self
|
61
58
|
end
|
62
59
|
|
63
60
|
# Iterates over all cookies that are not expired.
|
@@ -70,35 +67,34 @@ class HTTP::CookieJar::AbstractStore
|
|
70
67
|
# If (and only if) the +uri+ option is given, last access time of
|
71
68
|
# each cookie is updated to the current time.
|
72
69
|
def each(uri = nil, &block)
|
73
|
-
if uri
|
74
|
-
|
75
|
-
else
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
end
|
80
|
-
self
|
70
|
+
# if uri
|
71
|
+
# ...
|
72
|
+
# else
|
73
|
+
# synchronize {
|
74
|
+
# ...
|
75
|
+
# }
|
76
|
+
# end
|
77
|
+
# self
|
81
78
|
end
|
82
79
|
include Enumerable
|
83
80
|
|
84
81
|
def empty?
|
85
|
-
|
82
|
+
# true or false
|
86
83
|
end
|
87
84
|
|
88
85
|
def clear
|
89
|
-
|
90
|
-
self
|
86
|
+
# self
|
91
87
|
end
|
92
88
|
|
93
89
|
def cleanup(session = false)
|
94
|
-
if session
|
95
|
-
|
96
|
-
else
|
97
|
-
|
98
|
-
end.each { |cookie|
|
99
|
-
|
100
|
-
}
|
101
|
-
# subclasses can optionally remove over-the-limit cookies.
|
102
|
-
self
|
90
|
+
# if session
|
91
|
+
# select { |cookie| cookie.session? || cookie.expired? }
|
92
|
+
# else
|
93
|
+
# select(&:expired?)
|
94
|
+
# end.each { |cookie|
|
95
|
+
# delete(cookie)
|
96
|
+
# }
|
97
|
+
# # subclasses can optionally remove over-the-limit cookies.
|
98
|
+
# self
|
103
99
|
end
|
104
100
|
end
|
@@ -9,6 +9,7 @@ class HTTP::CookieJar
|
|
9
9
|
# Session cookies are stored separately on memory and will not be
|
10
10
|
# stored persistently in the SQLite3 database.
|
11
11
|
class MozillaStore < AbstractStore
|
12
|
+
# :stopdoc:
|
12
13
|
SCHEMA_VERSION = 5
|
13
14
|
|
14
15
|
def default_options
|
@@ -32,6 +33,41 @@ class HTTP::CookieJar
|
|
32
33
|
appId inBrowserElement
|
33
34
|
]
|
34
35
|
|
36
|
+
SQL = {}
|
37
|
+
|
38
|
+
Callable = proc { |obj, meth, *args|
|
39
|
+
proc {
|
40
|
+
obj.__send__(meth, *args)
|
41
|
+
}
|
42
|
+
}
|
43
|
+
|
44
|
+
class Database < SQLite3::Database
|
45
|
+
def initialize(file, options = {})
|
46
|
+
@stmts = []
|
47
|
+
options = {
|
48
|
+
:results_as_hash => true,
|
49
|
+
}.update(options)
|
50
|
+
super
|
51
|
+
end
|
52
|
+
|
53
|
+
def prepare(sql)
|
54
|
+
case st = super
|
55
|
+
when SQLite3::Statement
|
56
|
+
@stmts << st
|
57
|
+
end
|
58
|
+
st
|
59
|
+
end
|
60
|
+
|
61
|
+
def close
|
62
|
+
return self if closed?
|
63
|
+
@stmts.reject! { |st|
|
64
|
+
st.closed? || st.close
|
65
|
+
}
|
66
|
+
super
|
67
|
+
end
|
68
|
+
end
|
69
|
+
# :startdoc:
|
70
|
+
|
35
71
|
# Generates a Mozilla cookie store. If the file does not exist,
|
36
72
|
# it is created. If it does and its schema is old, it is
|
37
73
|
# automatically upgraded with a new schema keeping the existing
|
@@ -58,22 +94,32 @@ class HTTP::CookieJar
|
|
58
94
|
|
59
95
|
@filename = options[:filename] or raise ArgumentError, ':filename option is missing'
|
60
96
|
|
61
|
-
@sjar = HashStore.new
|
62
|
-
|
63
|
-
@db
|
97
|
+
@sjar = HTTP::CookieJar::HashStore.new
|
98
|
+
|
99
|
+
@db = Database.new(@filename)
|
100
|
+
|
101
|
+
@stmt = Hash.new { |st, key|
|
102
|
+
st[key] = @db.prepare(SQL[key])
|
103
|
+
}
|
104
|
+
|
105
|
+
ObjectSpace.define_finalizer(self, Callable[@db, :close])
|
64
106
|
|
65
107
|
upgrade_database
|
66
108
|
|
67
109
|
@gc_index = 0
|
68
110
|
end
|
69
111
|
|
112
|
+
def initialize_copy(other)
|
113
|
+
raise TypeError, 'can\'t clone %s' % self.class
|
114
|
+
end
|
115
|
+
|
70
116
|
# The file name of the SQLite3 database given in initialization.
|
71
117
|
attr_reader :filename
|
72
118
|
|
73
119
|
# Closes the SQLite3 database. After closing, any operation may
|
74
120
|
# raise an error.
|
75
121
|
def close
|
76
|
-
@db.close
|
122
|
+
@db.closed? || @db.close
|
77
123
|
self
|
78
124
|
end
|
79
125
|
|
@@ -126,6 +172,13 @@ class HTTP::CookieJar
|
|
126
172
|
SQL
|
127
173
|
end
|
128
174
|
|
175
|
+
def db_prepare(sql)
|
176
|
+
st = @db.prepare(sql)
|
177
|
+
yield st
|
178
|
+
ensure
|
179
|
+
st.close if st
|
180
|
+
end
|
181
|
+
|
129
182
|
def upgrade_database
|
130
183
|
loop {
|
131
184
|
case schema_version
|
@@ -138,28 +191,28 @@ class HTTP::CookieJar
|
|
138
191
|
when 2
|
139
192
|
@db.execute("ALTER TABLE moz_cookies ADD baseDomain TEXT")
|
140
193
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
194
|
+
db_prepare("UPDATE moz_cookies SET baseDomain = :baseDomain WHERE id = :id") { |st_update|
|
195
|
+
@db.execute("SELECT id, host FROM moz_cookies") { |row|
|
196
|
+
domain_name = DomainName.new(row['host'][/\A\.?(.*)/, 1])
|
197
|
+
domain = domain_name.domain || domain_name.hostname
|
198
|
+
st_update.execute(:baseDomain => domain, :id => row['id'])
|
199
|
+
}
|
147
200
|
}
|
148
201
|
|
149
202
|
@db.execute("CREATE INDEX moz_basedomain ON moz_cookies (baseDomain)")
|
150
203
|
self.schema_version += 1
|
151
204
|
when 3
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
205
|
+
db_prepare("DELETE FROM moz_cookies WHERE id = :id") { |st_delete|
|
206
|
+
prev_row = nil
|
207
|
+
@db.execute(<<-'SQL') { |row|
|
208
|
+
SELECT id, name, host, path FROM moz_cookies
|
209
|
+
ORDER BY name ASC, host ASC, path ASC, expiry ASC
|
210
|
+
SQL
|
211
|
+
if %w[name host path].all? { |col| prev_row and row[col] == prev_row[col] }
|
212
|
+
st_delete.execute(prev_row['id'])
|
213
|
+
end
|
214
|
+
prev_row = row
|
215
|
+
}
|
163
216
|
}
|
164
217
|
|
165
218
|
@db.execute("ALTER TABLE moz_cookies ADD creationTime INTEGER")
|
@@ -192,14 +245,15 @@ class HTTP::CookieJar
|
|
192
245
|
end
|
193
246
|
end
|
194
247
|
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
248
|
+
SQL[:add] = <<-'SQL' % [
|
249
|
+
INSERT OR REPLACE INTO moz_cookies (%s) VALUES (%s)
|
250
|
+
SQL
|
251
|
+
ALL_COLUMNS.join(', '),
|
252
|
+
ALL_COLUMNS.map { |col| ":#{col}" }.join(', ')
|
253
|
+
]
|
201
254
|
|
202
|
-
|
255
|
+
def db_add(cookie)
|
256
|
+
@stmt[:add].execute({
|
203
257
|
:baseDomain => cookie.domain_name.domain || cookie.domain,
|
204
258
|
:appId => @app_id,
|
205
259
|
:inBrowserElement => @in_browser_element ? 1 : 0,
|
@@ -217,18 +271,17 @@ class HTTP::CookieJar
|
|
217
271
|
self
|
218
272
|
end
|
219
273
|
|
274
|
+
SQL[:delete] = <<-'SQL'
|
275
|
+
DELETE FROM moz_cookies
|
276
|
+
WHERE appId = :appId AND
|
277
|
+
inBrowserElement = :inBrowserElement AND
|
278
|
+
name = :name AND
|
279
|
+
host = :host AND
|
280
|
+
path = :path
|
281
|
+
SQL
|
282
|
+
|
220
283
|
def db_delete(cookie)
|
221
|
-
@
|
222
|
-
@db.prepare(<<-'SQL')
|
223
|
-
DELETE FROM moz_cookies
|
224
|
-
WHERE appId = :appId AND
|
225
|
-
inBrowserElement = :inBrowserElement AND
|
226
|
-
name = :name AND
|
227
|
-
host = :host AND
|
228
|
-
path = :path
|
229
|
-
SQL
|
230
|
-
|
231
|
-
@st_delete.execute({
|
284
|
+
@stmt[:delete].execute({
|
232
285
|
:appId => @app_id,
|
233
286
|
:inBrowserElement => @in_browser_element ? 1 : 0,
|
234
287
|
:name => cookie.name,
|
@@ -255,25 +308,34 @@ class HTTP::CookieJar
|
|
255
308
|
db_delete(cookie)
|
256
309
|
end
|
257
310
|
|
311
|
+
SQL[:cookies_for_domain] = <<-'SQL'
|
312
|
+
SELECT * FROM moz_cookies
|
313
|
+
WHERE baseDomain = :baseDomain AND
|
314
|
+
appId = :appId AND
|
315
|
+
inBrowserElement = :inBrowserElement AND
|
316
|
+
expiry >= :expiry
|
317
|
+
SQL
|
318
|
+
|
319
|
+
SQL[:update_lastaccessed] = <<-'SQL'
|
320
|
+
UPDATE moz_cookies
|
321
|
+
SET lastAccessed = :lastAccessed
|
322
|
+
WHERE id = :id
|
323
|
+
SQL
|
324
|
+
|
325
|
+
SQL[:all_cookies] = <<-'SQL'
|
326
|
+
SELECT * FROM moz_cookies
|
327
|
+
WHERE appId = :appId AND
|
328
|
+
inBrowserElement = :inBrowserElement AND
|
329
|
+
expiry >= :expiry
|
330
|
+
SQL
|
331
|
+
|
258
332
|
def each(uri = nil, &block)
|
259
333
|
now = Time.now
|
260
334
|
if uri
|
261
|
-
@st_cookies_for_domain ||=
|
262
|
-
@db.prepare(<<-'SQL')
|
263
|
-
SELECT * FROM moz_cookies
|
264
|
-
WHERE baseDomain = :baseDomain AND
|
265
|
-
appId = :appId AND
|
266
|
-
inBrowserElement = :inBrowserElement AND
|
267
|
-
expiry >= :expiry
|
268
|
-
SQL
|
269
|
-
|
270
|
-
@st_update_lastaccessed ||=
|
271
|
-
@db.prepare("UPDATE moz_cookies SET lastAccessed = :lastAccessed where id = :id")
|
272
|
-
|
273
335
|
thost = DomainName.new(uri.host)
|
274
336
|
tpath = uri.path
|
275
337
|
|
276
|
-
@
|
338
|
+
@stmt[:cookies_for_domain].execute({
|
277
339
|
:baseDomain => thost.domain || thost.hostname,
|
278
340
|
:appId => @app_id,
|
279
341
|
:inBrowserElement => @in_browser_element ? 1 : 0,
|
@@ -289,15 +351,15 @@ class HTTP::CookieJar
|
|
289
351
|
attrs[:domain] = row['host']
|
290
352
|
attrs[:path] = row['path']
|
291
353
|
attrs[:expires_at] = Time.at(row['expiry'])
|
292
|
-
attrs[:accessed_at] = Time.at(row['lastAccessed'])
|
293
|
-
attrs[:created_at] = Time.at(row['creationTime'])
|
354
|
+
attrs[:accessed_at] = Time.at(row['lastAccessed'] || 0)
|
355
|
+
attrs[:created_at] = Time.at(row['creationTime'] || 0)
|
294
356
|
attrs[:secure] = secure
|
295
357
|
attrs[:httponly] = row['isHttpOnly'] != 0
|
296
358
|
})
|
297
359
|
|
298
360
|
if cookie.valid_for_uri?(uri)
|
299
361
|
cookie.accessed_at = now
|
300
|
-
@
|
362
|
+
@stmt[:update_lastaccessed].execute({
|
301
363
|
'lastAccessed' => now.to_i,
|
302
364
|
'id' => row['id'],
|
303
365
|
})
|
@@ -306,15 +368,7 @@ class HTTP::CookieJar
|
|
306
368
|
}
|
307
369
|
@sjar.each(uri, &block)
|
308
370
|
else
|
309
|
-
@
|
310
|
-
@db.prepare(<<-'SQL')
|
311
|
-
SELECT * FROM moz_cookies
|
312
|
-
WHERE appId = :appId AND
|
313
|
-
inBrowserElement = :inBrowserElement AND
|
314
|
-
expiry >= :expiry
|
315
|
-
SQL
|
316
|
-
|
317
|
-
@st_all_cookies.execute({
|
371
|
+
@stmt[:all_cookies].execute({
|
318
372
|
:appId => @app_id,
|
319
373
|
:inBrowserElement => @in_browser_element ? 1 : 0,
|
320
374
|
:expiry => now.to_i,
|
@@ -325,8 +379,8 @@ class HTTP::CookieJar
|
|
325
379
|
attrs[:domain] = row['host']
|
326
380
|
attrs[:path] = row['path']
|
327
381
|
attrs[:expires_at] = Time.at(row['expiry'])
|
328
|
-
attrs[:accessed_at] = Time.at(row['lastAccessed'])
|
329
|
-
attrs[:created_at] = Time.at(row['creationTime'])
|
382
|
+
attrs[:accessed_at] = Time.at(row['lastAccessed'] || 0)
|
383
|
+
attrs[:created_at] = Time.at(row['creationTime'] || 0)
|
330
384
|
attrs[:secure] = row['isSecure'] != 0
|
331
385
|
attrs[:httponly] = row['isHttpOnly'] != 0
|
332
386
|
})
|
@@ -344,11 +398,12 @@ class HTTP::CookieJar
|
|
344
398
|
self
|
345
399
|
end
|
346
400
|
|
347
|
-
|
348
|
-
|
349
|
-
|
401
|
+
SQL[:count] = <<-'SQL'
|
402
|
+
SELECT COUNT(id) FROM moz_cookies
|
403
|
+
SQL
|
350
404
|
|
351
|
-
|
405
|
+
def count
|
406
|
+
@stmt[:count].execute.first[0]
|
352
407
|
end
|
353
408
|
protected :count
|
354
409
|
|
@@ -356,44 +411,43 @@ class HTTP::CookieJar
|
|
356
411
|
@sjar.empty? && count == 0
|
357
412
|
end
|
358
413
|
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
)
|
384
|
-
SQL
|
414
|
+
SQL[:delete_expired] = <<-'SQL'
|
415
|
+
DELETE FROM moz_cookies WHERE expiry < :expiry
|
416
|
+
SQL
|
417
|
+
|
418
|
+
SQL[:overusing_domains] = <<-'SQL'
|
419
|
+
SELECT LTRIM(host, '.') domain, COUNT(*) count
|
420
|
+
FROM moz_cookies
|
421
|
+
GROUP BY domain
|
422
|
+
HAVING count > :count
|
423
|
+
SQL
|
424
|
+
|
425
|
+
SQL[:delete_per_domain_overuse] = <<-'SQL'
|
426
|
+
DELETE FROM moz_cookies WHERE id IN (
|
427
|
+
SELECT id FROM moz_cookies
|
428
|
+
WHERE LTRIM(host, '.') = :domain
|
429
|
+
ORDER BY creationtime
|
430
|
+
LIMIT :limit)
|
431
|
+
SQL
|
432
|
+
|
433
|
+
SQL[:delete_total_overuse] = <<-'SQL'
|
434
|
+
DELETE FROM moz_cookies WHERE id IN (
|
435
|
+
SELECT id FROM moz_cookies ORDER BY creationTime ASC LIMIT :limit
|
436
|
+
)
|
437
|
+
SQL
|
385
438
|
|
439
|
+
def cleanup(session = false)
|
386
440
|
synchronize {
|
387
441
|
break if @gc_index == 0
|
388
442
|
|
389
|
-
@
|
443
|
+
@stmt[:delete_expired].execute({ 'expiry' => Time.now.to_i })
|
390
444
|
|
391
|
-
@
|
445
|
+
@stmt[:overusing_domains].execute({
|
392
446
|
'count' => HTTP::Cookie::MAX_COOKIES_PER_DOMAIN
|
393
447
|
}).each { |row|
|
394
448
|
domain, count = row['domain'], row['count']
|
395
449
|
|
396
|
-
@
|
450
|
+
@stmt[:delete_per_domain_overuse].execute({
|
397
451
|
'domain' => domain,
|
398
452
|
'limit' => count - HTTP::Cookie::MAX_COOKIES_PER_DOMAIN,
|
399
453
|
})
|
@@ -402,7 +456,7 @@ class HTTP::CookieJar
|
|
402
456
|
overrun = count - HTTP::Cookie::MAX_COOKIES_TOTAL
|
403
457
|
|
404
458
|
if overrun > 0
|
405
|
-
@
|
459
|
+
@stmt[:delete_total_overuse].execute({ 'limit' => overrun })
|
406
460
|
end
|
407
461
|
|
408
462
|
@gc_index = 0
|
@@ -38,6 +38,10 @@ class HTTP::CookieJar::YAMLSaver < HTTP::CookieJar::AbstractSaver
|
|
38
38
|
data.each { |domain, paths|
|
39
39
|
paths.each { |path, names|
|
40
40
|
names.each { |cookie_name, cookie_hash|
|
41
|
+
if cookie_hash.respond_to?(:ivars)
|
42
|
+
# YAML::Object of Syck
|
43
|
+
cookie_hash = cookie_hash.ivars
|
44
|
+
end
|
41
45
|
cookie = HTTP::Cookie.new(cookie_hash)
|
42
46
|
jar.add(cookie)
|
43
47
|
}
|
data/test/helper.rb
CHANGED
data/test/mechanize.yml
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
---
|
2
|
+
google.com:
|
3
|
+
/:
|
4
|
+
PREF: !ruby/object:Mechanize::Cookie
|
5
|
+
version: 0
|
6
|
+
port:
|
7
|
+
discard:
|
8
|
+
comment_url:
|
9
|
+
expires: Tue, 24 Mar 2065 08:20:15 GMT
|
10
|
+
max_age:
|
11
|
+
comment:
|
12
|
+
secure: false
|
13
|
+
path: /
|
14
|
+
domain: google.com
|
15
|
+
accessed_at: 2013-03-24 17:20:15.822619000 +09:00
|
16
|
+
created_at: 2013-03-24 17:20:15.822619000 +09:00
|
17
|
+
name: PREF
|
18
|
+
value: ID=7571a59c059e09db:FF=0:TM=1364199615:LM=1364199615:S=BxUqnqPrchd2cVmC
|
19
|
+
for_domain: true
|
20
|
+
domain_name: !ruby/object:DomainName
|
21
|
+
ipaddr:
|
22
|
+
hostname: google.com
|
23
|
+
uri_host: google.com
|
24
|
+
tld: com
|
25
|
+
canonical_tld_p: true
|
26
|
+
domain: google.com
|
27
|
+
session: false
|
28
|
+
NID: !ruby/object:Mechanize::Cookie
|
29
|
+
version: 0
|
30
|
+
port:
|
31
|
+
discard:
|
32
|
+
comment_url:
|
33
|
+
expires: Sun, 23 Sep 2063 08:20:15 GMT
|
34
|
+
max_age:
|
35
|
+
comment:
|
36
|
+
secure: false
|
37
|
+
path: /
|
38
|
+
domain: google.com
|
39
|
+
accessed_at: 2013-03-24 17:20:15.828434000 +09:00
|
40
|
+
created_at: 2013-03-24 17:20:15.828434000 +09:00
|
41
|
+
name: NID
|
42
|
+
value: 67=Kn2osS6wOzILpl7sCM1QIDmGg2VESBiwCyt6zx4vOVSWKOYDlwGIpgIGrpD8FpkbS9eqizo3QWFa5YkOygnCF6vRIQpbvlTxWB2Hq1Oo-qXWy0317yCqQ-B25eJLfUcC
|
43
|
+
for_domain: true
|
44
|
+
domain_name: !ruby/object:DomainName
|
45
|
+
ipaddr:
|
46
|
+
hostname: google.com
|
47
|
+
uri_host: google.com
|
48
|
+
tld: com
|
49
|
+
canonical_tld_p: true
|
50
|
+
domain: google.com
|
51
|
+
session: false
|
52
|
+
google.co.jp:
|
53
|
+
/:
|
54
|
+
PREF: !ruby/object:Mechanize::Cookie
|
55
|
+
version: 0
|
56
|
+
port:
|
57
|
+
discard:
|
58
|
+
comment_url:
|
59
|
+
expires: Tue, 24 Mar 2065 08:20:16 GMT
|
60
|
+
max_age:
|
61
|
+
comment:
|
62
|
+
secure: false
|
63
|
+
path: /
|
64
|
+
domain: google.co.jp
|
65
|
+
accessed_at: 2013-03-24 17:20:17.136581000 +09:00
|
66
|
+
created_at: 2013-03-24 17:20:17.136581000 +09:00
|
67
|
+
name: PREF
|
68
|
+
value: ID=cb25dd1567d8b5c8:FF=0:TM=1364199616:LM=1364199616:S=c3PbhRq79Wo5T_vV
|
69
|
+
for_domain: true
|
70
|
+
domain_name: !ruby/object:DomainName
|
71
|
+
ipaddr:
|
72
|
+
hostname: google.co.jp
|
73
|
+
uri_host: google.co.jp
|
74
|
+
tld: jp
|
75
|
+
canonical_tld_p: true
|
76
|
+
domain: google.co.jp
|
77
|
+
session: false
|
78
|
+
NID: !ruby/object:Mechanize::Cookie
|
79
|
+
version: 0
|
80
|
+
port:
|
81
|
+
discard:
|
82
|
+
comment_url:
|
83
|
+
expires: Sun, 23 Sep 2063 08:20:16 GMT
|
84
|
+
max_age:
|
85
|
+
comment:
|
86
|
+
secure: false
|
87
|
+
path: /
|
88
|
+
domain: google.co.jp
|
89
|
+
accessed_at: 2013-03-24 17:20:17.139782000 +09:00
|
90
|
+
created_at: 2013-03-24 17:20:17.139782000 +09:00
|
91
|
+
name: NID
|
92
|
+
value: 67=GS7P-68zgm_KRA0e0dpN_XbYpmw9uBDe56qUeoCGiSRTahsM7dtOBCKfCoIFRKlzSuOiwJQdIZNpwv3DSXQNHXDKltucgfv2qkHlGeoj8-5VlowPXLLesz2VIpLOLw-a
|
93
|
+
for_domain: true
|
94
|
+
domain_name: !ruby/object:DomainName
|
95
|
+
ipaddr:
|
96
|
+
hostname: google.co.jp
|
97
|
+
uri_host: google.co.jp
|
98
|
+
tld: jp
|
99
|
+
canonical_tld_p: true
|
100
|
+
domain: google.co.jp
|
101
|
+
session: false
|
data/test/test_http_cookie.rb
CHANGED
@@ -3,11 +3,10 @@ require File.expand_path('helper', File.dirname(__FILE__))
|
|
3
3
|
|
4
4
|
class TestHTTPCookie < Test::Unit::TestCase
|
5
5
|
def silently
|
6
|
-
warn_level = $VERBOSE
|
7
|
-
|
8
|
-
|
6
|
+
warn_level, $VERBOSE = $VERBOSE, false
|
7
|
+
yield
|
8
|
+
ensure
|
9
9
|
$VERBOSE = warn_level
|
10
|
-
res
|
11
10
|
end
|
12
11
|
|
13
12
|
def setup
|
@@ -523,7 +522,7 @@ class TestHTTPCookie < Test::Unit::TestCase
|
|
523
522
|
assert_equal 'key', cookie.name
|
524
523
|
assert_equal 'value', cookie.value
|
525
524
|
assert_equal nil, cookie.expires
|
526
|
-
assert_raises(
|
525
|
+
assert_raises(RuntimeError) {
|
527
526
|
cookie.acceptable?
|
528
527
|
}
|
529
528
|
|
@@ -534,7 +533,7 @@ class TestHTTPCookie < Test::Unit::TestCase
|
|
534
533
|
assert_equal 'key', cookie.name
|
535
534
|
assert_equal 'value', cookie.value
|
536
535
|
assert_equal expires, cookie.expires
|
537
|
-
assert_raises(
|
536
|
+
assert_raises(RuntimeError) {
|
538
537
|
cookie.acceptable?
|
539
538
|
}
|
540
539
|
|
@@ -543,7 +542,7 @@ class TestHTTPCookie < Test::Unit::TestCase
|
|
543
542
|
assert_equal 'value', cookie.value
|
544
543
|
assert_equal expires, cookie.expires
|
545
544
|
assert_equal false, cookie.for_domain?
|
546
|
-
assert_raises(
|
545
|
+
assert_raises(RuntimeError) {
|
547
546
|
# domain and path are missing
|
548
547
|
cookie.acceptable?
|
549
548
|
}
|
@@ -553,7 +552,7 @@ class TestHTTPCookie < Test::Unit::TestCase
|
|
553
552
|
assert_equal 'value', cookie.value
|
554
553
|
assert_equal expires, cookie.expires
|
555
554
|
assert_equal true, cookie.for_domain?
|
556
|
-
assert_raises(
|
555
|
+
assert_raises(RuntimeError) {
|
557
556
|
# path is missing
|
558
557
|
cookie.acceptable?
|
559
558
|
}
|
@@ -563,7 +562,7 @@ class TestHTTPCookie < Test::Unit::TestCase
|
|
563
562
|
assert_equal 'value', cookie.value
|
564
563
|
assert_equal expires, cookie.expires
|
565
564
|
assert_equal false, cookie.for_domain?
|
566
|
-
assert_raises(
|
565
|
+
assert_raises(RuntimeError) {
|
567
566
|
# path is missing
|
568
567
|
cookie.acceptable?
|
569
568
|
}
|
@@ -574,7 +573,7 @@ class TestHTTPCookie < Test::Unit::TestCase
|
|
574
573
|
assert_equal expires, cookie.expires
|
575
574
|
assert_equal 'example.org', cookie.domain
|
576
575
|
assert_equal true, cookie.for_domain?
|
577
|
-
assert_raises(
|
576
|
+
assert_raises(RuntimeError) {
|
578
577
|
# path is missing
|
579
578
|
cookie.acceptable?
|
580
579
|
}
|
@@ -849,7 +848,7 @@ class TestHTTPCookie < Test::Unit::TestCase
|
|
849
848
|
cookie.domain = d
|
850
849
|
assert_equal nil, cookie.domain, "domain=#{d.inspect}"
|
851
850
|
assert_equal nil, cookie.domain_name, "domain=#{d.inspect}"
|
852
|
-
assert_raises(
|
851
|
+
assert_raises(RuntimeError) {
|
853
852
|
cookie.acceptable?
|
854
853
|
}
|
855
854
|
|
@@ -2,25 +2,7 @@ require File.expand_path('helper', File.dirname(__FILE__))
|
|
2
2
|
require 'tmpdir'
|
3
3
|
|
4
4
|
module TestHTTPCookieJar
|
5
|
-
|
6
|
-
def test_store
|
7
|
-
jar = HTTP::CookieJar.new(:store => :hash)
|
8
|
-
assert_instance_of HTTP::CookieJar::HashStore, jar.store
|
9
|
-
|
10
|
-
assert_raises(IndexError) {
|
11
|
-
jar = HTTP::CookieJar.new(:store => :nonexistent)
|
12
|
-
}
|
13
|
-
|
14
|
-
jar = HTTP::CookieJar.new(:store => HTTP::CookieJar::HashStore.new)
|
15
|
-
assert_instance_of HTTP::CookieJar::HashStore, jar.store
|
16
|
-
|
17
|
-
assert_raises(TypeError) {
|
18
|
-
jar = HTTP::CookieJar.new(:store => HTTP::CookieJar::HashStore)
|
19
|
-
}
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
module Tests
|
5
|
+
module CommonTests
|
24
6
|
def setup(options = nil, options2 = nil)
|
25
7
|
default_options = {
|
26
8
|
:store => :hash,
|
@@ -34,9 +16,9 @@ module TestHTTPCookieJar
|
|
34
16
|
@jar2 = HTTP::CookieJar.new(new_options2)
|
35
17
|
end
|
36
18
|
|
37
|
-
def hash_store?
|
38
|
-
|
39
|
-
end
|
19
|
+
#def hash_store?
|
20
|
+
# @store_type == :hash
|
21
|
+
#end
|
40
22
|
|
41
23
|
def mozilla_store?
|
42
24
|
@store_type == :mozilla
|
@@ -505,6 +487,32 @@ module TestHTTPCookieJar
|
|
505
487
|
assert_equal(5, @jar.cookies(url).length)
|
506
488
|
end
|
507
489
|
|
490
|
+
def test_load_yaml_mechanize
|
491
|
+
@jar.load(test_file('mechanize.yml'), :yaml)
|
492
|
+
|
493
|
+
assert_equal 4, @jar.to_a.size
|
494
|
+
|
495
|
+
com_nid, com_pref = @jar.cookies('http://www.google.com/')
|
496
|
+
|
497
|
+
assert_equal 'NID', com_nid.name
|
498
|
+
assert_equal 'Sun, 23 Sep 2063 08:20:15 GMT', com_nid.expires.httpdate
|
499
|
+
assert_equal 'google.com', com_nid.domain_name.hostname
|
500
|
+
|
501
|
+
assert_equal 'PREF', com_pref.name
|
502
|
+
assert_equal 'Tue, 24 Mar 2065 08:20:15 GMT', com_pref.expires.httpdate
|
503
|
+
assert_equal 'google.com', com_pref.domain_name.hostname
|
504
|
+
|
505
|
+
cojp_nid, cojp_pref = @jar.cookies('http://www.google.co.jp/')
|
506
|
+
|
507
|
+
assert_equal 'NID', cojp_nid.name
|
508
|
+
assert_equal 'Sun, 23 Sep 2063 08:20:16 GMT', cojp_nid.expires.httpdate
|
509
|
+
assert_equal 'google.co.jp', cojp_nid.domain_name.hostname
|
510
|
+
|
511
|
+
assert_equal 'PREF', cojp_pref.name
|
512
|
+
assert_equal 'Tue, 24 Mar 2065 08:20:16 GMT', cojp_pref.expires.httpdate
|
513
|
+
assert_equal 'google.co.jp', cojp_pref.domain_name.hostname
|
514
|
+
end
|
515
|
+
|
508
516
|
def test_expire_cookies
|
509
517
|
url = URI 'http://rubyforge.org/'
|
510
518
|
|
@@ -744,17 +752,116 @@ module TestHTTPCookieJar
|
|
744
752
|
end
|
745
753
|
|
746
754
|
class WithHashStore < Test::Unit::TestCase
|
747
|
-
include
|
755
|
+
include CommonTests
|
756
|
+
|
757
|
+
def test_new
|
758
|
+
jar = HTTP::CookieJar.new(:store => :hash)
|
759
|
+
assert_instance_of HTTP::CookieJar::HashStore, jar.store
|
760
|
+
|
761
|
+
assert_raises(IndexError) {
|
762
|
+
jar = HTTP::CookieJar.new(:store => :nonexistent)
|
763
|
+
}
|
764
|
+
|
765
|
+
jar = HTTP::CookieJar.new(:store => HTTP::CookieJar::HashStore.new)
|
766
|
+
assert_instance_of HTTP::CookieJar::HashStore, jar.store
|
767
|
+
|
768
|
+
assert_raises(TypeError) {
|
769
|
+
jar = HTTP::CookieJar.new(:store => HTTP::CookieJar::HashStore)
|
770
|
+
}
|
771
|
+
end
|
772
|
+
|
748
773
|
end
|
749
774
|
|
750
775
|
class WithMozillaStore < Test::Unit::TestCase
|
751
|
-
include
|
776
|
+
include CommonTests
|
752
777
|
|
753
778
|
def setup
|
754
779
|
super(
|
755
780
|
{ :store => :mozilla, :filename => ":memory:" },
|
756
781
|
{ :store => :mozilla, :filename => ":memory:" })
|
757
782
|
end
|
783
|
+
|
784
|
+
def add_and_delete(jar)
|
785
|
+
jar.parse("name=Akinori; Domain=rubyforge.org; Expires=Sun, 08 Aug 2076 19:00:00 GMT; Path=/",
|
786
|
+
'http://rubyforge.org/')
|
787
|
+
jar.parse("country=Japan; Domain=rubyforge.org; Expires=Sun, 08 Aug 2076 19:00:00 GMT; Path=/",
|
788
|
+
'http://rubyforge.org/')
|
789
|
+
jar.delete(HTTP::Cookie.new("name", :domain => 'rubyforge.org'))
|
790
|
+
end
|
791
|
+
|
792
|
+
def test_close
|
793
|
+
add_and_delete(@jar)
|
794
|
+
|
795
|
+
assert_not_send [@jar.store, :closed?]
|
796
|
+
@jar.store.close
|
797
|
+
assert_send [@jar.store, :closed?]
|
798
|
+
@jar.store.close # should do nothing
|
799
|
+
assert_send [@jar.store, :closed?]
|
800
|
+
end
|
801
|
+
|
802
|
+
def test_finalizer
|
803
|
+
db = nil
|
804
|
+
loop {
|
805
|
+
jar = HTTP::CookieJar.new(:store => :mozilla, :filename => ':memory:')
|
806
|
+
add_and_delete(jar)
|
807
|
+
db = jar.store.instance_variable_get(:@db)
|
808
|
+
class << db
|
809
|
+
alias close_orig close
|
810
|
+
def close
|
811
|
+
STDERR.print "[finalizer is called]"
|
812
|
+
STDERR.flush
|
813
|
+
close_orig
|
814
|
+
end
|
815
|
+
end
|
816
|
+
break
|
817
|
+
}
|
818
|
+
end
|
819
|
+
|
820
|
+
def test_upgrade_mozillastore
|
821
|
+
Dir.mktmpdir { |dir|
|
822
|
+
filename = File.join(dir, 'cookies.sqlite')
|
823
|
+
|
824
|
+
sqlite = SQLite3::Database.new(filename)
|
825
|
+
sqlite.execute(<<-'SQL')
|
826
|
+
CREATE TABLE moz_cookies (
|
827
|
+
id INTEGER PRIMARY KEY,
|
828
|
+
name TEXT,
|
829
|
+
value TEXT,
|
830
|
+
host TEXT,
|
831
|
+
path TEXT,
|
832
|
+
expiry INTEGER,
|
833
|
+
isSecure INTEGER,
|
834
|
+
isHttpOnly INTEGER)
|
835
|
+
SQL
|
836
|
+
sqlite.execute(<<-'SQL')
|
837
|
+
PRAGMA user_version = 1
|
838
|
+
SQL
|
839
|
+
|
840
|
+
begin
|
841
|
+
st_insert = sqlite.prepare(<<-'SQL')
|
842
|
+
INSERT INTO moz_cookies (
|
843
|
+
id, name, value, host, path, expiry, isSecure, isHttpOnly
|
844
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
845
|
+
SQL
|
846
|
+
|
847
|
+
st_insert.execute(1, 'name1', 'value1', '.example.co.jp', '/', 2312085765, 0, 0)
|
848
|
+
st_insert.execute(2, 'name1', 'value2', '.example.co.jp', '/', 2312085765, 0, 0)
|
849
|
+
st_insert.execute(3, 'name1', 'value3', 'www.example.co.jp', '/', 2312085765, 0, 0)
|
850
|
+
ensure
|
851
|
+
st_insert.close if st_insert
|
852
|
+
end
|
853
|
+
|
854
|
+
sqlite.close
|
855
|
+
jar = HTTP::CookieJar.new(:store => :mozilla, :filename => filename)
|
856
|
+
|
857
|
+
assert_equal 2, jar.to_a.size
|
858
|
+
assert_equal 2, jar.cookies('http://www.example.co.jp/').size
|
859
|
+
|
860
|
+
cookie, *rest = jar.cookies('http://host.example.co.jp/')
|
861
|
+
assert_send [rest, :empty?]
|
862
|
+
assert_equal 'value2', cookie.value
|
863
|
+
}
|
864
|
+
end
|
758
865
|
end if begin
|
759
866
|
require 'sqlite3'
|
760
867
|
true
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: http-cookie
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.0.
|
4
|
+
version: 1.0.0.pre12
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Akinori MUSHA
|
@@ -143,6 +143,7 @@ files:
|
|
143
143
|
- lib/http/cookie_jar/mozilla_store.rb
|
144
144
|
- lib/http/cookie_jar/yaml_saver.rb
|
145
145
|
- test/helper.rb
|
146
|
+
- test/mechanize.yml
|
146
147
|
- test/simplecov_start.rb
|
147
148
|
- test/test_http_cookie.rb
|
148
149
|
- test/test_http_cookie_jar.rb
|
@@ -171,6 +172,7 @@ specification_version: 4
|
|
171
172
|
summary: A Ruby library to handle HTTP Cookies
|
172
173
|
test_files:
|
173
174
|
- test/helper.rb
|
175
|
+
- test/mechanize.yml
|
174
176
|
- test/simplecov_start.rb
|
175
177
|
- test/test_http_cookie.rb
|
176
178
|
- test/test_http_cookie_jar.rb
|