http-cookie 1.0.0.pre11 → 1.0.0.pre12
Sign up to get free protection for your applications and to get access to all the features.
- 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
|