http-cookie 1.0.0.pre10 → 1.0.0.pre11
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +48 -15
- data/lib/http/cookie.rb +124 -101
- data/lib/http/cookie/ruby_compat.rb +59 -0
- data/lib/http/cookie/scanner.rb +37 -8
- data/lib/http/cookie/version.rb +1 -1
- data/lib/http/cookie_jar.rb +34 -17
- data/lib/http/cookie_jar/abstract_saver.rb +1 -1
- data/lib/http/cookie_jar/abstract_store.rb +1 -1
- data/lib/http/cookie_jar/hash_store.rb +2 -2
- data/lib/http/cookie_jar/mozilla_store.rb +3 -3
- data/test/test_http_cookie.rb +112 -4
- data/test/test_http_cookie_jar.rb +137 -18
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 74a442b5c8222376568f11b2ed2f3ff948cb297a
|
4
|
+
data.tar.gz: 27b3d634fdd2e75bff0302f89463b5ed777e936f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 48ee26913f44add403e4d620e75b6f64156efaf23b37ab30e7c10543bd765a12adaeb25ff7f6c666410b82d291457f049d718ae4d802906be53db5a28638b89c
|
7
|
+
data.tar.gz: 7703dd086e0802411ab9e7ee9c12278a3321a41a0fcecdb203a6de3e2848c5c73e6e5a4141ccb01f65e165e1f80a3c8b3ea1a60be3505bb5ea1bcfa2bf55fc59
|
data/README.md
CHANGED
@@ -25,7 +25,7 @@ Or install it yourself as:
|
|
25
25
|
## Usage
|
26
26
|
|
27
27
|
########################
|
28
|
-
# Client side example
|
28
|
+
# Client side example 1
|
29
29
|
########################
|
30
30
|
|
31
31
|
# Initialize a cookie jar
|
@@ -34,30 +34,60 @@ Or install it yourself as:
|
|
34
34
|
# Load from a file
|
35
35
|
jar.load(filename) if File.exist?(filename)
|
36
36
|
|
37
|
-
# Store received cookies
|
38
|
-
|
39
|
-
jar
|
37
|
+
# Store received cookies, where uri is the origin of this header
|
38
|
+
header["Set-Cookie"].each { |value|
|
39
|
+
jar.parse(value, uri)
|
40
40
|
}
|
41
41
|
|
42
|
-
#
|
43
|
-
|
42
|
+
# ...
|
43
|
+
|
44
|
+
# Set the Cookie header value, where uri is the destination URI
|
45
|
+
header["Cookie"] = HTTP::Cookie.cookie_value(jar.cookies(uri))
|
44
46
|
|
45
47
|
# Save to a file
|
46
48
|
jar.save(filename)
|
47
49
|
|
48
50
|
|
51
|
+
########################
|
52
|
+
# Client side example 2
|
53
|
+
########################
|
54
|
+
|
55
|
+
# Initialize a cookie jar using a Mozilla compatible SQLite3 backend
|
56
|
+
jar = HTTP::CookieJar.new(store: :mozilla, filename: 'cookies.sqlite')
|
57
|
+
|
58
|
+
# There is no need for load & save in this backend.
|
59
|
+
|
60
|
+
# Store received cookies, where uri is the origin of this header
|
61
|
+
header["Set-Cookie"].each { |value|
|
62
|
+
jar.parse(value, uri)
|
63
|
+
}
|
64
|
+
|
65
|
+
# ...
|
66
|
+
|
67
|
+
# Set the Cookie header value, where uri is the destination URI
|
68
|
+
header["Cookie"] = HTTP::Cookie.cookie_value(jar.cookies(uri))
|
69
|
+
|
70
|
+
|
49
71
|
########################
|
50
72
|
# Server side example
|
51
73
|
########################
|
52
74
|
|
53
|
-
# Generate a cookie
|
54
|
-
|
75
|
+
# Generate a domain cookie
|
76
|
+
cookie1 = HTTP::Cookie.new("uid", "u12345", domain: 'example.org',
|
55
77
|
for_domain: true,
|
56
78
|
path: '/',
|
57
79
|
max_age: 7*86400)
|
58
80
|
|
59
|
-
#
|
60
|
-
|
81
|
+
# Add it to the Set-Cookie response header
|
82
|
+
header['Set-Cookie'] = cookie1.set_cookie_value
|
83
|
+
|
84
|
+
# Generate a host-only cookie
|
85
|
+
cookie2 = HTTP::Cookie.new("aid", "a12345", origin: my_url,
|
86
|
+
path: '/',
|
87
|
+
max_age: 7*86400)
|
88
|
+
|
89
|
+
# Add it to the Set-Cookie response header
|
90
|
+
header['Set-Cookie'] = cookie2.set_cookie_value
|
61
91
|
|
62
92
|
|
63
93
|
## Incompatibilities with Mechanize::Cookie/CookieJar
|
@@ -77,14 +107,17 @@ equivalent using HTTP::Cookie:
|
|
77
107
|
|
78
108
|
# after
|
79
109
|
cookies1 = HTTP::Cookie.parse(set_cookie1, uri_or_url)
|
80
|
-
cookies2 = HTTP::Cookie.parse(set_cookie2, uri_or_url, :
|
110
|
+
cookies2 = HTTP::Cookie.parse(set_cookie2, uri_or_url, logger: log)
|
111
|
+
# or you can directly store parsed cookies in your jar
|
112
|
+
jar.parse(set_cookie1, uri_or_url)
|
113
|
+
jar.parse(set_cookie1, uri_or_url, logger: log)
|
81
114
|
|
82
115
|
- Mechanize::Cookie#version, #version=
|
83
116
|
|
84
|
-
There is no longer a sense of version in HTTP cookie
|
85
|
-
version number
|
86
|
-
be no other version since the version attribute
|
87
|
-
in RFC 6265.
|
117
|
+
There is no longer a sense of version in the HTTP cookie
|
118
|
+
specification. The only version number ever defined was zero, and
|
119
|
+
there will be no other version defined since the version attribute
|
120
|
+
has been removed in RFC 6265.
|
88
121
|
|
89
122
|
- Mechanize::Cookie#comment, #comment=
|
90
123
|
|
data/lib/http/cookie.rb
CHANGED
@@ -3,29 +3,12 @@ require 'http/cookie/version'
|
|
3
3
|
require 'time'
|
4
4
|
require 'uri'
|
5
5
|
require 'domain_name'
|
6
|
+
require 'http/cookie/ruby_compat'
|
6
7
|
|
7
8
|
module HTTP
|
8
9
|
autoload :CookieJar, 'http/cookie_jar'
|
9
10
|
end
|
10
11
|
|
11
|
-
# In Ruby < 1.9.3 URI() does not accept a URI object.
|
12
|
-
if RUBY_VERSION < "1.9.3"
|
13
|
-
begin
|
14
|
-
URI(URI(''))
|
15
|
-
rescue
|
16
|
-
def URI(url) # :nodoc:
|
17
|
-
case url
|
18
|
-
when URI
|
19
|
-
url
|
20
|
-
when String
|
21
|
-
URI.parse(url)
|
22
|
-
else
|
23
|
-
raise ArgumentError, 'bad argument (expected URI object or URI string)'
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
12
|
# This class is used to represent an HTTP Cookie.
|
30
13
|
class HTTP::Cookie
|
31
14
|
# Maximum number of bytes per cookie (RFC 6265 6.1 requires 4096 at
|
@@ -48,31 +31,13 @@ class HTTP::Cookie
|
|
48
31
|
expires max_age
|
49
32
|
created_at accessed_at
|
50
33
|
]
|
51
|
-
|
52
|
-
if String.respond_to?(:try_convert)
|
53
|
-
def check_string_type(object)
|
54
|
-
String.try_convert(object)
|
55
|
-
end
|
56
|
-
private :check_string_type
|
57
|
-
else
|
58
|
-
def check_string_type(object)
|
59
|
-
if object.is_a?(String) ||
|
60
|
-
(object.respond_to?(:to_str) && (object = object.to_str).is_a?(String))
|
61
|
-
object
|
62
|
-
else
|
63
|
-
nil
|
64
|
-
end
|
65
|
-
end
|
66
|
-
private :check_string_type
|
67
|
-
end
|
68
34
|
# :startdoc:
|
69
35
|
|
70
36
|
# The cookie name. It may not be nil or empty.
|
71
37
|
#
|
72
|
-
#
|
73
|
-
# ArgumentError
|
74
|
-
#
|
75
|
-
# `,;\"=`.
|
38
|
+
# Assign a string containing any of the following characters will
|
39
|
+
# raise ArgumentError: control characters (`\x00-\x1F` and `\x7F`),
|
40
|
+
# space and separators `,;\"=`.
|
76
41
|
#
|
77
42
|
# Note that RFC 6265 4.1.1 lists more characters disallowed for use
|
78
43
|
# in a cookie name, which are these: `<>@:/[]?{}`. Using these
|
@@ -82,9 +47,12 @@ class HTTP::Cookie
|
|
82
47
|
|
83
48
|
# The cookie value.
|
84
49
|
#
|
85
|
-
#
|
86
|
-
#
|
87
|
-
#
|
50
|
+
# Assign a string containing a control character (`\x00-\x1F` and
|
51
|
+
# `\x7F`) will raise ArgumentError.
|
52
|
+
#
|
53
|
+
# Assigning nil sets the value to an empty string and the expiration
|
54
|
+
# date to the Unix epoch. This is a handy way to make a cookie for
|
55
|
+
# expiration.
|
88
56
|
#
|
89
57
|
# Note that RFC 6265 4.1.1 lists more characters disallowed for use
|
90
58
|
# in a cookie value, which are these: ` ",;\`. Using these
|
@@ -138,18 +106,21 @@ class HTTP::Cookie
|
|
138
106
|
# :attr_accessor: max_age
|
139
107
|
|
140
108
|
# :call-seq:
|
141
|
-
# new(name, value)
|
142
|
-
# new(name, value, attr_hash)
|
143
|
-
# new(attr_hash)
|
109
|
+
# new(name, value = nil)
|
110
|
+
# new(name, value = nil, **attr_hash)
|
111
|
+
# new(**attr_hash)
|
144
112
|
#
|
145
113
|
# Creates a cookie object. For each key of `attr_hash`, the setter
|
146
114
|
# is called if defined. Each key can be either a symbol or a
|
147
|
-
# string
|
115
|
+
# string of downcased attribute names.
|
148
116
|
#
|
149
117
|
# This methods accepts any attribute name for which a setter method
|
150
118
|
# is defined. Beware, however, any error (typically ArgumentError)
|
151
119
|
# a setter method raises will be passed through.
|
152
120
|
#
|
121
|
+
# If `value` is omitted or it is nil, an expiration cookie is
|
122
|
+
# created unless `max_age` or `expires` (`expires_at`) is given.
|
123
|
+
#
|
153
124
|
# e.g.
|
154
125
|
#
|
155
126
|
# new("uid", "a12345")
|
@@ -160,51 +131,82 @@ class HTTP::Cookie
|
|
160
131
|
def initialize(*args)
|
161
132
|
@origin = @domain = @path =
|
162
133
|
@expires = @max_age = nil
|
163
|
-
@secure = @httponly = false
|
134
|
+
@for_domain = @secure = @httponly = false
|
164
135
|
@session = true
|
165
136
|
@created_at = @accessed_at = Time.now
|
166
|
-
|
167
|
-
case args.size
|
168
|
-
when 2
|
169
|
-
self.name, self.value = *args
|
170
|
-
@for_domain = false
|
171
|
-
return
|
172
|
-
when 3
|
173
|
-
self.name, self.value, attr_hash = *args
|
137
|
+
case argc = args.size
|
174
138
|
when 1
|
175
|
-
attr_hash = args.
|
139
|
+
if attr_hash = Hash.try_convert(args.last)
|
140
|
+
args.pop
|
141
|
+
else
|
142
|
+
self.name, self.value = args # value is set to nil
|
143
|
+
return
|
144
|
+
end
|
145
|
+
when 2..3
|
146
|
+
if attr_hash = Hash.try_convert(args.last)
|
147
|
+
args.pop
|
148
|
+
self.name, value = args
|
149
|
+
else
|
150
|
+
argc == 2 or
|
151
|
+
raise ArgumentError, "wrong number of arguments (#{argc} for 1-3)"
|
152
|
+
self.name, self.value = args
|
153
|
+
return
|
154
|
+
end
|
176
155
|
else
|
177
|
-
raise ArgumentError, "wrong number of arguments (#{
|
156
|
+
raise ArgumentError, "wrong number of arguments (#{argc} for 1-3)"
|
178
157
|
end
|
179
158
|
for_domain = false
|
180
159
|
domain = max_age = origin = nil
|
181
160
|
attr_hash.each_pair { |key, val|
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
when
|
188
|
-
for_domain = !!val
|
189
|
-
when 'domain'
|
161
|
+
case key.to_sym
|
162
|
+
when :name
|
163
|
+
self.name = val
|
164
|
+
when :value
|
165
|
+
value = val
|
166
|
+
when :domain
|
190
167
|
domain = val
|
191
|
-
when
|
168
|
+
when :path
|
169
|
+
self.path = val
|
170
|
+
when :origin
|
192
171
|
origin = val
|
193
|
-
when
|
172
|
+
when :for_domain, :for_domain?
|
173
|
+
for_domain = val
|
174
|
+
when :max_age
|
194
175
|
# Let max_age take precedence over expires
|
195
176
|
max_age = val
|
177
|
+
when :expires, :expires_at
|
178
|
+
self.expires = val
|
179
|
+
when :httponly, :httponly?
|
180
|
+
@httponly = val
|
181
|
+
when :secure, :secure?
|
182
|
+
@secure = val
|
183
|
+
when /[A-Z]/
|
184
|
+
warn "keyword should be downcased: #{key}" if $VERBOSE
|
185
|
+
key = key.downcase
|
186
|
+
redo
|
187
|
+
when Symbol
|
188
|
+
setter = :"#{key}="
|
189
|
+
if respond_to?(setter)
|
190
|
+
__send__(setter, val)
|
191
|
+
else
|
192
|
+
warn "unknown keyword: #{key}" if $VERBOSE
|
193
|
+
end
|
194
|
+
when String
|
195
|
+
key = key.to_sym
|
196
|
+
redo
|
196
197
|
else
|
197
|
-
|
198
|
-
|
198
|
+
key = key.to_s
|
199
|
+
redo
|
199
200
|
end
|
200
201
|
}
|
201
|
-
if @name.nil?
|
202
|
-
raise ArgumentError, "
|
202
|
+
if @name.nil?
|
203
|
+
raise ArgumentError, "name must be specified"
|
203
204
|
end
|
204
205
|
@for_domain = for_domain
|
205
206
|
self.domain = domain if domain
|
206
207
|
self.origin = origin if origin
|
207
208
|
self.max_age = max_age if max_age
|
209
|
+
self.value = value.nil? && (@expires || @max_age) ? '' : value
|
208
210
|
end
|
209
211
|
|
210
212
|
autoload :Scanner, 'http/cookie/scanner'
|
@@ -238,11 +240,10 @@ class HTTP::Cookie
|
|
238
240
|
target_path[bsize] == ?/
|
239
241
|
end
|
240
242
|
|
241
|
-
# Parses a Set-Cookie header value `set_cookie`
|
242
|
-
#
|
243
|
-
# (separated by commas) that are malformed
|
244
|
-
#
|
245
|
-
# allowed to issue are excluded from the resulted array.
|
243
|
+
# Parses a Set-Cookie header value `set_cookie` assuming that it
|
244
|
+
# is sent from a source URI/URL `origin`, and returns an array of
|
245
|
+
# Cookie objects. Parts (separated by commas) that are malformed
|
246
|
+
# or considered unacceptable are silently ignored.
|
246
247
|
#
|
247
248
|
# If a block is given, each cookie object is passed to the block.
|
248
249
|
#
|
@@ -280,9 +281,7 @@ class HTTP::Cookie
|
|
280
281
|
origin = URI(origin)
|
281
282
|
|
282
283
|
[].tap { |cookies|
|
283
|
-
|
284
|
-
until s.eos?
|
285
|
-
name, value, attrs = s.scan_cookie
|
284
|
+
Scanner.new(set_cookie, logger).scan_set_cookie { |name, value, attrs|
|
286
285
|
break if name.nil? || name.empty?
|
287
286
|
|
288
287
|
cookie = new(name, value)
|
@@ -319,7 +318,24 @@ class HTTP::Cookie
|
|
319
318
|
yield cookie if block_given?
|
320
319
|
|
321
320
|
cookies << cookie
|
322
|
-
|
321
|
+
}
|
322
|
+
}
|
323
|
+
end
|
324
|
+
|
325
|
+
# Takes an array of cookies and returns a string for use in the
|
326
|
+
# Cookie header, like "name1=value2; name2=value2".
|
327
|
+
def cookie_value(cookies)
|
328
|
+
cookies.join('; ')
|
329
|
+
end
|
330
|
+
|
331
|
+
# Parses a Cookie header value into a hash of name-value string
|
332
|
+
# pairs. The first appearance takes precedence if multiple pairs
|
333
|
+
# with the same name occur.
|
334
|
+
def cookie_value_to_hash(cookie_value)
|
335
|
+
{}.tap { |hash|
|
336
|
+
Scanner.new(cookie_value).scan_cookie { |name, value|
|
337
|
+
hash[name] ||= value
|
338
|
+
}
|
323
339
|
}
|
324
340
|
end
|
325
341
|
end
|
@@ -328,7 +344,7 @@ class HTTP::Cookie
|
|
328
344
|
|
329
345
|
# See #name.
|
330
346
|
def name=(name)
|
331
|
-
name =
|
347
|
+
name = String.try_convert(name) or
|
332
348
|
raise TypeError, "#{name.class} is not a String"
|
333
349
|
if name.empty?
|
334
350
|
raise ArgumentError, "cookie name cannot be empty"
|
@@ -345,7 +361,11 @@ class HTTP::Cookie
|
|
345
361
|
|
346
362
|
# See #value.
|
347
363
|
def value=(value)
|
348
|
-
|
364
|
+
if value.nil?
|
365
|
+
self.expires = UNIX_EPOCH
|
366
|
+
return @value = ''
|
367
|
+
end
|
368
|
+
value = String.try_convert(value) or
|
349
369
|
raise TypeError, "#{value.class} is not a String"
|
350
370
|
if value.match(/[\x00-\x1F\x7F]/)
|
351
371
|
raise ArgumentError, "invalid cookie value"
|
@@ -373,7 +393,7 @@ class HTTP::Cookie
|
|
373
393
|
when DomainName
|
374
394
|
@domain_name = domain
|
375
395
|
else
|
376
|
-
domain =
|
396
|
+
domain = String.try_convert(domain) or
|
377
397
|
raise TypeError, "#{domain.class} is not a String"
|
378
398
|
if domain.start_with?('.')
|
379
399
|
for_domain = true
|
@@ -418,7 +438,7 @@ class HTTP::Cookie
|
|
418
438
|
|
419
439
|
# See #path.
|
420
440
|
def path=(path)
|
421
|
-
path =
|
441
|
+
path = String.try_convert(path) or
|
422
442
|
raise TypeError, "#{path.class} is not a String"
|
423
443
|
@path = path.start_with?('/') ? path : '/'
|
424
444
|
end
|
@@ -484,7 +504,7 @@ class HTTP::Cookie
|
|
484
504
|
case sec
|
485
505
|
when Integer, nil
|
486
506
|
else
|
487
|
-
str =
|
507
|
+
str = String.try_convert(sec) or
|
488
508
|
raise TypeError, "#{sec.class} is not an Integer or String"
|
489
509
|
/\A-?\d+\z/.match(str) or
|
490
510
|
raise ArgumentError, "invalid Max-Age: #{sec.inspect}"
|
@@ -566,29 +586,32 @@ class HTTP::Cookie
|
|
566
586
|
acceptable_from_uri?(uri) && HTTP::Cookie.path_match?(@path, uri.path)
|
567
587
|
end
|
568
588
|
|
569
|
-
# Returns a string for use in
|
570
|
-
#
|
589
|
+
# Returns a string for use in the Cookie header, i.e. `name=value`
|
590
|
+
# or `name="value"`.
|
571
591
|
def cookie_value
|
572
592
|
"#{@name}=#{Scanner.quote(@value)}"
|
573
593
|
end
|
574
594
|
alias to_s cookie_value
|
575
595
|
|
576
|
-
# Returns a string for use in
|
577
|
-
#
|
578
|
-
#
|
579
|
-
#
|
580
|
-
|
581
|
-
# the origin.
|
582
|
-
def set_cookie_value(origin = nil)
|
583
|
-
origin = origin ? URI(origin) : @origin or
|
584
|
-
raise "origin must be specified to produce a value for Set-Cookie"
|
585
|
-
|
596
|
+
# Returns a string for use in the Set-Cookie header. If necessary
|
597
|
+
# information like a path or domain (when `for_domain` is set) is
|
598
|
+
# missing, RuntimeError is raised. It is always the best to set an
|
599
|
+
# origin before calling this method.
|
600
|
+
def set_cookie_value
|
586
601
|
string = cookie_value
|
587
602
|
if @for_domain
|
588
|
-
|
603
|
+
if @domain
|
604
|
+
string << "; Domain=#{@domain}"
|
605
|
+
else
|
606
|
+
raise "for_domain is specified but domain is known"
|
607
|
+
end
|
589
608
|
end
|
590
|
-
if
|
591
|
-
|
609
|
+
if @path
|
610
|
+
if !@origin || (@origin + './').path != @path
|
611
|
+
string << "; Path=#{@path}"
|
612
|
+
end
|
613
|
+
else
|
614
|
+
raise "path is known"
|
592
615
|
end
|
593
616
|
if @max_age
|
594
617
|
string << "; Max-Age=#{@max_age}"
|
@@ -608,7 +631,6 @@ class HTTP::Cookie
|
|
608
631
|
'#<%s:' % self.class << PERSISTENT_PROPERTIES.map { |key|
|
609
632
|
'%s=%s' % [key, instance_variable_get(:"@#{key}").inspect]
|
610
633
|
}.join(', ') << ' origin=%s>' % [@origin ? @origin.to_s : 'nil']
|
611
|
-
|
612
634
|
end
|
613
635
|
|
614
636
|
# Compares the cookie with another. When there are many cookies with
|
@@ -643,6 +665,7 @@ class HTTP::Cookie
|
|
643
665
|
# YAML deserialization helper for Psych.
|
644
666
|
def yaml_initialize(tag, map)
|
645
667
|
expires = nil
|
668
|
+
@origin = nil
|
646
669
|
map.each { |key, value|
|
647
670
|
case key
|
648
671
|
when 'expires'
|
@@ -0,0 +1,59 @@
|
|
1
|
+
class Array
|
2
|
+
def select!
|
3
|
+
i = 0
|
4
|
+
each_with_index { |x, j|
|
5
|
+
yield x or next
|
6
|
+
self[i] = x if i != j
|
7
|
+
i += 1
|
8
|
+
}
|
9
|
+
return nil if i == size
|
10
|
+
self[i..-1] = []
|
11
|
+
self
|
12
|
+
end unless method_defined?(:select!)
|
13
|
+
end
|
14
|
+
|
15
|
+
class Hash
|
16
|
+
class << self
|
17
|
+
def try_convert(object)
|
18
|
+
if object.is_a?(Hash) ||
|
19
|
+
(object.respond_to?(:to_hash) && (object = object.to_hash).is_a?(Hash))
|
20
|
+
object
|
21
|
+
else
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
end unless method_defined?(:try_convert)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class String
|
29
|
+
class << self
|
30
|
+
def try_convert(object)
|
31
|
+
if object.is_a?(String) ||
|
32
|
+
(object.respond_to?(:to_str) && (object = object.to_str).is_a?(String))
|
33
|
+
object
|
34
|
+
else
|
35
|
+
nil
|
36
|
+
end
|
37
|
+
end unless method_defined?(:try_convert)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# In Ruby < 1.9.3 URI() does not accept a URI object.
|
42
|
+
if RUBY_VERSION < "1.9.3"
|
43
|
+
require 'uri'
|
44
|
+
|
45
|
+
begin
|
46
|
+
URI(URI(''))
|
47
|
+
rescue
|
48
|
+
def URI(url) # :nodoc:
|
49
|
+
case url
|
50
|
+
when URI
|
51
|
+
url
|
52
|
+
when String
|
53
|
+
URI.parse(url)
|
54
|
+
else
|
55
|
+
raise ArgumentError, 'bad argument (expected URI object or URI string)'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/lib/http/cookie/scanner.rb
CHANGED
@@ -143,15 +143,23 @@ class HTTP::Cookie::Scanner < StringScanner
|
|
143
143
|
year += 2000
|
144
144
|
end
|
145
145
|
|
146
|
-
|
146
|
+
hh, mm, ss = time
|
147
|
+
if hh > 23 || mm > 59 || ss > 59
|
147
148
|
return nil
|
148
149
|
end
|
149
150
|
|
150
151
|
tuple_to_time(day_of_month, month, year, time)
|
151
152
|
end
|
152
153
|
|
153
|
-
def
|
154
|
-
|
154
|
+
def scan_set_cookie
|
155
|
+
unless block_given?
|
156
|
+
scan_set_cookie { |*values|
|
157
|
+
return values
|
158
|
+
}
|
159
|
+
return
|
160
|
+
end
|
161
|
+
|
162
|
+
# RFC 6265 4.1.1 & 5.2
|
155
163
|
until eos?
|
156
164
|
start = pos
|
157
165
|
len = nil
|
@@ -159,9 +167,7 @@ class HTTP::Cookie::Scanner < StringScanner
|
|
159
167
|
skip_wsp
|
160
168
|
|
161
169
|
name, value = scan_name_value
|
162
|
-
if
|
163
|
-
break
|
164
|
-
elsif value.nil?
|
170
|
+
if value.nil?
|
165
171
|
@logger.warn("Cookie definition lacks a name-value pair.") if @logger
|
166
172
|
elsif name.empty?
|
167
173
|
@logger.warn("Cookie definition has an empty name.") if @logger
|
@@ -171,12 +177,13 @@ class HTTP::Cookie::Scanner < StringScanner
|
|
171
177
|
|
172
178
|
case
|
173
179
|
when skip(/,/)
|
180
|
+
# The comma is used as separator for concatenating multiple
|
181
|
+
# values of a header.
|
174
182
|
len = (pos - 1) - start
|
175
183
|
break
|
176
184
|
when skip(/;/)
|
177
185
|
skip_wsp
|
178
186
|
aname, avalue = scan_name_value
|
179
|
-
break if aname.nil?
|
180
187
|
next if aname.empty? || value.nil?
|
181
188
|
aname.downcase!
|
182
189
|
case aname
|
@@ -209,7 +216,29 @@ class HTTP::Cookie::Scanner < StringScanner
|
|
209
216
|
next
|
210
217
|
end
|
211
218
|
|
212
|
-
|
219
|
+
yield name, value, attrs if value
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
def scan_cookie
|
224
|
+
unless block_given?
|
225
|
+
scan_cookie { |*values|
|
226
|
+
return values
|
227
|
+
}
|
228
|
+
return
|
229
|
+
end
|
230
|
+
|
231
|
+
# RFC 6265 4.1.1 & 5.4
|
232
|
+
until eos?
|
233
|
+
skip_wsp
|
234
|
+
|
235
|
+
name, value = scan_name_value
|
236
|
+
|
237
|
+
yield name, value if value
|
238
|
+
|
239
|
+
# The comma is used as separator for concatenating multiple
|
240
|
+
# values of a header.
|
241
|
+
skip(/[;,]/)
|
213
242
|
end
|
214
243
|
end
|
215
244
|
end
|
data/lib/http/cookie/version.rb
CHANGED
data/lib/http/cookie_jar.rb
CHANGED
@@ -49,6 +49,10 @@ class HTTP::CookieJar
|
|
49
49
|
# any case. A given cookie must have domain and path attributes
|
50
50
|
# set, or ArgumentError is raised.
|
51
51
|
#
|
52
|
+
# Whether a cookie with the `for_domain` flag on overwrites another
|
53
|
+
# with the flag off or vice versa depends on the store used. See
|
54
|
+
# individual store classes for that matter.
|
55
|
+
#
|
52
56
|
# ### Compatibility Note for Mechanize::Cookie users
|
53
57
|
#
|
54
58
|
# In HTTP::Cookie, each cookie object can store its origin URI
|
@@ -70,12 +74,22 @@ class HTTP::CookieJar
|
|
70
74
|
end
|
71
75
|
alias << add
|
72
76
|
|
73
|
-
#
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
77
|
+
# Deletes a cookie that has the same name, domain and path as a
|
78
|
+
# given cookie from the jar and returns self.
|
79
|
+
#
|
80
|
+
# How the `for_domain` flag value affects the set of deleted cookies
|
81
|
+
# depends on the store used. See individual store classes for that
|
82
|
+
# matter.
|
83
|
+
def delete(cookie)
|
84
|
+
@store.delete(cookie)
|
85
|
+
self
|
86
|
+
end
|
87
|
+
|
88
|
+
# Gets an array of cookies sorted by the path and creation time. If
|
89
|
+
# `url` is given, only ones that should be sent to the URL/URI are
|
90
|
+
# selected, with the access time of each of them updated.
|
91
|
+
def cookies(url = nil)
|
92
|
+
each(url).sort
|
79
93
|
end
|
80
94
|
|
81
95
|
# Tests if the jar is empty. If `url` is given, tests if there is
|
@@ -89,7 +103,8 @@ class HTTP::CookieJar
|
|
89
103
|
end
|
90
104
|
end
|
91
105
|
|
92
|
-
# Iterates over all cookies that are not expired
|
106
|
+
# Iterates over all cookies that are not expired in no particular
|
107
|
+
# order.
|
93
108
|
#
|
94
109
|
# An optional argument `uri` specifies a URI/URL indicating the
|
95
110
|
# destination of the cookies being selected. Every cookie yielded
|
@@ -111,10 +126,13 @@ class HTTP::CookieJar
|
|
111
126
|
end
|
112
127
|
include Enumerable
|
113
128
|
|
114
|
-
# Parses a Set-Cookie field value `set_cookie`
|
115
|
-
# `origin
|
116
|
-
#
|
117
|
-
#
|
129
|
+
# Parses a Set-Cookie field value `set_cookie` assuming that it is
|
130
|
+
# sent from a source URL/URI `origin`, and adds the cookies parsed
|
131
|
+
# as valid and considered acceptable to the jar. Returns an array
|
132
|
+
# of cookies that have been added.
|
133
|
+
#
|
134
|
+
# If a block is given, it is called for each cookie and the cookie
|
135
|
+
# is added only if the block returns a true value.
|
118
136
|
#
|
119
137
|
# `jar.parse(set_cookie, origin)` is a shorthand for this:
|
120
138
|
#
|
@@ -125,16 +143,15 @@ class HTTP::CookieJar
|
|
125
143
|
# See HTTP::Cookie.parse for available options.
|
126
144
|
def parse(set_cookie, origin, options = nil) # :yield: cookie
|
127
145
|
if block_given?
|
128
|
-
HTTP::Cookie.parse(set_cookie, origin, options) { |
|
129
|
-
|
130
|
-
|
146
|
+
HTTP::Cookie.parse(set_cookie, origin, options).tap { |cookies|
|
147
|
+
cookies.select! { |cookie|
|
148
|
+
yield(cookie) && add(cookie)
|
149
|
+
}
|
131
150
|
}
|
132
151
|
else
|
133
152
|
HTTP::Cookie.parse(set_cookie, origin, options) { |cookie|
|
134
153
|
add(cookie)
|
135
154
|
}
|
136
|
-
# XXX: ruby 1.8 fails to call super from a proc'ized method
|
137
|
-
# HTTP::Cookie.parse(set_cookie, origin, options, &method(:add)
|
138
155
|
end
|
139
156
|
end
|
140
157
|
|
@@ -154,7 +171,7 @@ class HTTP::CookieJar
|
|
154
171
|
# <dt>:yaml</dt>
|
155
172
|
# <dd>YAML structure (default)</dd>
|
156
173
|
# <dt>:cookiestxt</dt>
|
157
|
-
# <dd
|
174
|
+
# <dd>Mozilla's cookies.txt format</dd>
|
158
175
|
# </dl>
|
159
176
|
#
|
160
177
|
# * `:session`
|
@@ -37,7 +37,7 @@ class HTTP::CookieJar::AbstractSaver
|
|
37
37
|
# Initializes each instance variable of the same name as option
|
38
38
|
# keyword.
|
39
39
|
default_options.each_pair { |key, default|
|
40
|
-
instance_variable_set("@#{key}", options.
|
40
|
+
instance_variable_set("@#{key}", options.fetch(key, default))
|
41
41
|
}
|
42
42
|
end
|
43
43
|
|
@@ -41,7 +41,7 @@ class HTTP::CookieJar::AbstractStore
|
|
41
41
|
# Initializes each instance variable of the same name as option
|
42
42
|
# keyword.
|
43
43
|
default_options.each_pair { |key, default|
|
44
|
-
instance_variable_set("@#{key}", options.
|
44
|
+
instance_variable_set("@#{key}", options.fetch(key, default))
|
45
45
|
}
|
46
46
|
end
|
47
47
|
|
@@ -55,14 +55,14 @@ class HTTP::CookieJar
|
|
55
55
|
end
|
56
56
|
|
57
57
|
def add(cookie)
|
58
|
-
path_cookies = ((@jar[cookie.
|
58
|
+
path_cookies = ((@jar[cookie.domain] ||= {})[cookie.path] ||= {})
|
59
59
|
path_cookies[cookie.name] = cookie
|
60
60
|
cleanup if (@gc_index += 1) >= @gc_threshold
|
61
61
|
self
|
62
62
|
end
|
63
63
|
|
64
64
|
def delete(cookie)
|
65
|
-
path_cookies = ((@jar[cookie.
|
65
|
+
path_cookies = ((@jar[cookie.domain] ||= {})[cookie.path] ||= {})
|
66
66
|
path_cookies.delete(cookie.name)
|
67
67
|
self
|
68
68
|
end
|
@@ -255,7 +255,7 @@ class HTTP::CookieJar
|
|
255
255
|
db_delete(cookie)
|
256
256
|
end
|
257
257
|
|
258
|
-
def each(uri = nil)
|
258
|
+
def each(uri = nil, &block)
|
259
259
|
now = Time.now
|
260
260
|
if uri
|
261
261
|
@st_cookies_for_domain ||=
|
@@ -304,7 +304,7 @@ class HTTP::CookieJar
|
|
304
304
|
yield cookie
|
305
305
|
end
|
306
306
|
}
|
307
|
-
@sjar.each(uri, &
|
307
|
+
@sjar.each(uri, &block)
|
308
308
|
else
|
309
309
|
@st_all_cookies ||=
|
310
310
|
@db.prepare(<<-'SQL')
|
@@ -333,7 +333,7 @@ class HTTP::CookieJar
|
|
333
333
|
|
334
334
|
yield cookie
|
335
335
|
}
|
336
|
-
@sjar.each(&
|
336
|
+
@sjar.each(&block)
|
337
337
|
end
|
338
338
|
self
|
339
339
|
end
|
data/test/test_http_cookie.rb
CHANGED
@@ -50,10 +50,29 @@ class TestHTTPCookie < Test::Unit::TestCase
|
|
50
50
|
silently do
|
51
51
|
assert_equal 1, HTTP::Cookie.parse(cookie, url) { |c|
|
52
52
|
assert c.expires, "Tried parsing: #{date}"
|
53
|
-
|
53
|
+
assert_send [c.expires, :<, yesterday]
|
54
54
|
}.size
|
55
55
|
end
|
56
56
|
end
|
57
|
+
|
58
|
+
[
|
59
|
+
["PREF=1; expires=Wed, 01 Jan 100 12:34:56 GMT", nil],
|
60
|
+
["PREF=1; expires=Sat, 01 Jan 1600 12:34:56 GMT", nil],
|
61
|
+
["PREF=1; expires=Tue, 01 Jan 69 12:34:56 GMT", 2069],
|
62
|
+
["PREF=1; expires=Thu, 01 Jan 70 12:34:56 GMT", 1970],
|
63
|
+
["PREF=1; expires=Wed, 01 Jan 20 12:34:56 GMT", 2020],
|
64
|
+
["PREF=1; expires=Sat, 01 Jan 2020 12:34:60 GMT", nil],
|
65
|
+
["PREF=1; expires=Sat, 01 Jan 2020 12:60:56 GMT", nil],
|
66
|
+
["PREF=1; expires=Sat, 01 Jan 2020 24:00:00 GMT", nil],
|
67
|
+
["PREF=1; expires=Sat, 32 Jan 2020 12:34:56 GMT", nil],
|
68
|
+
].each { |set_cookie, year|
|
69
|
+
cookie, = HTTP::Cookie.parse(set_cookie, url)
|
70
|
+
if year
|
71
|
+
assert_equal year, cookie.expires.year, "#{set_cookie}: expires in #{year}"
|
72
|
+
else
|
73
|
+
assert_equal nil, cookie.expires, "#{set_cookie}: invalid expiry date"
|
74
|
+
end
|
75
|
+
}
|
57
76
|
end
|
58
77
|
|
59
78
|
def test_parse_empty
|
@@ -105,6 +124,18 @@ class TestHTTPCookie < Test::Unit::TestCase
|
|
105
124
|
}.size
|
106
125
|
end
|
107
126
|
|
127
|
+
def test_parse_no_nothing
|
128
|
+
cookie = '; "", ;'
|
129
|
+
url = URI.parse('http://www.example.com/')
|
130
|
+
assert_equal 0, HTTP::Cookie.parse(cookie, url).size
|
131
|
+
end
|
132
|
+
|
133
|
+
def test_parse_no_name
|
134
|
+
cookie = '=no-name; path=/'
|
135
|
+
url = URI.parse('http://www.example.com/')
|
136
|
+
assert_equal 0, HTTP::Cookie.parse(cookie, url).size
|
137
|
+
end
|
138
|
+
|
108
139
|
def test_parse_weird_cookie
|
109
140
|
cookie = 'n/a, ASPSESSIONIDCSRRQDQR=FBLDGHPBNDJCPCGNCPAENELB; path=/'
|
110
141
|
url = URI.parse('http://www.searchinnovation.com/')
|
@@ -400,13 +431,51 @@ class TestHTTPCookie < Test::Unit::TestCase
|
|
400
431
|
cookie = HTTP::Cookie.new('foo', value)
|
401
432
|
assert_equal(cookie_value, cookie.cookie_value)
|
402
433
|
}
|
434
|
+
|
435
|
+
pairs = [
|
436
|
+
['Foo', 'value1'],
|
437
|
+
['Bar', 'value 2'],
|
438
|
+
['Baz', 'value3'],
|
439
|
+
['Bar', 'value"4'],
|
440
|
+
]
|
441
|
+
|
442
|
+
cookie_value = HTTP::Cookie.cookie_value(pairs.map { |name, value|
|
443
|
+
HTTP::Cookie.new(:name => name, :value => value)
|
444
|
+
})
|
445
|
+
|
446
|
+
assert_equal 'Foo=value1; Bar="value 2"; Baz=value3; Bar="value\\"4"', cookie_value
|
447
|
+
|
448
|
+
hash = HTTP::Cookie.cookie_value_to_hash(cookie_value)
|
449
|
+
|
450
|
+
assert_equal 3, hash.size
|
451
|
+
|
452
|
+
hash.each_pair { |name, value|
|
453
|
+
_, pvalue = pairs.assoc(name)
|
454
|
+
assert_equal pvalue, value
|
455
|
+
}
|
403
456
|
end
|
404
457
|
|
405
458
|
def test_set_cookie_value
|
406
|
-
url = URI.parse('http://rubyforge.org/')
|
459
|
+
url = URI.parse('http://rubyforge.org/path/')
|
460
|
+
|
461
|
+
[
|
462
|
+
HTTP::Cookie.new('a', 'b', :domain => 'rubyforge.org', :path => '/path/'),
|
463
|
+
HTTP::Cookie.new('a', 'b', :origin => url),
|
464
|
+
].each { |cookie|
|
465
|
+
cookie.set_cookie_value
|
466
|
+
}
|
467
|
+
|
468
|
+
[
|
469
|
+
HTTP::Cookie.new('a', 'b', :domain => 'rubyforge.org'),
|
470
|
+
HTTP::Cookie.new('a', 'b', :for_domain => true, :path => '/path/'),
|
471
|
+
].each { |cookie|
|
472
|
+
assert_raises(RuntimeError) {
|
473
|
+
cookie.set_cookie_value
|
474
|
+
}
|
475
|
+
}
|
407
476
|
|
408
477
|
['foo=bar', 'foo="bar"', 'foo="ba\"r baz"'].each { |cookie_value|
|
409
|
-
cookie_params = @cookie_params.merge('secure' => 'secure', 'max-age' => 'Max-Age=1000')
|
478
|
+
cookie_params = @cookie_params.merge('path' => '/path/', 'secure' => 'secure', 'max-age' => 'Max-Age=1000')
|
410
479
|
date = Time.at(Time.now.to_i)
|
411
480
|
cookie_params.keys.combine.each do |keys|
|
412
481
|
cookie_text = [cookie_value, *keys.map { |key| cookie_params[key] }].join('; ')
|
@@ -510,11 +579,34 @@ class TestHTTPCookie < Test::Unit::TestCase
|
|
510
579
|
cookie.acceptable?
|
511
580
|
}
|
512
581
|
|
513
|
-
assert_raises(ArgumentError) { HTTP::Cookie.new(
|
582
|
+
assert_raises(ArgumentError) { HTTP::Cookie.new() }
|
514
583
|
assert_raises(ArgumentError) { HTTP::Cookie.new(:value => 'value') }
|
515
584
|
assert_raises(ArgumentError) { HTTP::Cookie.new('', 'value') }
|
516
585
|
assert_raises(ArgumentError) { HTTP::Cookie.new('key=key', 'value') }
|
517
586
|
assert_raises(ArgumentError) { HTTP::Cookie.new("key\tkey", 'value') }
|
587
|
+
assert_raises(ArgumentError) { HTTP::Cookie.new('key', 'value', 'something') }
|
588
|
+
assert_raises(ArgumentError) { HTTP::Cookie.new('key', 'value', {}, 'something') }
|
589
|
+
|
590
|
+
[
|
591
|
+
HTTP::Cookie.new(:name => 'name'),
|
592
|
+
HTTP::Cookie.new("key", nil, :for_domain => true),
|
593
|
+
HTTP::Cookie.new("key", nil),
|
594
|
+
HTTP::Cookie.new("key", :secure => true),
|
595
|
+
HTTP::Cookie.new("key"),
|
596
|
+
].each { |cookie|
|
597
|
+
assert_equal '', cookie.value
|
598
|
+
assert_equal true, cookie.expired?
|
599
|
+
}
|
600
|
+
|
601
|
+
[
|
602
|
+
HTTP::Cookie.new(:name => 'name', :max_age => 3600),
|
603
|
+
HTTP::Cookie.new("key", nil, :expires => Time.now + 3600),
|
604
|
+
HTTP::Cookie.new("key", :expires => Time.now + 3600),
|
605
|
+
HTTP::Cookie.new("key", :expires => Time.now + 3600, :value => nil),
|
606
|
+
].each { |cookie|
|
607
|
+
assert_equal '', cookie.value
|
608
|
+
assert_equal false, cookie.expired?
|
609
|
+
}
|
518
610
|
end
|
519
611
|
|
520
612
|
def cookie_values(options = {})
|
@@ -681,6 +773,22 @@ class TestHTTPCookie < Test::Unit::TestCase
|
|
681
773
|
assert_equal false, cookie.acceptable?
|
682
774
|
end
|
683
775
|
|
776
|
+
def test_value
|
777
|
+
cookie = HTTP::Cookie.new('name', 'value')
|
778
|
+
assert_equal 'value', cookie.value
|
779
|
+
|
780
|
+
cookie.value = 'new value'
|
781
|
+
assert_equal 'new value', cookie.value
|
782
|
+
|
783
|
+
assert_raises(ArgumentError) { cookie.value = "a\tb" }
|
784
|
+
assert_raises(ArgumentError) { cookie.value = "a\nb" }
|
785
|
+
|
786
|
+
assert_equal false, cookie.expired?
|
787
|
+
cookie.value = nil
|
788
|
+
assert_equal '', cookie.value
|
789
|
+
assert_equal true, cookie.expired?
|
790
|
+
end
|
791
|
+
|
684
792
|
def test_path
|
685
793
|
uri = URI.parse('http://example.com/foo/bar')
|
686
794
|
|
@@ -2,6 +2,24 @@ require File.expand_path('helper', File.dirname(__FILE__))
|
|
2
2
|
require 'tmpdir'
|
3
3
|
|
4
4
|
module TestHTTPCookieJar
|
5
|
+
class TestBasic < Test::Unit::TestCase
|
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
|
+
|
5
23
|
module Tests
|
6
24
|
def setup(options = nil, options2 = nil)
|
7
25
|
default_options = {
|
@@ -13,7 +31,7 @@ module TestHTTPCookieJar
|
|
13
31
|
@store_type = new_options[:store]
|
14
32
|
@gc_threshold = new_options[:gc_threshold]
|
15
33
|
@jar = HTTP::CookieJar.new(new_options)
|
16
|
-
@jar2 = HTTP::CookieJar.new(
|
34
|
+
@jar2 = HTTP::CookieJar.new(new_options2)
|
17
35
|
end
|
18
36
|
|
19
37
|
def hash_store?
|
@@ -303,6 +321,14 @@ module TestHTTPCookieJar
|
|
303
321
|
assert_equal(0, @jar.cookies(url).length)
|
304
322
|
end
|
305
323
|
|
324
|
+
def test_save_nonexistent_saver
|
325
|
+
Dir.mktmpdir { |dir|
|
326
|
+
assert_raises(ArgumentError) {
|
327
|
+
@jar.save(File.join(dir, "file"), :nonexistent)
|
328
|
+
}
|
329
|
+
}
|
330
|
+
end
|
331
|
+
|
306
332
|
def test_save_cookies_yaml
|
307
333
|
url = URI 'http://rubyforge.org/'
|
308
334
|
|
@@ -310,7 +336,6 @@ module TestHTTPCookieJar
|
|
310
336
|
cookie = HTTP::Cookie.new(cookie_values(:origin => url))
|
311
337
|
s_cookie = HTTP::Cookie.new(cookie_values(:name => 'Bar',
|
312
338
|
:expires => nil,
|
313
|
-
:session => true,
|
314
339
|
:origin => url))
|
315
340
|
|
316
341
|
@jar.add(cookie)
|
@@ -335,14 +360,53 @@ module TestHTTPCookieJar
|
|
335
360
|
assert_equal(3, @jar.cookies(url).length)
|
336
361
|
end
|
337
362
|
|
363
|
+
def test_save_load_signature
|
364
|
+
Dir.mktmpdir { |dir|
|
365
|
+
filename = File.join(dir, "cookies.yml")
|
366
|
+
|
367
|
+
@jar.save(filename, :format => :cookiestxt, :session => true)
|
368
|
+
@jar.save(filename, :format => :cookiestxt, :session => true)
|
369
|
+
@jar.save(filename, :format => :cookiestxt)
|
370
|
+
@jar.save(filename, :cookiestxt, :session => true)
|
371
|
+
@jar.save(filename, :cookiestxt)
|
372
|
+
@jar.save(filename, :session => true)
|
373
|
+
@jar.save(filename)
|
374
|
+
assert_raises(ArgumentError) {
|
375
|
+
@jar.save()
|
376
|
+
}
|
377
|
+
assert_raises(ArgumentError) {
|
378
|
+
@jar.save(filename, { :format => :cookiestxt }, { :session => true })
|
379
|
+
}
|
380
|
+
assert_raises(ArgumentError) {
|
381
|
+
@jar.save(filename, :cookiestxt, { :session => true }, { :format => :cookiestxt })
|
382
|
+
}
|
383
|
+
|
384
|
+
@jar.load(filename, :format => :cookiestxt, :linefeed => "\n")
|
385
|
+
@jar.load(filename, :format => :cookiestxt, :linefeed => "\n")
|
386
|
+
@jar.load(filename, :format => :cookiestxt)
|
387
|
+
@jar.load(filename, :cookiestxt, :linefeed => "\n")
|
388
|
+
@jar.load(filename, :cookiestxt)
|
389
|
+
@jar.load(filename, :linefeed => "\n")
|
390
|
+
@jar.load(filename)
|
391
|
+
assert_raises(ArgumentError) {
|
392
|
+
@jar.load()
|
393
|
+
}
|
394
|
+
assert_raises(ArgumentError) {
|
395
|
+
@jar.load(filename, { :format => :cookiestxt }, { :linefeed => "\n" })
|
396
|
+
}
|
397
|
+
assert_raises(ArgumentError) {
|
398
|
+
@jar.load(filename, :cookiestxt, { :linefeed => "\n" }, { :format => :cookiestxt })
|
399
|
+
}
|
400
|
+
}
|
401
|
+
end
|
402
|
+
|
338
403
|
def test_save_session_cookies_yaml
|
339
404
|
url = URI 'http://rubyforge.org/'
|
340
405
|
|
341
406
|
# Add one cookie with an expiration date in the future
|
342
407
|
cookie = HTTP::Cookie.new(cookie_values)
|
343
408
|
s_cookie = HTTP::Cookie.new(cookie_values(:name => 'Bar',
|
344
|
-
:expires => nil
|
345
|
-
:session => true))
|
409
|
+
:expires => nil))
|
346
410
|
|
347
411
|
@jar.add(cookie)
|
348
412
|
@jar.add(s_cookie)
|
@@ -360,7 +424,6 @@ module TestHTTPCookieJar
|
|
360
424
|
assert_equal(3, @jar.cookies(url).length)
|
361
425
|
end
|
362
426
|
|
363
|
-
|
364
427
|
def test_save_and_read_cookiestxt
|
365
428
|
url = URI 'http://rubyforge.org/foo/'
|
366
429
|
|
@@ -368,8 +431,7 @@ module TestHTTPCookieJar
|
|
368
431
|
cookie = HTTP::Cookie.new(cookie_values)
|
369
432
|
expires = cookie.expires
|
370
433
|
s_cookie = HTTP::Cookie.new(cookie_values(:name => 'Bar',
|
371
|
-
:expires => nil
|
372
|
-
:session => true))
|
434
|
+
:expires => nil))
|
373
435
|
cookie2 = HTTP::Cookie.new(cookie_values(:name => 'Baz',
|
374
436
|
:value => 'Foo#Baz',
|
375
437
|
:path => '/foo/',
|
@@ -394,6 +456,13 @@ module TestHTTPCookieJar
|
|
394
456
|
|
395
457
|
content = File.read(filename)
|
396
458
|
|
459
|
+
filename2 = File.join(dir, "cookies2.txt")
|
460
|
+
open(filename2, 'w') { |w|
|
461
|
+
w.puts '# HTTP Cookie File'
|
462
|
+
@jar.save(w, :cookiestxt, :header => nil)
|
463
|
+
}
|
464
|
+
assert_equal content, File.read(filename2)
|
465
|
+
|
397
466
|
assert_match(/^\.rubyforge\.org\t.*\tFoo\t/, content)
|
398
467
|
assert_match(/^rubyforge\.org\t.*\tBaz\t/, content)
|
399
468
|
assert_match(/^#HttpOnly_\.rubyforge\.org\t/, content)
|
@@ -554,17 +623,43 @@ module TestHTTPCookieJar
|
|
554
623
|
assert_equal('Foo1 Foo2', @jar.cookies(surl).map { |c| c.name }.sort.join(' ') )
|
555
624
|
end
|
556
625
|
|
557
|
-
def
|
558
|
-
|
559
|
-
|
626
|
+
def test_delete
|
627
|
+
cookie1 = HTTP::Cookie.new(cookie_values)
|
628
|
+
cookie2 = HTTP::Cookie.new(:name => 'Foo', :value => '',
|
629
|
+
:domain => 'rubyforge.org',
|
630
|
+
:for_domain => false,
|
631
|
+
:path => '/')
|
632
|
+
cookie3 = HTTP::Cookie.new(:name => 'Foo', :value => '',
|
633
|
+
:domain => 'rubyforge.org',
|
634
|
+
:for_domain => true,
|
635
|
+
:path => '/')
|
560
636
|
|
561
|
-
|
562
|
-
|
637
|
+
@jar.add(cookie1)
|
638
|
+
@jar.delete(cookie2)
|
563
639
|
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
640
|
+
if mozilla_store?
|
641
|
+
assert_equal(1, @jar.to_a.length)
|
642
|
+
@jar.delete(cookie3)
|
643
|
+
end
|
644
|
+
|
645
|
+
assert_equal(0, @jar.to_a.length)
|
646
|
+
end
|
647
|
+
|
648
|
+
def test_accessed_at
|
649
|
+
orig = HTTP::Cookie.new(cookie_values(:expires => nil))
|
650
|
+
@jar.add(orig)
|
651
|
+
|
652
|
+
time = orig.accessed_at
|
653
|
+
|
654
|
+
assert_in_delta 1.0, time, Time.now, "accessed_at is initialized to the current time"
|
655
|
+
|
656
|
+
cookie, = @jar.to_a
|
657
|
+
|
658
|
+
assert_equal time, cookie.accessed_at, "accessed_at is not updated by each()"
|
659
|
+
|
660
|
+
cookie, = @jar.cookies("http://rubyforge.org/")
|
661
|
+
|
662
|
+
assert_send [cookie.accessed_at, :>, time], "accessed_at is not updated by each(url)"
|
568
663
|
end
|
569
664
|
|
570
665
|
def test_max_cookies
|
@@ -614,14 +709,38 @@ module TestHTTPCookieJar
|
|
614
709
|
}
|
615
710
|
}
|
616
711
|
|
617
|
-
|
618
|
-
|
712
|
+
assert_send [count, :>, slimit]
|
713
|
+
assert_send [@jar.to_a.size, :<=, slimit]
|
619
714
|
@jar.cleanup
|
620
715
|
assert_equal hlimit, @jar.to_a.size
|
621
716
|
assert_equal false, @jar.any? { |cookie|
|
622
717
|
cookie.domain == cookie.value
|
623
718
|
}
|
624
719
|
end
|
720
|
+
|
721
|
+
def test_parse
|
722
|
+
set_cookie = [
|
723
|
+
"name=Akinori; Domain=rubyforge.org; Expires=Sun, 08 Aug 2076 19:00:00 GMT; Path=/",
|
724
|
+
"country=Japan; Domain=rubyforge.org; Expires=Sun, 08 Aug 2076 19:00:00 GMT; Path=/",
|
725
|
+
"city=Tokyo; Domain=rubyforge.org; Expires=Sun, 08 Aug 2076 19:00:00 GMT; Path=/",
|
726
|
+
].join(', ')
|
727
|
+
|
728
|
+
cookies = @jar.parse(set_cookie, 'http://rubyforge.org/')
|
729
|
+
assert_equal %w[Akinori Japan Tokyo], cookies.map { |c| c.value }
|
730
|
+
assert_equal %w[Tokyo Japan Akinori], @jar.to_a.sort_by { |c| c.name }.map { |c| c.value }
|
731
|
+
end
|
732
|
+
|
733
|
+
def test_parse_with_block
|
734
|
+
set_cookie = [
|
735
|
+
"name=Akinori; Domain=rubyforge.org; Expires=Sun, 08 Aug 2076 19:00:00 GMT; Path=/",
|
736
|
+
"country=Japan; Domain=rubyforge.org; Expires=Sun, 08 Aug 2076 19:00:00 GMT; Path=/",
|
737
|
+
"city=Tokyo; Domain=rubyforge.org; Expires=Sun, 08 Aug 2076 19:00:00 GMT; Path=/",
|
738
|
+
].join(', ')
|
739
|
+
|
740
|
+
cookies = @jar.parse(set_cookie, 'http://rubyforge.org/') { |c| c.name != 'city' }
|
741
|
+
assert_equal %w[Akinori Japan], cookies.map { |c| c.value }
|
742
|
+
assert_equal %w[Japan Akinori], @jar.to_a.sort_by { |c| c.name }.map { |c| c.value }
|
743
|
+
end
|
625
744
|
end
|
626
745
|
|
627
746
|
class WithHashStore < Test::Unit::TestCase
|
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.pre11
|
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-04-
|
14
|
+
date: 2013-04-15 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: domain_name
|
@@ -132,6 +132,7 @@ files:
|
|
132
132
|
- http-cookie.gemspec
|
133
133
|
- lib/http-cookie.rb
|
134
134
|
- lib/http/cookie.rb
|
135
|
+
- lib/http/cookie/ruby_compat.rb
|
135
136
|
- lib/http/cookie/scanner.rb
|
136
137
|
- lib/http/cookie/version.rb
|
137
138
|
- lib/http/cookie_jar.rb
|