http-cookie 1.0.0.pre10 → 1.0.0.pre11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/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
|