http-cookie 1.0.0.pre2 → 1.0.0.pre3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/http-cookie.gemspec +1 -0
- data/lib/http/cookie.rb +6 -0
- data/lib/http/cookie/version.rb +1 -1
- data/lib/http/cookie_jar.rb +2 -3
- data/lib/http/cookie_jar/cookiestxt_saver.rb +14 -2
- data/lib/http/cookie_jar/hash_store.rb +23 -18
- data/lib/http/cookie_jar/mozilla_store.rb +327 -0
- data/test/test_http_cookie.rb +3 -0
- data/test/test_http_cookie_jar.rb +45 -8
- metadata +17 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 38b7c03ef15bbe6b866f7128b719962c7776fa16
|
4
|
+
data.tar.gz: 79078f90e4250e68ec2fa0b6250ee378d7681aea
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 41d93c054cda8e2fbb07554de72061fcf6218da13dce541fda0581056315b0d0438307c1f95043d59bce7742e4cee08ea9295f75c7fc1ddf297849cf7ed87ee0
|
7
|
+
data.tar.gz: a9cebb93040062c160bccf8758a25898af16f8b8fc2e5118a5cfb7210ba96b2f212b8154ca2b4e1fb1e2e740a5efaffd515bd9addc0ddee3be94d6e93e89f7f9
|
data/http-cookie.gemspec
CHANGED
@@ -24,6 +24,7 @@ Gem::Specification.new do |gem|
|
|
24
24
|
gem.extra_rdoc_files = ['README.md', 'LICENSE.txt']
|
25
25
|
|
26
26
|
gem.add_runtime_dependency("domain_name", ["~> 0.5"])
|
27
|
+
gem.add_runtime_dependency("sqlite3", ["~> 1.3.3"])
|
27
28
|
gem.add_development_dependency("bundler", [">= 1.2.0"])
|
28
29
|
gem.add_development_dependency("test-unit", [">= 2.4.3"])
|
29
30
|
gem.add_development_dependency("rake", [">= 0.9.2.2"])
|
data/lib/http/cookie.rb
CHANGED
@@ -386,6 +386,12 @@ class HTTP::Cookie
|
|
386
386
|
@domain = @domain_name.hostname
|
387
387
|
end
|
388
388
|
|
389
|
+
# Returns the domain, with a dot prefixed only if the domain flag is
|
390
|
+
# on.
|
391
|
+
def dot_domain
|
392
|
+
@for_domain ? '.' << @domain : @domain
|
393
|
+
end
|
394
|
+
|
389
395
|
# Returns the domain attribute value as a DomainName object.
|
390
396
|
attr_reader :domain_name
|
391
397
|
|
data/lib/http/cookie/version.rb
CHANGED
data/lib/http/cookie_jar.rb
CHANGED
@@ -13,6 +13,8 @@ class HTTP::CookieJar
|
|
13
13
|
# Generates a new cookie jar. The default store class is `:hash`,
|
14
14
|
# which maps to `HTTP::CookieJar::HashStore`. Any given options are
|
15
15
|
# passed through to the initializer of the specified store class.
|
16
|
+
# For example, the `:mozilla` (`HTTP::CookieJar::MozillaStore`)
|
17
|
+
# store class requires a `:filename` option.
|
16
18
|
def initialize(store = :hash, options = nil)
|
17
19
|
case store
|
18
20
|
when Symbol
|
@@ -95,9 +97,6 @@ class HTTP::CookieJar
|
|
95
97
|
if uri
|
96
98
|
uri = URI(uri)
|
97
99
|
return self unless URI::HTTP === uri && uri.host
|
98
|
-
block = proc { |cookie|
|
99
|
-
yield cookie if cookie.valid_for_uri?(uri)
|
100
|
-
}
|
101
100
|
end
|
102
101
|
|
103
102
|
@store.each(uri, &block)
|
@@ -28,11 +28,14 @@ class HTTP::CookieJar::CookiestxtSaver < HTTP::CookieJar::AbstractSaver
|
|
28
28
|
}
|
29
29
|
end
|
30
30
|
|
31
|
+
HTTPONLY_PREFIX = '#HttpOnly_'
|
32
|
+
RE_HTTPONLY_PREFIX = /\A#{HTTPONLY_PREFIX}/
|
33
|
+
|
31
34
|
# Serializes the cookie into a cookies.txt line.
|
32
35
|
def cookie_to_record(cookie)
|
33
36
|
cookie.instance_eval {
|
34
37
|
[
|
35
|
-
@
|
38
|
+
@httponly ? HTTPONLY_PREFIX + dot_domain : dot_domain,
|
36
39
|
@for_domain ? True : False,
|
37
40
|
@path,
|
38
41
|
@secure ? True : False,
|
@@ -46,7 +49,15 @@ class HTTP::CookieJar::CookiestxtSaver < HTTP::CookieJar::AbstractSaver
|
|
46
49
|
# Parses a line from cookies.txt and returns a cookie object if the
|
47
50
|
# line represents a cookie record or returns nil otherwise.
|
48
51
|
def parse_record(line)
|
49
|
-
|
52
|
+
case line
|
53
|
+
when RE_HTTPONLY_PREFIX
|
54
|
+
httponly = true
|
55
|
+
line = $'
|
56
|
+
when /\A#/
|
57
|
+
return nil
|
58
|
+
else
|
59
|
+
httponly = false
|
60
|
+
end
|
50
61
|
|
51
62
|
domain,
|
52
63
|
s_for_domain, # Whether this cookie is for domain
|
@@ -68,6 +79,7 @@ class HTTP::CookieJar::CookiestxtSaver < HTTP::CookieJar::AbstractSaver
|
|
68
79
|
:for_domain => s_for_domain == True,
|
69
80
|
:path => path,
|
70
81
|
:secure => s_secure == True,
|
82
|
+
:httponly => httponly,
|
71
83
|
:expires => expires,
|
72
84
|
:version => 0)
|
73
85
|
end
|
@@ -9,11 +9,12 @@ end
|
|
9
9
|
# :startdoc:
|
10
10
|
|
11
11
|
class HTTP::CookieJar
|
12
|
+
# A store class that uses a hash of hashes.
|
12
13
|
class HashStore < AbstractStore
|
13
|
-
GC_THRESHOLD = HTTP::Cookie::MAX_COOKIES_TOTAL / 20
|
14
|
-
|
15
14
|
def default_options
|
16
|
-
{
|
15
|
+
{
|
16
|
+
:gc_threshold => HTTP::Cookie::MAX_COOKIES_TOTAL / 20
|
17
|
+
}
|
17
18
|
end
|
18
19
|
|
19
20
|
def initialize(options = nil)
|
@@ -40,18 +41,20 @@ class HTTP::CookieJar
|
|
40
41
|
|
41
42
|
def add(cookie)
|
42
43
|
path_cookies = ((@jar[cookie.domain_name.hostname] ||= {})[cookie.path] ||= {})
|
44
|
+
path_cookies[cookie.name] = cookie
|
45
|
+
cleanup if (@gc_index += 1) >= @gc_threshold
|
46
|
+
self
|
47
|
+
end
|
43
48
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
path_cookies[cookie.name] = cookie
|
48
|
-
cleanup if (@gc_index += 1) >= GC_THRESHOLD
|
49
|
-
end
|
50
|
-
|
49
|
+
def delete(cookie)
|
50
|
+
path_cookies = ((@jar[cookie.domain_name.hostname] ||= {})[cookie.path] ||= {})
|
51
|
+
path_cookies.delete(cookie.name)
|
51
52
|
self
|
52
53
|
end
|
54
|
+
private :delete
|
53
55
|
|
54
56
|
def each(uri = nil)
|
57
|
+
now = Time.now
|
55
58
|
if uri
|
56
59
|
thost = DomainName.new(uri.host)
|
57
60
|
tpath = uri.path
|
@@ -60,11 +63,13 @@ class HTTP::CookieJar
|
|
60
63
|
paths.each { |path, hash|
|
61
64
|
next unless HTTP::Cookie.path_match?(path, tpath)
|
62
65
|
hash.delete_if { |name, cookie|
|
63
|
-
if cookie.expired?
|
66
|
+
if cookie.expired?(now)
|
64
67
|
true
|
65
68
|
else
|
66
|
-
cookie.
|
67
|
-
|
69
|
+
if cookie.valid_for_uri?(uri)
|
70
|
+
cookie.accessed_at = now
|
71
|
+
yield cookie
|
72
|
+
end
|
68
73
|
false
|
69
74
|
end
|
70
75
|
}
|
@@ -74,7 +79,7 @@ class HTTP::CookieJar
|
|
74
79
|
@jar.each { |domain, paths|
|
75
80
|
paths.each { |path, hash|
|
76
81
|
hash.delete_if { |name, cookie|
|
77
|
-
if cookie.expired?
|
82
|
+
if cookie.expired?(now)
|
78
83
|
true
|
79
84
|
else
|
80
85
|
yield cookie
|
@@ -97,14 +102,14 @@ class HTTP::CookieJar
|
|
97
102
|
end
|
98
103
|
|
99
104
|
def cleanup(session = false)
|
105
|
+
now = Time.now
|
100
106
|
all_cookies = []
|
101
|
-
|
102
107
|
@jar.each { |domain, paths|
|
103
108
|
domain_cookies = []
|
104
109
|
|
105
110
|
paths.each { |path, hash|
|
106
111
|
hash.delete_if { |name, cookie|
|
107
|
-
if cookie.expired? || (session && cookie.session?)
|
112
|
+
if cookie.expired?(now) || (session && cookie.session?)
|
108
113
|
true
|
109
114
|
else
|
110
115
|
domain_cookies << cookie
|
@@ -116,7 +121,7 @@ class HTTP::CookieJar
|
|
116
121
|
if (debt = domain_cookies.size - HTTP::Cookie::MAX_COOKIES_PER_DOMAIN) > 0
|
117
122
|
domain_cookies.sort_by!(&:created_at)
|
118
123
|
domain_cookies.slice!(0, debt).each { |cookie|
|
119
|
-
|
124
|
+
delete(cookie)
|
120
125
|
}
|
121
126
|
end
|
122
127
|
|
@@ -126,7 +131,7 @@ class HTTP::CookieJar
|
|
126
131
|
if (debt = all_cookies.size - HTTP::Cookie::MAX_COOKIES_TOTAL) > 0
|
127
132
|
all_cookies.sort_by!(&:created_at)
|
128
133
|
all_cookies.slice!(0, debt).each { |cookie|
|
129
|
-
|
134
|
+
delete(cookie)
|
130
135
|
}
|
131
136
|
end
|
132
137
|
|
@@ -0,0 +1,327 @@
|
|
1
|
+
require 'http/cookie_jar'
|
2
|
+
require 'sqlite3'
|
3
|
+
|
4
|
+
class HTTP::CookieJar
|
5
|
+
class MozillaStore < AbstractStore
|
6
|
+
SCHEMA_VERSION = 5
|
7
|
+
|
8
|
+
def default_options
|
9
|
+
{
|
10
|
+
:gc_threshold => HTTP::Cookie::MAX_COOKIES_TOTAL / 20,
|
11
|
+
:app_id => 0,
|
12
|
+
:in_browser_element => false,
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
ALL_COLUMNS = %w[
|
17
|
+
baseDomain
|
18
|
+
appId inBrowserElement
|
19
|
+
name value
|
20
|
+
host path
|
21
|
+
expiry creationTime lastAccessed
|
22
|
+
isSecure isHttpOnly
|
23
|
+
]
|
24
|
+
UK_COLUMNS = %w[
|
25
|
+
name host path
|
26
|
+
appId inBrowserElement
|
27
|
+
]
|
28
|
+
|
29
|
+
def initialize(options = nil)
|
30
|
+
super
|
31
|
+
|
32
|
+
@filename = options[:filename] or raise ArgumentError, ':filename option is missing'
|
33
|
+
|
34
|
+
@db = SQLite3::Database.new(@filename)
|
35
|
+
@db.results_as_hash = true
|
36
|
+
|
37
|
+
upgrade_database
|
38
|
+
|
39
|
+
@gc_index = 0
|
40
|
+
end
|
41
|
+
|
42
|
+
def schema_version
|
43
|
+
@schema_version ||= @db.execute("PRAGMA user_version").first[0]
|
44
|
+
rescue SQLite3::SQLException
|
45
|
+
@logger.warn "couldn't get schema version!" if @logger
|
46
|
+
return nil
|
47
|
+
end
|
48
|
+
|
49
|
+
protected
|
50
|
+
|
51
|
+
def schema_version=(version)
|
52
|
+
@db.execute("PRAGMA user_version = %d" % version)
|
53
|
+
@schema_version = version
|
54
|
+
end
|
55
|
+
|
56
|
+
def create_table
|
57
|
+
self.schema_version = SCHEMA_VERSION
|
58
|
+
@db.execute("DROP TABLE IF EXISTS moz_cookies")
|
59
|
+
@db.execute(<<-'SQL')
|
60
|
+
CREATE TABLE moz_cookies (
|
61
|
+
id INTEGER PRIMARY KEY,
|
62
|
+
baseDomain TEXT,
|
63
|
+
appId INTEGER DEFAULT 0,
|
64
|
+
inBrowserElement INTEGER DEFAULT 0,
|
65
|
+
name TEXT,
|
66
|
+
value TEXT,
|
67
|
+
host TEXT,
|
68
|
+
path TEXT,
|
69
|
+
expiry INTEGER,
|
70
|
+
lastAccessed INTEGER,
|
71
|
+
creationTime INTEGER,
|
72
|
+
isSecure INTEGER,
|
73
|
+
isHttpOnly INTEGER,
|
74
|
+
CONSTRAINT moz_uniqueid UNIQUE (name, host, path, appId, inBrowserElement)
|
75
|
+
)
|
76
|
+
SQL
|
77
|
+
@db.execute(<<-'SQL')
|
78
|
+
CREATE INDEX moz_basedomain
|
79
|
+
ON moz_cookies (baseDomain,
|
80
|
+
appId,
|
81
|
+
inBrowserElement);
|
82
|
+
SQL
|
83
|
+
end
|
84
|
+
|
85
|
+
def upgrade_database
|
86
|
+
loop {
|
87
|
+
case schema_version
|
88
|
+
when nil, 0
|
89
|
+
self.schema_version = SCHEMA_VERSION
|
90
|
+
break
|
91
|
+
when 1
|
92
|
+
@db.execute("ALTER TABLE moz_cookies ADD lastAccessed INTEGER")
|
93
|
+
self.schema_version += 1
|
94
|
+
when 2
|
95
|
+
@db.execute("ALTER TABLE moz_cookies ADD baseDomain TEXT")
|
96
|
+
|
97
|
+
st_update = @db.prepare("UPDATE moz_cookies SET baseDomain = :baseDomain WHERE id = :id")
|
98
|
+
|
99
|
+
@db.execute("SELECT id, host FROM moz_cookies") { |row|
|
100
|
+
domain = DomainName.new(row[:host]).domain
|
101
|
+
st_update.execute(:baseDomain => domain, :id => row[:id])
|
102
|
+
}
|
103
|
+
|
104
|
+
@db.execute("CREATE INDEX moz_basedomain ON moz_cookies (baseDomain)")
|
105
|
+
self.schema_version += 1
|
106
|
+
when 3
|
107
|
+
st_delete = @db.prepare("DELETE FROM moz_cookies WHERE id = :id")
|
108
|
+
|
109
|
+
prev_row = nil
|
110
|
+
@db.execute(<<-'SQL') { |row|
|
111
|
+
SELECT id, name, host, path FROM moz_cookies
|
112
|
+
ORDER BY name ASC, host ASC, path ASC, expiry ASC
|
113
|
+
SQL
|
114
|
+
if %w[name host path].all? { |col| row[col] == prev_row[col] }
|
115
|
+
st_delete.execute(prev_row['id'])
|
116
|
+
end
|
117
|
+
prev_row = row
|
118
|
+
}
|
119
|
+
|
120
|
+
@db.execute("ALTER TABLE moz_cookies ADD creationTime INTEGER")
|
121
|
+
@db.execute("UPDATE moz_cookies SET creationTime = (SELECT id WHERE id = moz_cookies.id)")
|
122
|
+
@db.execute("CREATE UNIQUE INDEX moz_uniqueid ON moz_cookies (name, host, path)")
|
123
|
+
self.schema_version += 1
|
124
|
+
when 4
|
125
|
+
@db.execute("ALTER TABLE moz_cookies RENAME TO moz_cookies_old")
|
126
|
+
@db.execute("DROP INDEX moz_basedomain")
|
127
|
+
create_table
|
128
|
+
@db.execute(<<-'SQL')
|
129
|
+
INSERT INTO moz_cookies
|
130
|
+
(baseDomain, appId, inBrowserElement, name, value, host, path, expiry,
|
131
|
+
lastAccessed, creationTime, isSecure, isHttpOnly)
|
132
|
+
SELECT baseDomain, 0, 0, name, value, host, path, expiry,
|
133
|
+
lastAccessed, creationTime, isSecure, isHttpOnly
|
134
|
+
FROM moz_cookies_old
|
135
|
+
SQL
|
136
|
+
@db.execute("DROP TABLE moz_cookies_old")
|
137
|
+
@logger.info("Upgraded database to schema version %d" % schema_version) if @logger
|
138
|
+
else
|
139
|
+
break
|
140
|
+
end
|
141
|
+
}
|
142
|
+
|
143
|
+
begin
|
144
|
+
@db.execute("SELECT %s from moz_cookies limit 1" % ALL_COLUMNS.join(', '))
|
145
|
+
rescue SQLite3::SQLException
|
146
|
+
create_table
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
public
|
151
|
+
|
152
|
+
def add(cookie)
|
153
|
+
@st_add ||=
|
154
|
+
@db.prepare('INSERT OR REPLACE INTO moz_cookies (%s) VALUES (%s)' % [
|
155
|
+
ALL_COLUMNS.join(', '),
|
156
|
+
ALL_COLUMNS.map { |col| ":#{col}" }.join(', ')
|
157
|
+
])
|
158
|
+
|
159
|
+
@st_add.execute({
|
160
|
+
:baseDomain => cookie.domain_name.domain,
|
161
|
+
:appId => @app_id,
|
162
|
+
:inBrowserElement => @in_browser_element ? 1 : 0,
|
163
|
+
:name => cookie.name, :value => cookie.value,
|
164
|
+
:host => cookie.dot_domain,
|
165
|
+
:path => cookie.path,
|
166
|
+
:expiry => cookie.expires_at.to_i,
|
167
|
+
:creationTime => cookie.created_at.to_i,
|
168
|
+
:lastAccessed => cookie.accessed_at.to_i,
|
169
|
+
:isSecure => cookie.secure? ? 1 : 0,
|
170
|
+
:isHttpOnly => cookie.httponly? ? 1 : 0,
|
171
|
+
})
|
172
|
+
cleanup if (@gc_index += 1) >= @gc_threshold
|
173
|
+
|
174
|
+
self
|
175
|
+
end
|
176
|
+
|
177
|
+
def each(uri = nil)
|
178
|
+
now = Time.now
|
179
|
+
if uri
|
180
|
+
@st_cookies_for_domain ||=
|
181
|
+
@db.prepare(<<-'SQL')
|
182
|
+
SELECT * FROM moz_cookies
|
183
|
+
WHERE baseDomain = :baseDomain AND
|
184
|
+
appId = :appId AND
|
185
|
+
inBrowserElement = :inBrowserElement AND
|
186
|
+
expiry >= :expiry
|
187
|
+
SQL
|
188
|
+
|
189
|
+
@st_update_lastaccessed ||=
|
190
|
+
@db.prepare("UPDATE moz_cookies SET lastAccessed = :lastAccessed where id = :id")
|
191
|
+
|
192
|
+
thost = DomainName.new(uri.host)
|
193
|
+
tpath = HTTP::Cookie.normalize_path(uri.path)
|
194
|
+
|
195
|
+
@st_cookies_for_domain.execute({
|
196
|
+
:baseDomain => thost.domain_name.domain,
|
197
|
+
:appId => @app_id,
|
198
|
+
:inBrowserElement => @in_browser_element ? 1 : 0,
|
199
|
+
:expiry => now.to_i,
|
200
|
+
}).each { |row|
|
201
|
+
if secure = row['isSecure'] != 0
|
202
|
+
next unless URI::HTTPS === uri
|
203
|
+
end
|
204
|
+
|
205
|
+
cookie = HTTP::Cookie.new({}.tap { |attrs|
|
206
|
+
attrs[:name] = row['name']
|
207
|
+
attrs[:value] = row['value']
|
208
|
+
attrs[:domain] = row['host']
|
209
|
+
attrs[:path] = row['path']
|
210
|
+
attrs[:expires_at] = Time.at(row['expiry'])
|
211
|
+
attrs[:accessed_at] = Time.at(row['lastAccessed'])
|
212
|
+
attrs[:created_at] = Time.at(row['creationTime'])
|
213
|
+
attrs[:secure] = secure
|
214
|
+
attrs[:httponly] = row['isHttpOnly'] != 0
|
215
|
+
})
|
216
|
+
|
217
|
+
if cookie.valid_for_uri?(uri)
|
218
|
+
cookie.accessed_at = now
|
219
|
+
@st_update_lastaccessed.execute({
|
220
|
+
'lastAccessed' => now.to_i,
|
221
|
+
'id' => row['id'],
|
222
|
+
})
|
223
|
+
yield cookie
|
224
|
+
end
|
225
|
+
}
|
226
|
+
else
|
227
|
+
@st_all_cookies ||=
|
228
|
+
@db.prepare(<<-'SQL')
|
229
|
+
SELECT * FROM moz_cookies
|
230
|
+
WHERE appId = :appId AND
|
231
|
+
inBrowserElement = :inBrowserElement AND
|
232
|
+
expiry >= :expiry
|
233
|
+
SQL
|
234
|
+
|
235
|
+
@st_all_cookies.execute({
|
236
|
+
:appId => @app_id,
|
237
|
+
:inBrowserElement => @in_browser_element ? 1 : 0,
|
238
|
+
:expiry => now.to_i,
|
239
|
+
}).each { |row|
|
240
|
+
cookie = HTTP::Cookie.new({}.tap { |attrs|
|
241
|
+
attrs[:name] = row['name']
|
242
|
+
attrs[:value] = row['value']
|
243
|
+
attrs[:domain] = row['host']
|
244
|
+
attrs[:path] = row['path']
|
245
|
+
attrs[:expires_at] = Time.at(row['expiry'])
|
246
|
+
attrs[:accessed_at] = Time.at(row['lastAccessed'])
|
247
|
+
attrs[:created_at] = Time.at(row['creationTime'])
|
248
|
+
attrs[:secure] = row['isSecure'] != 0
|
249
|
+
attrs[:httponly] = row['isHttpOnly'] != 0
|
250
|
+
})
|
251
|
+
|
252
|
+
yield cookie
|
253
|
+
}
|
254
|
+
end
|
255
|
+
self
|
256
|
+
end
|
257
|
+
|
258
|
+
def clear
|
259
|
+
@db.execute("DELETE FROM moz_cookies")
|
260
|
+
self
|
261
|
+
end
|
262
|
+
|
263
|
+
def count
|
264
|
+
@st_count ||=
|
265
|
+
@db.prepare("SELECT COUNT(id) FROM moz_cookies")
|
266
|
+
|
267
|
+
@st_count.execute.first[0]
|
268
|
+
end
|
269
|
+
protected :count
|
270
|
+
|
271
|
+
def empty?
|
272
|
+
count == 0
|
273
|
+
end
|
274
|
+
|
275
|
+
def cleanup(session = false)
|
276
|
+
now = Time.now
|
277
|
+
all_cookies = []
|
278
|
+
|
279
|
+
@st_delete_expired ||=
|
280
|
+
@db.prepare("DELETE FROM moz_cookies WHERE expiry < :expiry")
|
281
|
+
|
282
|
+
@st_overusing_domains ||=
|
283
|
+
@db.prepare(<<-'SQL')
|
284
|
+
SELECT LTRIM(host, '.') domain, COUNT(*) count
|
285
|
+
FROM moz_cookies
|
286
|
+
GROUP BY domain
|
287
|
+
HAVING count > :count
|
288
|
+
SQL
|
289
|
+
|
290
|
+
@st_delete_per_domain_overuse ||=
|
291
|
+
@db.prepare(<<-'SQL')
|
292
|
+
DELETE FROM moz_cookies WHERE id IN (
|
293
|
+
SELECT id FROM moz_cookies
|
294
|
+
WHERE LTRIM(host, '.') = :domain
|
295
|
+
ORDER BY creationtime
|
296
|
+
LIMIT :limit)
|
297
|
+
SQL
|
298
|
+
@st_delete_total_overuse ||=
|
299
|
+
@db.prepare(<<-'SQL')
|
300
|
+
DELETE FROM moz_cookies WHERE id IN (
|
301
|
+
SELECT id FROM moz_cookies ORDER BY creationTime ASC LIMIT :limit
|
302
|
+
)
|
303
|
+
SQL
|
304
|
+
|
305
|
+
@st_delete_expired.execute({ 'expiry' => now.to_i })
|
306
|
+
|
307
|
+
@st_overusing_domains.execute({
|
308
|
+
'count' => HTTP::Cookie::MAX_COOKIES_PER_DOMAIN
|
309
|
+
}).each { |row|
|
310
|
+
domain, count = row['domain'], row['count']
|
311
|
+
|
312
|
+
@st_delete_per_domain_overuse.execute({
|
313
|
+
'domain' => domain,
|
314
|
+
'limit' => count - HTTP::Cookie::MAX_COOKIES_PER_DOMAIN,
|
315
|
+
})
|
316
|
+
}
|
317
|
+
|
318
|
+
overrun = count - HTTP::Cookie::MAX_COOKIES_TOTAL
|
319
|
+
|
320
|
+
if overrun > 0
|
321
|
+
@st_delete_total_overuse.execute({ 'limit' => overrun })
|
322
|
+
end
|
323
|
+
|
324
|
+
@gc_index = 0
|
325
|
+
end
|
326
|
+
end
|
327
|
+
end
|
data/test/test_http_cookie.rb
CHANGED
@@ -162,6 +162,7 @@ class TestHTTPCookie < Test::Unit::TestCase
|
|
162
162
|
|
163
163
|
assert_equal 'example.com', cookie.domain
|
164
164
|
assert cookie.for_domain?
|
165
|
+
assert_equal '.example.com', cookie.dot_domain
|
165
166
|
end
|
166
167
|
|
167
168
|
def test_parse_domain_no_dot
|
@@ -173,6 +174,7 @@ class TestHTTPCookie < Test::Unit::TestCase
|
|
173
174
|
|
174
175
|
assert_equal 'example.com', cookie.domain
|
175
176
|
assert cookie.for_domain?
|
177
|
+
assert_equal '.example.com', cookie.dot_domain
|
176
178
|
end
|
177
179
|
|
178
180
|
def test_parse_domain_none
|
@@ -184,6 +186,7 @@ class TestHTTPCookie < Test::Unit::TestCase
|
|
184
186
|
|
185
187
|
assert_equal 'example.com', cookie.domain
|
186
188
|
assert !cookie.for_domain?
|
189
|
+
assert_equal 'example.com', cookie.dot_domain
|
187
190
|
end
|
188
191
|
|
189
192
|
def test_parse_max_age
|
@@ -360,20 +360,31 @@ class TestHTTPCookieJar < Test::Unit::TestCase
|
|
360
360
|
:value => 'Foo#Baz',
|
361
361
|
:path => '/foo/',
|
362
362
|
:for_domain => false))
|
363
|
+
h_cookie = HTTP::Cookie.new(cookie_values(:name => 'Quux',
|
364
|
+
:value => 'Foo#Quux',
|
365
|
+
:httponly => true))
|
363
366
|
|
364
367
|
@jar.add(cookie)
|
365
368
|
@jar.add(s_cookie)
|
366
369
|
@jar.add(cookie2)
|
370
|
+
@jar.add(h_cookie)
|
367
371
|
|
368
|
-
assert_equal(
|
372
|
+
assert_equal(4, @jar.cookies(url).length)
|
369
373
|
|
370
374
|
Dir.mktmpdir do |dir|
|
371
|
-
|
375
|
+
filename = File.join(dir, "cookies.txt")
|
376
|
+
@jar.save(filename, :cookiestxt)
|
377
|
+
|
378
|
+
content = File.read(filename)
|
379
|
+
|
380
|
+
assert_match(/^\.rubyforge\.org\t.*\tFoo\t/, content)
|
381
|
+
assert_match(/^rubyforge\.org\t.*\tBaz\t/, content)
|
382
|
+
assert_match(/^#HttpOnly_\.rubyforge\.org\t/, content)
|
372
383
|
|
373
384
|
jar = HTTP::CookieJar.new
|
374
|
-
jar.load(
|
385
|
+
jar.load(filename, :cookiestxt) # HACK test the format
|
375
386
|
cookies = jar.cookies(url)
|
376
|
-
assert_equal(
|
387
|
+
assert_equal(3, cookies.length)
|
377
388
|
cookies.each { |cookie|
|
378
389
|
case cookie.name
|
379
390
|
when 'Foo'
|
@@ -382,18 +393,27 @@ class TestHTTPCookieJar < Test::Unit::TestCase
|
|
382
393
|
assert_equal 'rubyforge.org', cookie.domain
|
383
394
|
assert_equal true, cookie.for_domain
|
384
395
|
assert_equal '/', cookie.path
|
396
|
+
assert_equal false, cookie.httponly?
|
385
397
|
when 'Baz'
|
386
398
|
assert_equal 'Foo#Baz', cookie.value
|
387
399
|
assert_equal 'rubyforge.org', cookie.domain
|
388
400
|
assert_equal false, cookie.for_domain
|
389
401
|
assert_equal '/foo/', cookie.path
|
402
|
+
assert_equal false, cookie.httponly?
|
403
|
+
when 'Quux'
|
404
|
+
assert_equal 'Foo#Quux', cookie.value
|
405
|
+
assert_equal expires, cookie.expires
|
406
|
+
assert_equal 'rubyforge.org', cookie.domain
|
407
|
+
assert_equal true, cookie.for_domain
|
408
|
+
assert_equal '/', cookie.path
|
409
|
+
assert_equal true, cookie.httponly?
|
390
410
|
else
|
391
411
|
raise
|
392
412
|
end
|
393
413
|
}
|
394
414
|
end
|
395
415
|
|
396
|
-
assert_equal(
|
416
|
+
assert_equal(4, @jar.cookies(url).length)
|
397
417
|
end
|
398
418
|
|
399
419
|
def test_expire_cookies
|
@@ -514,8 +534,7 @@ class TestHTTPCookieJar < Test::Unit::TestCase
|
|
514
534
|
assert_equal('Foo1 Foo2', @jar.cookies(surl).map { |c| c.name }.sort.join(' ') )
|
515
535
|
end
|
516
536
|
|
517
|
-
def
|
518
|
-
jar = HTTP::CookieJar.new
|
537
|
+
def h_test_max_cookies(jar, slimit)
|
519
538
|
limit_per_domain = HTTP::Cookie::MAX_COOKIES_PER_DOMAIN
|
520
539
|
uri = URI('http://www.example.org/')
|
521
540
|
date = Time.at(Time.now.to_i + 86400)
|
@@ -540,7 +559,6 @@ class TestHTTPCookieJar < Test::Unit::TestCase
|
|
540
559
|
}.sort
|
541
560
|
|
542
561
|
hlimit = HTTP::Cookie::MAX_COOKIES_TOTAL
|
543
|
-
slimit = hlimit + HTTP::CookieJar::HashStore::GC_THRESHOLD
|
544
562
|
|
545
563
|
n = hlimit / limit_per_domain * 2
|
546
564
|
|
@@ -569,4 +587,23 @@ class TestHTTPCookieJar < Test::Unit::TestCase
|
|
569
587
|
cookie.domain == cookie.value
|
570
588
|
}
|
571
589
|
end
|
590
|
+
|
591
|
+
def test_max_cookies_hashstore
|
592
|
+
gc_threshold = 150
|
593
|
+
h_test_max_cookies(
|
594
|
+
HTTP::CookieJar.new(:hash,
|
595
|
+
:gc_threshold => gc_threshold),
|
596
|
+
HTTP::Cookie::MAX_COOKIES_TOTAL + gc_threshold)
|
597
|
+
end
|
598
|
+
|
599
|
+
def test_max_cookies_mozillastore
|
600
|
+
gc_threshold = 150
|
601
|
+
Dir.mktmpdir { |dir|
|
602
|
+
h_test_max_cookies(
|
603
|
+
HTTP::CookieJar.new(:mozilla,
|
604
|
+
:gc_threshold => gc_threshold,
|
605
|
+
:filename => File.join(dir, "cookies.sqlite")),
|
606
|
+
HTTP::Cookie::MAX_COOKIES_TOTAL + gc_threshold)
|
607
|
+
}
|
608
|
+
end
|
572
609
|
end
|
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.pre3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Akinori MUSHA
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2013-03-
|
14
|
+
date: 2013-03-27 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: domain_name
|
@@ -27,6 +27,20 @@ dependencies:
|
|
27
27
|
- - ~>
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: '0.5'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: sqlite3
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
requirements:
|
34
|
+
- - ~>
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: 1.3.3
|
37
|
+
type: :runtime
|
38
|
+
prerelease: false
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 1.3.3
|
30
44
|
- !ruby/object:Gem::Dependency
|
31
45
|
name: bundler
|
32
46
|
requirement: !ruby/object:Gem::Requirement
|
@@ -125,6 +139,7 @@ files:
|
|
125
139
|
- lib/http/cookie_jar/abstract_store.rb
|
126
140
|
- lib/http/cookie_jar/cookiestxt_saver.rb
|
127
141
|
- lib/http/cookie_jar/hash_store.rb
|
142
|
+
- lib/http/cookie_jar/mozilla_store.rb
|
128
143
|
- lib/http/cookie_jar/yaml_saver.rb
|
129
144
|
- test/helper.rb
|
130
145
|
- test/simplecov_start.rb
|