http-cookie 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,141 @@
1
+ require 'http/cookie_jar'
2
+
3
+ class Array
4
+ def sort_by!(&block)
5
+ replace(sort_by(&block))
6
+ end unless method_defined?(:sort_by!)
7
+ end
8
+
9
+ class HTTP::CookieJar
10
+ class HashStore < AbstractStore
11
+ GC_THRESHOLD = HTTP::Cookie::MAX_COOKIES_TOTAL / 20
12
+
13
+ def default_options
14
+ {}
15
+ end
16
+
17
+ def initialize(options = nil)
18
+ super
19
+
20
+ @jar = {}
21
+ # {
22
+ # hostname => {
23
+ # path => {
24
+ # name => cookie,
25
+ # ...
26
+ # },
27
+ # ...
28
+ # },
29
+ # ...
30
+ # }
31
+
32
+ @gc_index = 0
33
+ end
34
+
35
+ def initialize_copy(other)
36
+ @jar = Marshal.load(Marshal.dump(other.instance_variable_get(:@jar)))
37
+ end
38
+
39
+ def add(cookie)
40
+ path_cookies = ((@jar[cookie.domain_name.hostname] ||= {})[cookie.path] ||= {})
41
+
42
+ if cookie.expired?
43
+ path_cookies.delete(cookie.name)
44
+ else
45
+ path_cookies[cookie.name] = cookie
46
+ cleanup if (@gc_index += 1) >= GC_THRESHOLD
47
+ end
48
+
49
+ self
50
+ end
51
+
52
+ def each(uri = nil)
53
+ if uri
54
+ uri = URI(uri)
55
+ thost = DomainName.new(uri.host)
56
+ tpath = HTTP::Cookie.normalize_path(uri.path)
57
+ @jar.each { |domain, paths|
58
+ next unless thost.cookie_domain?(domain)
59
+ paths.each { |path, hash|
60
+ next unless tpath.start_with?(path)
61
+ hash.delete_if { |name, cookie|
62
+ if cookie.expired?
63
+ true
64
+ else
65
+ cookie.accessed_at = Time.now
66
+ yield cookie
67
+ false
68
+ end
69
+ }
70
+ }
71
+ }
72
+ else
73
+ @jar.each { |domain, paths|
74
+ paths.each { |path, hash|
75
+ hash.delete_if { |name, cookie|
76
+ if cookie.expired?
77
+ true
78
+ else
79
+ yield cookie
80
+ false
81
+ end
82
+ }
83
+ }
84
+ }
85
+ end
86
+ end
87
+
88
+ def clear
89
+ @jar.clear
90
+ self
91
+ end
92
+
93
+ def empty?
94
+ @jar.empty?
95
+ end
96
+
97
+ def cleanup(session = false)
98
+ all_cookies = []
99
+
100
+ @jar.each { |domain, paths|
101
+ domain_cookies = []
102
+
103
+ paths.each { |path, hash|
104
+ hash.delete_if { |name, cookie|
105
+ if cookie.expired? || (session && cookie.session?)
106
+ true
107
+ else
108
+ domain_cookies << cookie
109
+ false
110
+ end
111
+ }
112
+ }
113
+
114
+ if (debt = domain_cookies.size - HTTP::Cookie::MAX_COOKIES_PER_DOMAIN) > 0
115
+ domain_cookies.sort_by!(&:created_at)
116
+ domain_cookies.slice!(0, debt).each { |cookie|
117
+ add(cookie.expire)
118
+ }
119
+ end
120
+
121
+ all_cookies.concat(domain_cookies)
122
+ }
123
+
124
+ if (debt = all_cookies.size - HTTP::Cookie::MAX_COOKIES_TOTAL) > 0
125
+ all_cookies.sort_by!(&:created_at)
126
+ all_cookies.slice!(0, debt).each { |cookie|
127
+ add(cookie.expire)
128
+ }
129
+ end
130
+
131
+ @jar.delete_if { |domain, paths|
132
+ paths.delete_if { |path, hash|
133
+ hash.empty?
134
+ }
135
+ paths.empty?
136
+ }
137
+
138
+ @gc_index = 0
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,37 @@
1
+ require 'http/cookie_jar'
2
+ begin
3
+ require 'psych'
4
+ rescue LoadError
5
+ end
6
+ require 'yaml'
7
+
8
+ # YAMLSaver saves and loads cookies in the YAML format.
9
+ class HTTP::CookieJar::YAMLSaver < HTTP::CookieJar::AbstractSaver
10
+ def save(io, jar)
11
+ YAML.dump(@session ? jar.to_a : jar.reject(&:session?), io)
12
+ end
13
+
14
+ def load(io, jar)
15
+ begin
16
+ data = YAML.load(io)
17
+ rescue ArgumentError
18
+ @logger.warn "unloadable YAML cookie data discarded" if @logger
19
+ return
20
+ end
21
+
22
+ unless data.instance_of?(Array)
23
+ @logger.warn "incompatible YAML cookie data discarded" if @logger
24
+ return
25
+ end
26
+
27
+ data.each { |cookie|
28
+ jar.add(cookie)
29
+ }
30
+ end
31
+
32
+ private
33
+
34
+ def default_options
35
+ {}
36
+ end
37
+ end
@@ -0,0 +1,33 @@
1
+ require 'rubygems'
2
+ require 'test-unit'
3
+ require 'uri'
4
+ require 'http/cookie'
5
+
6
+ module Enumerable
7
+ def combine
8
+ masks = inject([[], 1]){|(ar, m), e| [ar << m, m << 1 ] }[0]
9
+ all = masks.inject(0){ |al, m| al|m }
10
+
11
+ result = []
12
+ for i in 1..all do
13
+ tmp = []
14
+ each_with_index do |e, idx|
15
+ tmp << e unless (masks[idx] & i) == 0
16
+ end
17
+ result << tmp
18
+ end
19
+ result
20
+ end
21
+ end
22
+
23
+ module Test::Unit::Assertions
24
+ def assert_raises_with_message(exc, re, message = nil, &block)
25
+ e = nil
26
+ begin
27
+ block.call
28
+ rescue Exception => e
29
+ end
30
+ assert_instance_of(exc, e, message)
31
+ assert_match(re, e.message, message)
32
+ end
33
+ end
@@ -0,0 +1,2 @@
1
+ require 'simplecov'
2
+ SimpleCov.start
@@ -0,0 +1,624 @@
1
+ # -*- coding: utf-8 -*-
2
+ require File.expand_path('helper', File.dirname(__FILE__))
3
+
4
+ class TestHTTPCookie < Test::Unit::TestCase
5
+ def silently
6
+ warn_level = $VERBOSE
7
+ $VERBOSE = false
8
+ res = yield
9
+ $VERBOSE = warn_level
10
+ res
11
+ end
12
+
13
+ def setup
14
+ httpdate = 'Sun, 27-Sep-2037 00:00:00 GMT'
15
+
16
+ @cookie_params = {
17
+ 'expires' => 'expires=%s' % httpdate,
18
+ 'path' => 'path=/',
19
+ 'domain' => 'domain=.rubyforge.org',
20
+ 'httponly' => 'HttpOnly',
21
+ }
22
+
23
+ @expires = Time.parse(httpdate)
24
+ end
25
+
26
+ def test_parse_dates
27
+ url = URI.parse('http://localhost/')
28
+
29
+ yesterday = Time.now - 86400
30
+
31
+ dates = [ "14 Apr 89 03:20:12",
32
+ "14 Apr 89 03:20 GMT",
33
+ "Fri, 17 Mar 89 4:01:33",
34
+ "Fri, 17 Mar 89 4:01 GMT",
35
+ "Mon Jan 16 16:12 PDT 1989",
36
+ "Mon Jan 16 16:12 +0130 1989",
37
+ "6 May 1992 16:41-JST (Wednesday)",
38
+ #"22-AUG-1993 10:59:12.82",
39
+ "22-AUG-1993 10:59pm",
40
+ "22-AUG-1993 12:59am",
41
+ "22-AUG-1993 12:59 PM",
42
+ #"Friday, August 04, 1995 3:54 PM",
43
+ #"06/21/95 04:24:34 PM",
44
+ #"20/06/95 21:07",
45
+ "95-06-08 19:32:48 EDT",
46
+ ]
47
+
48
+ dates.each do |date|
49
+ cookie = "PREF=1; expires=#{date}"
50
+ silently do
51
+ HTTP::Cookie.parse(cookie, :origin => url) { |c|
52
+ assert c.expires, "Tried parsing: #{date}"
53
+ assert_equal(true, c.expires < yesterday)
54
+ }
55
+ end
56
+ end
57
+ end
58
+
59
+ def test_parse_empty
60
+ cookie_str = 'a=b; ; c=d'
61
+
62
+ uri = URI.parse 'http://example'
63
+
64
+ HTTP::Cookie.parse cookie_str, :origin => uri do |cookie|
65
+ assert_equal 'a', cookie.name
66
+ assert_equal 'b', cookie.value
67
+ end
68
+ end
69
+
70
+ def test_parse_no_space
71
+ cookie_str = "foo=bar;Expires=Sun, 06 Nov 2011 00:28:06 GMT;Path=/"
72
+
73
+ uri = URI.parse 'http://example'
74
+
75
+ HTTP::Cookie.parse cookie_str, :origin => uri do |cookie|
76
+ assert_equal 'foo', cookie.name
77
+ assert_equal 'bar', cookie.value
78
+ assert_equal '/', cookie.path
79
+ assert_equal Time.at(1320539286), cookie.expires
80
+ end
81
+ end
82
+
83
+ def test_parse_too_long_cookie
84
+ uri = URI.parse 'http://example'
85
+
86
+ cookie_str = "foo=#{'クッキー' * 340}; path=/ab/"
87
+ assert_equal(HTTP::Cookie::MAX_LENGTH - 1, cookie_str.bytesize)
88
+
89
+ assert_equal 1, HTTP::Cookie.parse(cookie_str, :origin => uri).size
90
+
91
+ assert_equal 1, HTTP::Cookie.parse(cookie_str.sub(';', 'x;'), :origin => uri).size
92
+
93
+ assert_equal 0, HTTP::Cookie.parse(cookie_str.sub(';', 'xx;'), :origin => uri).size
94
+ end
95
+
96
+ def test_parse_quoted
97
+ cookie_str =
98
+ "quoted=\"value\"; Expires=Sun, 06 Nov 2011 00:11:18 GMT; Path=/"
99
+
100
+ uri = URI.parse 'http://example'
101
+
102
+ HTTP::Cookie.parse cookie_str, :origin => uri do |cookie|
103
+ assert_equal 'quoted', cookie.name
104
+ assert_equal '"value"', cookie.value
105
+ end
106
+ end
107
+
108
+ def test_parse_weird_cookie
109
+ cookie = 'n/a, ASPSESSIONIDCSRRQDQR=FBLDGHPBNDJCPCGNCPAENELB; path=/'
110
+ url = URI.parse('http://www.searchinnovation.com/')
111
+ HTTP::Cookie.parse(cookie, :origin => url) { |c|
112
+ assert_equal('ASPSESSIONIDCSRRQDQR', c.name)
113
+ assert_equal('FBLDGHPBNDJCPCGNCPAENELB', c.value)
114
+ }
115
+ end
116
+
117
+ def test_double_semicolon
118
+ double_semi = 'WSIDC=WEST;; domain=.williams-sonoma.com; path=/'
119
+ url = URI.parse('http://williams-sonoma.com/')
120
+ HTTP::Cookie.parse(double_semi, :origin => url) { |cookie|
121
+ assert_equal('WSIDC', cookie.name)
122
+ assert_equal('WEST', cookie.value)
123
+ }
124
+ end
125
+
126
+ def test_parse_bad_version
127
+ bad_cookie = 'PRETANET=TGIAqbFXtt; Name=/PRETANET; Path=/; Version=1.2; Content-type=text/html; Domain=192.168.6.196; expires=Friday, 13-November-2026 23:01:46 GMT;'
128
+ url = URI.parse('http://localhost/')
129
+ HTTP::Cookie.parse(bad_cookie, :origin => url) { |cookie|
130
+ assert_nil(cookie.version)
131
+ }
132
+ end
133
+
134
+ def test_parse_bad_max_age
135
+ bad_cookie = 'PRETANET=TGIAqbFXtt; Name=/PRETANET; Path=/; Max-Age=1.2; Content-type=text/html; Domain=192.168.6.196; expires=Friday, 13-November-2026 23:01:46 GMT;'
136
+ url = URI.parse('http://localhost/')
137
+ HTTP::Cookie.parse(bad_cookie, :origin => url) { |cookie|
138
+ assert_nil(cookie.max_age)
139
+ }
140
+ end
141
+
142
+ def test_parse_date_fail
143
+ url = URI.parse('http://localhost/')
144
+
145
+ dates = [
146
+ "20/06/95 21:07",
147
+ ]
148
+
149
+ silently do
150
+ dates.each do |date|
151
+ cookie = "PREF=1; expires=#{date}"
152
+ HTTP::Cookie.parse(cookie, :origin => url) { |c|
153
+ assert_equal(true, c.expires.nil?)
154
+ }
155
+ end
156
+ end
157
+ end
158
+
159
+ def test_parse_domain_dot
160
+ url = URI.parse('http://host.example.com/')
161
+
162
+ cookie_str = 'a=b; domain=.example.com'
163
+
164
+ cookie = HTTP::Cookie.parse(cookie_str, :origin => url).first
165
+
166
+ assert_equal 'example.com', cookie.domain
167
+ assert cookie.for_domain?
168
+ end
169
+
170
+ def test_parse_domain_no_dot
171
+ url = URI.parse('http://host.example.com/')
172
+
173
+ cookie_str = 'a=b; domain=example.com'
174
+
175
+ cookie = HTTP::Cookie.parse(cookie_str, :origin => url).first
176
+
177
+ assert_equal 'example.com', cookie.domain
178
+ assert cookie.for_domain?
179
+ end
180
+
181
+ def test_parse_domain_none
182
+ url = URI.parse('http://example.com/')
183
+
184
+ cookie_str = 'a=b;'
185
+
186
+ cookie = HTTP::Cookie.parse(cookie_str, :origin => url).first
187
+
188
+ assert_equal 'example.com', cookie.domain
189
+ assert !cookie.for_domain?
190
+ end
191
+
192
+ def test_parse_max_age
193
+ url = URI.parse('http://localhost/')
194
+
195
+ epoch, date = 4485353164, 'Fri, 19 Feb 2112 19:26:04 GMT'
196
+ base = Time.at(1363014000)
197
+
198
+ cookie = HTTP::Cookie.parse("name=Akinori; expires=#{date}", :origin => url).first
199
+ assert_equal Time.at(epoch), cookie.expires
200
+
201
+ cookie = HTTP::Cookie.parse('name=Akinori; max-age=3600', :origin => url).first
202
+ assert_in_delta Time.now + 3600, cookie.expires, 1
203
+ cookie = HTTP::Cookie.parse('name=Akinori; max-age=3600', :origin => url, :date => base).first
204
+ assert_equal base + 3600, cookie.expires
205
+
206
+ # Max-Age has precedence over Expires
207
+ cookie = HTTP::Cookie.parse("name=Akinori; max-age=3600; expires=#{date}", :origin => url).first
208
+ assert_in_delta Time.now + 3600, cookie.expires, 1
209
+ cookie = HTTP::Cookie.parse("name=Akinori; max-age=3600; expires=#{date}", :origin => url, :date => base).first
210
+ assert_equal base + 3600, cookie.expires
211
+
212
+ cookie = HTTP::Cookie.parse("name=Akinori; expires=#{date}; max-age=3600", :origin => url).first
213
+ assert_in_delta Time.now + 3600, cookie.expires, 1
214
+ cookie = HTTP::Cookie.parse("name=Akinori; expires=#{date}; max-age=3600", :origin => url, :date => base).first
215
+ assert_equal base + 3600, cookie.expires
216
+ end
217
+
218
+ def test_parse_expires_session
219
+ url = URI.parse('http://localhost/')
220
+
221
+ [
222
+ 'name=Akinori',
223
+ 'name=Akinori; expires',
224
+ 'name=Akinori; max-age',
225
+ 'name=Akinori; expires=',
226
+ 'name=Akinori; max-age=',
227
+ ].each { |str|
228
+ cookie = HTTP::Cookie.parse(str, :origin => url).first
229
+ assert cookie.session?, str
230
+ }
231
+
232
+ [
233
+ 'name=Akinori; expires=Mon, 19 Feb 2012 19:26:04 GMT',
234
+ 'name=Akinori; max-age=3600',
235
+ ].each { |str|
236
+ cookie = HTTP::Cookie.parse(str, :origin => url).first
237
+ assert !cookie.session?, str
238
+ }
239
+ end
240
+
241
+ def test_parse_many
242
+ url = URI 'http://localhost/'
243
+ cookie_str =
244
+ "abc, " \
245
+ "name=Aaron; Domain=localhost; Expires=Sun, 06 Nov 2011 00:29:51 GMT; Path=/, " \
246
+ "name=Aaron; Domain=localhost; Expires=Sun, 06 Nov 2011 00:29:51 GMT; Path=/, " \
247
+ "name=Aaron; Domain=localhost; Expires=Sun, 06 Nov 2011 00:29:51 GMT; Path=/, " \
248
+ "name=Aaron; Domain=localhost; Expires=Sun, 06 Nov 2011 00:29:51 GMT; Path=/; HttpOnly, " \
249
+ "expired=doh; Expires=Fri, 04 Nov 2011 00:29:51 GMT; Path=/, " \
250
+ "a_path=some_path; Expires=Sun, 06 Nov 2011 00:29:51 GMT; Path=/some_path, " \
251
+ "no_path1=no_path; Expires=Sun, 06 Nov 2011 00:29:52 GMT, no_expires=nope; Path=/, " \
252
+ "no_path2=no_path; Expires=Sun, 06 Nov 2011 00:29:52 GMT; no_expires=nope; Path, " \
253
+ "no_path3=no_path; Expires=Sun, 06 Nov 2011 00:29:52 GMT; no_expires=nope; Path=, " \
254
+ "no_domain1=no_domain; Expires=Sun, 06 Nov 2011 00:29:53 GMT; no_expires=nope, " \
255
+ "no_domain2=no_domain; Expires=Sun, 06 Nov 2011 00:29:53 GMT; no_expires=nope; Domain, " \
256
+ "no_domain3=no_domain; Expires=Sun, 06 Nov 2011 00:29:53 GMT; no_expires=nope; Domain="
257
+
258
+ cookies = HTTP::Cookie.parse cookie_str, :origin => url
259
+ assert_equal 13, cookies.length
260
+
261
+ name = cookies.find { |c| c.name == 'name' }
262
+ assert_equal "Aaron", name.value
263
+ assert_equal "/", name.path
264
+ assert_equal Time.at(1320539391), name.expires
265
+
266
+ a_path = cookies.find { |c| c.name == 'a_path' }
267
+ assert_equal "some_path", a_path.value
268
+ assert_equal "/some_path", a_path.path
269
+ assert_equal Time.at(1320539391), a_path.expires
270
+
271
+ no_expires = cookies.find { |c| c.name == 'no_expires' }
272
+ assert_equal "nope", no_expires.value
273
+ assert_equal "/", no_expires.path
274
+ assert_nil no_expires.expires
275
+
276
+ no_path_cookies = cookies.select { |c| c.value == 'no_path' }
277
+ assert_equal 3, no_path_cookies.size
278
+ no_path_cookies.each { |c|
279
+ assert_equal "/", c.path, c.name
280
+ assert_equal Time.at(1320539392), c.expires, c.name
281
+ }
282
+
283
+ no_domain_cookies = cookies.select { |c| c.value == 'no_domain' }
284
+ assert_equal 3, no_domain_cookies.size
285
+ no_domain_cookies.each { |c|
286
+ assert !c.for_domain?, c.name
287
+ assert_equal c.domain, url.host, c.name
288
+ assert_equal Time.at(1320539393), c.expires, c.name
289
+ }
290
+
291
+ assert cookies.find { |c| c.name == 'expired' }
292
+ end
293
+
294
+ def test_parse_valid_cookie
295
+ url = URI.parse('http://rubyforge.org/')
296
+ cookie_params = @cookie_params
297
+ cookie_value = '12345%7D=ASDFWEE345%3DASda'
298
+
299
+ cookie_params.keys.combine.each do |keys|
300
+ cookie_text = [cookie_value, *keys.map { |key| cookie_params[key] }].join('; ')
301
+ cookie, = HTTP::Cookie.parse(cookie_text, :origin => url)
302
+
303
+ assert_equal('12345%7D=ASDFWEE345%3DASda', cookie.to_s)
304
+ assert_equal('/', cookie.path)
305
+
306
+ assert_equal(keys.include?('expires') ? @expires : nil, cookie.expires)
307
+ assert_equal(keys.include?('httponly'), cookie.httponly?)
308
+ end
309
+ end
310
+
311
+ def test_parse_valid_cookie_empty_value
312
+ url = URI.parse('http://rubyforge.org/')
313
+ cookie_params = @cookie_params
314
+ cookie_value = '12345%7D='
315
+
316
+ cookie_params.keys.combine.each do |keys|
317
+ cookie_text = [cookie_value, *keys.map { |key| cookie_params[key] }].join('; ')
318
+ cookie, = HTTP::Cookie.parse(cookie_text, :origin => url)
319
+
320
+ assert_equal('12345%7D=', cookie.to_s)
321
+ assert_equal('', cookie.value)
322
+ assert_equal('/', cookie.path)
323
+
324
+ assert_equal(keys.include?('expires') ? @expires : nil, cookie.expires)
325
+ assert_equal(keys.include?('httponly'), cookie.httponly?)
326
+ end
327
+ end
328
+
329
+ # If no path was given, use the one from the URL
330
+ def test_cookie_using_url_path
331
+ url = URI.parse('http://rubyforge.org/login.php')
332
+ cookie_params = @cookie_params
333
+ cookie_value = '12345%7D=ASDFWEE345%3DASda'
334
+
335
+ cookie_params.keys.combine.each do |keys|
336
+ next if keys.include?('path')
337
+ cookie_text = [cookie_value, *keys.map { |key| cookie_params[key] }].join('; ')
338
+ cookie, = HTTP::Cookie.parse(cookie_text, :origin => url)
339
+
340
+ assert_equal('12345%7D=ASDFWEE345%3DASda', cookie.to_s)
341
+ assert_equal('/', cookie.path)
342
+
343
+ assert_equal(keys.include?('expires') ? @expires : nil, cookie.expires)
344
+ assert_equal(keys.include?('httponly'), cookie.httponly?)
345
+ end
346
+ end
347
+
348
+ # Test using secure cookies
349
+ def test_cookie_with_secure
350
+ url = URI.parse('http://rubyforge.org/')
351
+ cookie_params = @cookie_params.merge('secure' => 'secure')
352
+ cookie_value = '12345%7D=ASDFWEE345%3DASda'
353
+
354
+ cookie_params.keys.combine.each do |keys|
355
+ next unless keys.include?('secure')
356
+ cookie_text = [cookie_value, *keys.map { |key| cookie_params[key] }].join('; ')
357
+ cookie, = HTTP::Cookie.parse(cookie_text, :origin => url)
358
+
359
+ assert_equal('12345%7D=ASDFWEE345%3DASda', cookie.to_s)
360
+ assert_equal('/', cookie.path)
361
+ assert_equal(true, cookie.secure)
362
+
363
+ assert_equal(keys.include?('expires') ? @expires : nil, cookie.expires)
364
+ assert_equal(keys.include?('httponly'), cookie.httponly?)
365
+ end
366
+ end
367
+
368
+ def test_set_cookie_value
369
+ url = URI.parse('http://rubyforge.org/')
370
+ cookie_params = @cookie_params.merge('secure' => 'secure')
371
+ cookie_value = 'foo=bar'
372
+
373
+ cookie_params.keys.combine.each do |keys|
374
+ cookie_text = [cookie_value, *keys.map { |key| cookie_params[key] }].join('; ')
375
+ cookie, = HTTP::Cookie.parse(cookie_text, :origin => url)
376
+ cookie2, = HTTP::Cookie.parse(cookie.set_cookie_value, :origin => url)
377
+
378
+ assert_equal(cookie.name, cookie2.name)
379
+ assert_equal(cookie.value, cookie2.value)
380
+ assert_equal(cookie.domain, cookie2.domain)
381
+ assert_equal(cookie.for_domain?, cookie2.for_domain?)
382
+ assert_equal(cookie.path, cookie2.path)
383
+ assert_equal(cookie.expires, cookie2.expires)
384
+ assert_equal(cookie.secure?, cookie2.secure?)
385
+ assert_equal(cookie.httponly?, cookie2.httponly?)
386
+ end
387
+ end
388
+
389
+ def test_parse_cookie_no_spaces
390
+ url = URI.parse('http://rubyforge.org/')
391
+ cookie_params = @cookie_params
392
+ cookie_value = '12345%7D=ASDFWEE345%3DASda'
393
+
394
+ cookie_params.keys.combine.each do |keys|
395
+ cookie_text = [cookie_value, *keys.map { |key| cookie_params[key] }].join(';')
396
+ cookie, = HTTP::Cookie.parse(cookie_text, :origin => url)
397
+
398
+ assert_equal('12345%7D=ASDFWEE345%3DASda', cookie.to_s)
399
+ assert_equal('/', cookie.path)
400
+
401
+ assert_equal(keys.include?('expires') ? @expires : nil, cookie.expires)
402
+ assert_equal(keys.include?('httponly'), cookie.httponly?)
403
+ end
404
+ end
405
+
406
+ def test_new
407
+ cookie = HTTP::Cookie.new('key', 'value')
408
+ assert_equal 'key', cookie.name
409
+ assert_equal 'value', cookie.value
410
+ assert_equal nil, cookie.expires
411
+
412
+ # Minimum unit for the expires attribute is second
413
+ expires = Time.at((Time.now + 3600).to_i)
414
+
415
+ cookie = HTTP::Cookie.new('key', 'value', :expires => expires.dup)
416
+ assert_equal 'key', cookie.name
417
+ assert_equal 'value', cookie.value
418
+ assert_equal expires, cookie.expires
419
+
420
+ cookie = HTTP::Cookie.new(:value => 'value', :name => 'key', :expires => expires.dup)
421
+ assert_equal 'key', cookie.name
422
+ assert_equal 'value', cookie.value
423
+ assert_equal expires, cookie.expires
424
+
425
+ cookie = HTTP::Cookie.new(:value => 'value', :name => 'key', :expires => expires.dup, :domain => 'example.org', :for_domain? => true)
426
+ assert_equal 'key', cookie.name
427
+ assert_equal 'value', cookie.value
428
+ assert_equal expires, cookie.expires
429
+ assert_equal 'example.org', cookie.domain
430
+ assert_equal true, cookie.for_domain?
431
+
432
+ assert_raises(ArgumentError) { HTTP::Cookie.new(:name => 'name') }
433
+ assert_raises(ArgumentError) { HTTP::Cookie.new(:value => 'value') }
434
+ assert_raises(ArgumentError) { HTTP::Cookie.new('', 'value') }
435
+ assert_raises(ArgumentError) { HTTP::Cookie.new('key=key', 'value') }
436
+ assert_raises(ArgumentError) { HTTP::Cookie.new("key\tkey", 'value') }
437
+ end
438
+
439
+ def cookie_values(options = {})
440
+ {
441
+ :name => 'Foo',
442
+ :value => 'Bar',
443
+ :path => '/',
444
+ :expires => Time.now + (10 * 86400),
445
+ :for_domain => true,
446
+ :domain => 'rubyforge.org',
447
+ :origin => 'http://rubyforge.org/'
448
+ }.merge(options)
449
+ end
450
+
451
+ def test_compare
452
+ time = Time.now
453
+ cookies = [
454
+ { :created_at => time + 1 },
455
+ { :created_at => time - 1 },
456
+ { :created_at => time },
457
+ { :created_at => time, :path => '/foo/bar/' },
458
+ { :created_at => time, :path => '/foo/' },
459
+ ].map { |attrs| HTTP::Cookie.new(cookie_values(attrs)) }
460
+
461
+ assert_equal([3, 4, 1, 2, 0], cookies.sort.map { |i|
462
+ cookies.find_index { |j| j.equal?(i) }
463
+ })
464
+ end
465
+
466
+ def test_expiration
467
+ cookie = HTTP::Cookie.new(cookie_values)
468
+
469
+ assert_equal false, cookie.expired?
470
+ assert_equal true, cookie.expired?(cookie.expires + 1)
471
+ assert_equal false, cookie.expired?(cookie.expires - 1)
472
+ cookie.expire
473
+ assert_equal true, cookie.expired?
474
+ end
475
+
476
+ def test_equal
477
+ assert_not_equal(HTTP::Cookie.new(cookie_values),
478
+ HTTP::Cookie.new(cookie_values(:value => 'bar')))
479
+ end
480
+
481
+ def test_new_rejects_cookies_that_do_not_contain_an_embedded_dot
482
+ url = URI 'http://rubyforge.org/'
483
+
484
+ assert_raises(ArgumentError) {
485
+ tld_cookie = HTTP::Cookie.new(cookie_values(:domain => '.org', :origin => url))
486
+ }
487
+ assert_raises(ArgumentError) {
488
+ single_dot_cookie = HTTP::Cookie.new(cookie_values(:domain => '.', :origin => url))
489
+ }
490
+ end
491
+
492
+ def test_fall_back_rules_for_local_domains
493
+ url = URI 'http://www.example.local'
494
+
495
+ assert_raises(ArgumentError) {
496
+ tld_cookie = HTTP::Cookie.new(cookie_values(:domain => '.local', :origin => url))
497
+ }
498
+
499
+ sld_cookie = HTTP::Cookie.new(cookie_values(:domain => '.example.local', :origin => url))
500
+ end
501
+
502
+ def test_new_rejects_cookies_with_ipv4_address_subdomain
503
+ url = URI 'http://192.168.0.1/'
504
+
505
+ assert_raises(ArgumentError) {
506
+ cookie = HTTP::Cookie.new(cookie_values(:domain => '.0.1', :origin => url))
507
+ }
508
+ end
509
+
510
+ def test_domain_nil
511
+ cookie = HTTP::Cookie.parse('a=b').first
512
+ assert_raises(RuntimeError) {
513
+ cookie.valid_for_uri?('http://example.com/')
514
+ }
515
+ end
516
+
517
+ def test_domain=
518
+ url = URI.parse('http://host.dom.example.com:8080/')
519
+
520
+ cookie_str = 'a=b; domain=Example.Com'
521
+ cookie = HTTP::Cookie.parse(cookie_str, :origin => url).first
522
+ assert 'example.com', cookie.domain
523
+
524
+ cookie.domain = DomainName(url.host)
525
+ assert 'host.dom.example.com', cookie.domain
526
+
527
+ cookie.domain = 'Dom.example.com'
528
+ assert 'dom.example.com', cookie.domain
529
+
530
+ cookie.domain = Object.new.tap { |o|
531
+ def o.to_str
532
+ 'Example.com'
533
+ end
534
+ }
535
+ assert 'example.com', cookie.domain
536
+ end
537
+
538
+ def test_origin=
539
+ url = URI.parse('http://example.com/path/')
540
+
541
+ cookie_str = 'a=b'
542
+ cookie = HTTP::Cookie.parse(cookie_str).first
543
+ cookie.origin = url
544
+ assert_equal '/path/', cookie.path
545
+ assert_equal 'example.com', cookie.domain
546
+ assert_equal false, cookie.for_domain
547
+ assert_raises(ArgumentError) {
548
+ cookie.origin = URI.parse('http://www.example.com/')
549
+ }
550
+
551
+ cookie_str = 'a=b; domain=.example.com; path=/'
552
+ cookie = HTTP::Cookie.parse(cookie_str).first
553
+ cookie.origin = url
554
+ assert_equal '/', cookie.path
555
+ assert_equal 'example.com', cookie.domain
556
+ assert_equal true, cookie.for_domain
557
+ assert_raises(ArgumentError) {
558
+ cookie.origin = URI.parse('http://www.example.com/')
559
+ }
560
+
561
+ cookie_str = 'a=b; domain=example.com'
562
+ cookie = HTTP::Cookie.parse(cookie_str).first
563
+ assert_raises(ArgumentError) {
564
+ cookie.origin = URI.parse('http://example.org/')
565
+ }
566
+ end
567
+
568
+ def test_valid_for_uri?
569
+ cookie = HTTP::Cookie.parse('a=b', :origin => URI('http://example.com/dir/file.html')).first
570
+ assert_equal true, cookie.valid_for_uri?(URI('https://example.com/dir/test.html'))
571
+ assert_equal true, cookie.valid_for_uri?('https://example.com/dir/test.html')
572
+ assert_equal true, cookie.valid_for_uri?(URI('http://example.com/dir/test.html'))
573
+ assert_equal false, cookie.valid_for_uri?(URI('https://example.com/dir2/test.html'))
574
+ assert_equal false, cookie.valid_for_uri?(URI('http://example.com/dir2/test.html'))
575
+ assert_equal false, cookie.valid_for_uri?(URI('https://www.example.com/dir/test.html'))
576
+ assert_equal false, cookie.valid_for_uri?(URI('http://www.example.com/dir/test.html'))
577
+ assert_equal false, cookie.valid_for_uri?(URI('https://www.example.com/dir2/test.html'))
578
+ assert_equal false, cookie.valid_for_uri?(URI('http://www.example.com/dir2/test.html'))
579
+
580
+ cookie = HTTP::Cookie.parse('a=b; path=/dir2/', :origin => URI('http://example.com/dir/file.html')).first
581
+ assert_equal false, cookie.valid_for_uri?(URI('https://example.com/dir/test.html'))
582
+ assert_equal false, cookie.valid_for_uri?(URI('http://example.com/dir/test.html'))
583
+ assert_equal true, cookie.valid_for_uri?(URI('https://example.com/dir2/test.html'))
584
+ assert_equal true, cookie.valid_for_uri?(URI('http://example.com/dir2/test.html'))
585
+ assert_equal false, cookie.valid_for_uri?(URI('https://www.example.com/dir/test.html'))
586
+ assert_equal false, cookie.valid_for_uri?(URI('http://www.example.com/dir/test.html'))
587
+ assert_equal false, cookie.valid_for_uri?(URI('https://www.example.com/dir2/test.html'))
588
+ assert_equal false, cookie.valid_for_uri?(URI('http://www.example.com/dir2/test.html'))
589
+
590
+ cookie = HTTP::Cookie.parse('a=b; domain=example.com; path=/dir2/', :origin => URI('http://example.com/dir/file.html')).first
591
+ assert_equal false, cookie.valid_for_uri?(URI('https://example.com/dir/test.html'))
592
+ assert_equal false, cookie.valid_for_uri?(URI('http://example.com/dir/test.html'))
593
+ assert_equal true, cookie.valid_for_uri?(URI('https://example.com/dir2/test.html'))
594
+ assert_equal true, cookie.valid_for_uri?(URI('http://example.com/dir2/test.html'))
595
+ assert_equal false, cookie.valid_for_uri?(URI('https://www.example.com/dir/test.html'))
596
+ assert_equal false, cookie.valid_for_uri?(URI('http://www.example.com/dir/test.html'))
597
+ assert_equal true, cookie.valid_for_uri?(URI('https://www.example.com/dir2/test.html'))
598
+ assert_equal true, cookie.valid_for_uri?(URI('http://www.example.com/dir2/test.html'))
599
+
600
+ cookie = HTTP::Cookie.parse('a=b; secure', :origin => URI('https://example.com/dir/file.html')).first
601
+ assert_equal true, cookie.valid_for_uri?(URI('https://example.com/dir/test.html'))
602
+ assert_equal false, cookie.valid_for_uri?(URI('http://example.com/dir/test.html'))
603
+ assert_equal false, cookie.valid_for_uri?(URI('https://example.com/dir2/test.html'))
604
+ assert_equal false, cookie.valid_for_uri?(URI('http://example.com/dir2/test.html'))
605
+
606
+ cookie = HTTP::Cookie.parse('a=b', :origin => URI('https://example.com/')).first
607
+ assert_equal true, cookie.valid_for_uri?(URI('https://example.com'))
608
+ end
609
+
610
+ def test_migration
611
+ assert_raises_with_message(ArgumentError, /equivalent/) {
612
+ HTTP::Cookie.parse('http://example.com/', 'key=value')
613
+ }
614
+ assert_raises_with_message(ArgumentError, /equivalent/) {
615
+ HTTP::Cookie.parse('http://example.com/', 'key=value', Object.new)
616
+ }
617
+
618
+ cookie = HTTP::Cookie.new('key', 'value')
619
+ assert_raises_with_message(NoMethodError, /equivalent/) {
620
+ cookie.set_domain('www.example.com')
621
+ }
622
+ end
623
+ end
624
+