http-cookie 1.0.0.pre12 → 1.0.0
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/lib/http/cookie.rb +22 -25
- data/lib/http/cookie/ruby_compat.rb +5 -1
- data/lib/http/cookie/scanner.rb +0 -14
- data/lib/http/cookie/version.rb +1 -1
- data/lib/http/cookie_jar.rb +7 -8
- data/lib/http/cookie_jar/abstract_saver.rb +16 -2
- data/lib/http/cookie_jar/abstract_store.rb +28 -4
- data/lib/http/cookie_jar/cookiestxt_saver.rb +23 -2
- data/lib/http/cookie_jar/hash_store.rb +6 -13
- data/lib/http/cookie_jar/mozilla_store.rb +6 -15
- data/lib/http/cookie_jar/yaml_saver.rb +17 -2
- data/test/helper.rb +30 -0
- data/test/test_http_cookie.rb +34 -21
- data/test/test_http_cookie_jar.rb +114 -2
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aacf47668ef161f9e46f07ed44bd6e145c805c14
|
4
|
+
data.tar.gz: 92c544f479f357ad08e66a8a3827e1edaca35c2e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7cc1fc98627c5167e3eb410359b00a868f849d10458ca0b1881efdb6ab94bf51d300f732f9b3de52edec2e21934553f937cb38e416af18e103ca923e70285c58
|
7
|
+
data.tar.gz: 3fef65c59da56daba7cb4d571b034cecab3b66cb656811fe9644d99404a152b5656dc04d2a501a3a6b74cf75cb5bcdde91c87f3d5b470d8ba1ffcd515498c421
|
data/lib/http/cookie.rb
CHANGED
@@ -87,7 +87,7 @@ class HTTP::Cookie
|
|
87
87
|
# The Expires attribute value as a Time object.
|
88
88
|
#
|
89
89
|
# The setter method accepts a Time object, a string representation
|
90
|
-
# of date/time, or `nil`.
|
90
|
+
# of date/time that Time.parse can understand, or `nil`.
|
91
91
|
#
|
92
92
|
# Setting this value resets #max_age to nil. When #max_age is
|
93
93
|
# non-nil, #expires returns `created_at + max_age`.
|
@@ -111,12 +111,11 @@ class HTTP::Cookie
|
|
111
111
|
# new(**attr_hash)
|
112
112
|
#
|
113
113
|
# Creates a cookie object. For each key of `attr_hash`, the setter
|
114
|
-
# is called if defined
|
115
|
-
#
|
116
|
-
#
|
117
|
-
#
|
118
|
-
#
|
119
|
-
# a setter method raises will be passed through.
|
114
|
+
# is called if defined and any error (typically ArgumentError or
|
115
|
+
# TypeError) that is raised will be passed through. Each key can be
|
116
|
+
# either a downcased symbol or a string that may be mixed case.
|
117
|
+
# Support for the latter may, however, be obsoleted in future when
|
118
|
+
# Ruby 2.0's keyword syntax is adopted.
|
120
119
|
#
|
121
120
|
# If `value` is omitted or it is nil, an expiration cookie is
|
122
121
|
# created unless `max_age` or `expires` (`expires_at`) is given.
|
@@ -157,8 +156,8 @@ class HTTP::Cookie
|
|
157
156
|
end
|
158
157
|
for_domain = false
|
159
158
|
domain = max_age = origin = nil
|
160
|
-
attr_hash.each_pair { |
|
161
|
-
case key
|
159
|
+
attr_hash.each_pair { |okey, val|
|
160
|
+
case key ||= okey
|
162
161
|
when :name
|
163
162
|
self.name = val
|
164
163
|
when :value
|
@@ -180,23 +179,21 @@ class HTTP::Cookie
|
|
180
179
|
@httponly = val
|
181
180
|
when :secure, :secure?
|
182
181
|
@secure = val
|
183
|
-
when /[A-Z]/
|
184
|
-
warn "keyword should be downcased: #{key}" if $VERBOSE
|
185
|
-
key = key.downcase
|
186
|
-
redo
|
187
182
|
when Symbol
|
188
183
|
setter = :"#{key}="
|
189
184
|
if respond_to?(setter)
|
190
185
|
__send__(setter, val)
|
191
186
|
else
|
192
|
-
warn "unknown
|
187
|
+
warn "unknown attribute name: #{okey.inspect}" if $VERBOSE
|
188
|
+
next
|
193
189
|
end
|
194
190
|
when String
|
195
|
-
|
191
|
+
warn "use downcased symbol for keyword: #{okey.inspect}" if $VERBOSE
|
192
|
+
key = key.downcase.to_sym
|
196
193
|
redo
|
197
194
|
else
|
198
|
-
|
199
|
-
|
195
|
+
warn "invalid keyword ignored: #{okey.inspect}" if $VERBOSE
|
196
|
+
next
|
200
197
|
end
|
201
198
|
}
|
202
199
|
if @name.nil?
|
@@ -343,7 +340,7 @@ class HTTP::Cookie
|
|
343
340
|
attr_reader :name
|
344
341
|
|
345
342
|
# See #name.
|
346
|
-
def name=
|
343
|
+
def name= name
|
347
344
|
name = (String.try_convert(name) or
|
348
345
|
raise TypeError, "#{name.class} is not a String")
|
349
346
|
if name.empty?
|
@@ -360,7 +357,7 @@ class HTTP::Cookie
|
|
360
357
|
attr_reader :value
|
361
358
|
|
362
359
|
# See #value.
|
363
|
-
def value=
|
360
|
+
def value= value
|
364
361
|
if value.nil?
|
365
362
|
self.expires = UNIX_EPOCH
|
366
363
|
return @value = ''
|
@@ -379,7 +376,7 @@ class HTTP::Cookie
|
|
379
376
|
attr_reader :domain
|
380
377
|
|
381
378
|
# See #domain.
|
382
|
-
def domain=
|
379
|
+
def domain= domain
|
383
380
|
case domain
|
384
381
|
when nil
|
385
382
|
@for_domain = false
|
@@ -437,7 +434,7 @@ class HTTP::Cookie
|
|
437
434
|
attr_reader :path
|
438
435
|
|
439
436
|
# See #path.
|
440
|
-
def path=
|
437
|
+
def path= path
|
441
438
|
path = (String.try_convert(path) or
|
442
439
|
raise TypeError, "#{path.class} is not a String")
|
443
440
|
@path = path.start_with?('/') ? path : '/'
|
@@ -446,7 +443,7 @@ class HTTP::Cookie
|
|
446
443
|
attr_reader :origin
|
447
444
|
|
448
445
|
# See #origin.
|
449
|
-
def origin=
|
446
|
+
def origin= origin
|
450
447
|
return origin if origin == @origin
|
451
448
|
@origin.nil? or
|
452
449
|
raise ArgumentError, "origin cannot be changed once it is set"
|
@@ -482,7 +479,7 @@ class HTTP::Cookie
|
|
482
479
|
end
|
483
480
|
|
484
481
|
# See #expires.
|
485
|
-
def expires=
|
482
|
+
def expires= t
|
486
483
|
case t
|
487
484
|
when nil, Time
|
488
485
|
else
|
@@ -499,7 +496,7 @@ class HTTP::Cookie
|
|
499
496
|
attr_reader :max_age
|
500
497
|
|
501
498
|
# See #max_age.
|
502
|
-
def max_age=
|
499
|
+
def max_age= sec
|
503
500
|
@expires = nil
|
504
501
|
case sec
|
505
502
|
when Integer, nil
|
@@ -635,7 +632,7 @@ class HTTP::Cookie
|
|
635
632
|
|
636
633
|
# Compares the cookie with another. When there are many cookies with
|
637
634
|
# the same name for a URL, the value of the smallest must be used.
|
638
|
-
def <=>
|
635
|
+
def <=> other
|
639
636
|
# RFC 6265 5.4
|
640
637
|
# Precedence: 1. longer path 2. older creation
|
641
638
|
(@name <=> other.name).nonzero? ||
|
@@ -1,5 +1,5 @@
|
|
1
1
|
class Array
|
2
|
-
def select!
|
2
|
+
def select! # :yield: x
|
3
3
|
i = 0
|
4
4
|
each_with_index { |x, j|
|
5
5
|
yield x or next
|
@@ -10,6 +10,10 @@ class Array
|
|
10
10
|
self[i..-1] = []
|
11
11
|
self
|
12
12
|
end unless method_defined?(:select!)
|
13
|
+
|
14
|
+
def sort_by!(&block) # :yield: x
|
15
|
+
replace(sort_by(&block))
|
16
|
+
end unless method_defined?(:sort_by!)
|
13
17
|
end
|
14
18
|
|
15
19
|
class Hash
|
data/lib/http/cookie/scanner.rb
CHANGED
@@ -152,13 +152,6 @@ class HTTP::Cookie::Scanner < StringScanner
|
|
152
152
|
end
|
153
153
|
|
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
155
|
# RFC 6265 4.1.1 & 5.2
|
163
156
|
until eos?
|
164
157
|
start = pos
|
@@ -221,13 +214,6 @@ class HTTP::Cookie::Scanner < StringScanner
|
|
221
214
|
end
|
222
215
|
|
223
216
|
def scan_cookie
|
224
|
-
unless block_given?
|
225
|
-
scan_cookie { |*values|
|
226
|
-
return values
|
227
|
-
}
|
228
|
-
return
|
229
|
-
end
|
230
|
-
|
231
217
|
# RFC 6265 4.1.1 & 5.4
|
232
218
|
until eos?
|
233
219
|
skip_wsp
|
data/lib/http/cookie/version.rb
CHANGED
data/lib/http/cookie_jar.rb
CHANGED
@@ -6,9 +6,6 @@ require 'http/cookie'
|
|
6
6
|
# any particular website.
|
7
7
|
|
8
8
|
class HTTP::CookieJar
|
9
|
-
require 'http/cookie_jar/abstract_store'
|
10
|
-
require 'http/cookie_jar/abstract_saver'
|
11
|
-
|
12
9
|
class << self
|
13
10
|
def const_missing(name)
|
14
11
|
case name.to_s
|
@@ -62,6 +59,7 @@ class HTTP::CookieJar
|
|
62
59
|
end
|
63
60
|
end
|
64
61
|
|
62
|
+
# The copy constructor. Not all backend store classes support cloning.
|
65
63
|
def initialize_copy(other)
|
66
64
|
@store = other.instance_eval { @store.dup }
|
67
65
|
end
|
@@ -94,7 +92,7 @@ class HTTP::CookieJar
|
|
94
92
|
begin
|
95
93
|
cookie.acceptable?
|
96
94
|
rescue RuntimeError => e
|
97
|
-
|
95
|
+
raise ArgumentError, e.message
|
98
96
|
end
|
99
97
|
self
|
100
98
|
end
|
@@ -139,7 +137,7 @@ class HTTP::CookieJar
|
|
139
137
|
#
|
140
138
|
# If (and only if) the `uri` option is given, last access time of
|
141
139
|
# each cookie is updated to the current time.
|
142
|
-
def each(uri = nil, &block)
|
140
|
+
def each(uri = nil, &block) # :yield: cookie
|
143
141
|
block_given? or return enum_for(__method__, uri)
|
144
142
|
|
145
143
|
if uri
|
@@ -210,7 +208,7 @@ class HTTP::CookieJar
|
|
210
208
|
# </dl>
|
211
209
|
#
|
212
210
|
# All options given are passed through to the underlying cookie
|
213
|
-
# saver module.
|
211
|
+
# saver module's constructor.
|
214
212
|
def save(writable, *options)
|
215
213
|
opthash = {
|
216
214
|
:format => :yaml,
|
@@ -269,7 +267,7 @@ class HTTP::CookieJar
|
|
269
267
|
# </dl>
|
270
268
|
#
|
271
269
|
# All options given are passed through to the underlying cookie
|
272
|
-
# saver module.
|
270
|
+
# saver module's constructor.
|
273
271
|
def load(readable, *options)
|
274
272
|
opthash = {
|
275
273
|
:format => :yaml,
|
@@ -314,7 +312,8 @@ class HTTP::CookieJar
|
|
314
312
|
self
|
315
313
|
end
|
316
314
|
|
317
|
-
# Removes expired cookies and returns self.
|
315
|
+
# Removes expired cookies and returns self. If `session` is true,
|
316
|
+
# all session cookies are removed as well.
|
318
317
|
def cleanup(session = false)
|
319
318
|
@store.cleanup session
|
320
319
|
self
|
@@ -1,3 +1,6 @@
|
|
1
|
+
# :markup: markdown
|
2
|
+
|
3
|
+
# An abstract superclass for all saver classes.
|
1
4
|
class HTTP::CookieJar::AbstractSaver
|
2
5
|
class << self
|
3
6
|
@@class_map = {}
|
@@ -16,20 +19,25 @@ class HTTP::CookieJar::AbstractSaver
|
|
16
19
|
end
|
17
20
|
end
|
18
21
|
|
19
|
-
def inherited(subclass)
|
22
|
+
def inherited(subclass) # :nodoc:
|
20
23
|
@@class_map[class_to_symbol(subclass)] = subclass
|
21
24
|
end
|
22
25
|
|
23
|
-
def class_to_symbol(klass)
|
26
|
+
def class_to_symbol(klass) # :nodoc:
|
24
27
|
klass.name[/[^:]+?(?=Saver$|$)/].downcase.to_sym
|
25
28
|
end
|
26
29
|
end
|
27
30
|
|
31
|
+
# Defines options and their default values.
|
28
32
|
def default_options
|
29
33
|
# {}
|
30
34
|
end
|
31
35
|
private :default_options
|
32
36
|
|
37
|
+
# :call-seq:
|
38
|
+
# new(**options)
|
39
|
+
#
|
40
|
+
# Called by the constructor of each subclass using super().
|
33
41
|
def initialize(options = nil)
|
34
42
|
options ||= {}
|
35
43
|
@logger = options[:logger]
|
@@ -41,10 +49,16 @@ class HTTP::CookieJar::AbstractSaver
|
|
41
49
|
}
|
42
50
|
end
|
43
51
|
|
52
|
+
# Implements HTTP::CookieJar#save().
|
53
|
+
#
|
54
|
+
# This is an abstract method that each subclass must override.
|
44
55
|
def save(io, jar)
|
45
56
|
# self
|
46
57
|
end
|
47
58
|
|
59
|
+
# Implements HTTP::CookieJar#load().
|
60
|
+
#
|
61
|
+
# This is an abstract method that each subclass must override.
|
48
62
|
def load(io, jar)
|
49
63
|
# self
|
50
64
|
end
|
@@ -1,5 +1,7 @@
|
|
1
|
+
# :markup: markdown
|
1
2
|
require 'monitor'
|
2
3
|
|
4
|
+
# An abstract superclass for all store classes.
|
3
5
|
class HTTP::CookieJar::AbstractStore
|
4
6
|
include MonitorMixin
|
5
7
|
|
@@ -20,20 +22,25 @@ class HTTP::CookieJar::AbstractStore
|
|
20
22
|
end
|
21
23
|
end
|
22
24
|
|
23
|
-
def inherited(subclass)
|
25
|
+
def inherited(subclass) # :nodoc:
|
24
26
|
@@class_map[class_to_symbol(subclass)] = subclass
|
25
27
|
end
|
26
28
|
|
27
|
-
def class_to_symbol(klass)
|
29
|
+
def class_to_symbol(klass) # :nodoc:
|
28
30
|
klass.name[/[^:]+?(?=Store$|$)/].downcase.to_sym
|
29
31
|
end
|
30
32
|
end
|
31
33
|
|
34
|
+
# Defines options and their default values.
|
32
35
|
def default_options
|
33
36
|
# {}
|
34
37
|
end
|
35
38
|
private :default_options
|
36
39
|
|
40
|
+
# :call-seq:
|
41
|
+
# new(**options)
|
42
|
+
#
|
43
|
+
# Called by the constructor of each subclass using super().
|
37
44
|
def initialize(options = nil)
|
38
45
|
super() # MonitorMixin
|
39
46
|
options ||= {}
|
@@ -45,14 +52,21 @@ class HTTP::CookieJar::AbstractStore
|
|
45
52
|
}
|
46
53
|
end
|
47
54
|
|
55
|
+
# This is an abstract method that each subclass must override.
|
48
56
|
def initialize_copy(other)
|
49
57
|
# self
|
50
58
|
end
|
51
59
|
|
60
|
+
# Implements HTTP::CookieJar#add().
|
61
|
+
#
|
62
|
+
# This is an abstract method that each subclass must override.
|
52
63
|
def add(cookie)
|
53
64
|
# self
|
54
65
|
end
|
55
66
|
|
67
|
+
# Implements HTTP::CookieJar#delete().
|
68
|
+
#
|
69
|
+
# This is an abstract method that each subclass must override.
|
56
70
|
def delete(cookie)
|
57
71
|
# self
|
58
72
|
end
|
@@ -66,7 +80,9 @@ class HTTP::CookieJar::AbstractStore
|
|
66
80
|
#
|
67
81
|
# If (and only if) the +uri+ option is given, last access time of
|
68
82
|
# each cookie is updated to the current time.
|
69
|
-
|
83
|
+
#
|
84
|
+
# This is an abstract method that each subclass must override.
|
85
|
+
def each(uri = nil, &block) # :yield: cookie
|
70
86
|
# if uri
|
71
87
|
# ...
|
72
88
|
# else
|
@@ -78,14 +94,22 @@ class HTTP::CookieJar::AbstractStore
|
|
78
94
|
end
|
79
95
|
include Enumerable
|
80
96
|
|
97
|
+
# Implements HTTP::CookieJar#empty?().
|
81
98
|
def empty?
|
82
|
-
|
99
|
+
each { return false }
|
100
|
+
true
|
83
101
|
end
|
84
102
|
|
103
|
+
# Implements HTTP::CookieJar#clear().
|
104
|
+
#
|
105
|
+
# This is an abstract method that each subclass must override.
|
85
106
|
def clear
|
86
107
|
# self
|
87
108
|
end
|
88
109
|
|
110
|
+
# Implements HTTP::CookieJar#cleanup().
|
111
|
+
#
|
112
|
+
# This is an abstract method that each subclass must override.
|
89
113
|
def cleanup(session = false)
|
90
114
|
# if session
|
91
115
|
# select { |cookie| cookie.session? || cookie.expired? }
|
@@ -1,9 +1,25 @@
|
|
1
|
+
# :markup: markdown
|
1
2
|
require 'http/cookie_jar'
|
2
3
|
|
3
4
|
# CookiestxtSaver saves and loads cookies in the cookies.txt format.
|
4
5
|
class HTTP::CookieJar::CookiestxtSaver < HTTP::CookieJar::AbstractSaver
|
5
|
-
|
6
|
-
|
6
|
+
# :singleton-method: new
|
7
|
+
# :call-seq:
|
8
|
+
# new(**options)
|
9
|
+
#
|
10
|
+
# Available option keywords are below:
|
11
|
+
#
|
12
|
+
# * `:header`
|
13
|
+
#
|
14
|
+
# Specifies the header line not including a line feed, which is
|
15
|
+
# only used by #save(). None is output if nil is
|
16
|
+
# given. (default: `"# HTTP Cookie File"`)
|
17
|
+
#
|
18
|
+
# * `:linefeed`
|
19
|
+
#
|
20
|
+
# Specifies the line separator (default: `"\n"`).
|
21
|
+
|
22
|
+
##
|
7
23
|
|
8
24
|
def save(io, jar)
|
9
25
|
io.puts @header if @header
|
@@ -28,8 +44,13 @@ class HTTP::CookieJar::CookiestxtSaver < HTTP::CookieJar::AbstractSaver
|
|
28
44
|
}
|
29
45
|
end
|
30
46
|
|
47
|
+
# :stopdoc:
|
48
|
+
True = "TRUE"
|
49
|
+
False = "FALSE"
|
50
|
+
|
31
51
|
HTTPONLY_PREFIX = '#HttpOnly_'
|
32
52
|
RE_HTTPONLY_PREFIX = /\A#{HTTPONLY_PREFIX}/
|
53
|
+
# :startdoc:
|
33
54
|
|
34
55
|
# Serializes the cookie into a cookies.txt line.
|
35
56
|
def cookie_to_record(cookie)
|
@@ -1,13 +1,6 @@
|
|
1
|
+
# :markup: markdown
|
1
2
|
require 'http/cookie_jar'
|
2
3
|
|
3
|
-
# :stopdoc:
|
4
|
-
class Array
|
5
|
-
def sort_by!(&block)
|
6
|
-
replace(sort_by(&block))
|
7
|
-
end unless method_defined?(:sort_by!)
|
8
|
-
end
|
9
|
-
# :startdoc:
|
10
|
-
|
11
4
|
class HTTP::CookieJar
|
12
5
|
# A store class that uses a hash-based cookie store.
|
13
6
|
#
|
@@ -26,6 +19,9 @@ class HTTP::CookieJar
|
|
26
19
|
}
|
27
20
|
end
|
28
21
|
|
22
|
+
# :call-seq:
|
23
|
+
# new(**options)
|
24
|
+
#
|
29
25
|
# Generates a hash based cookie store.
|
30
26
|
#
|
31
27
|
# Available option keywords are as below:
|
@@ -50,6 +46,7 @@ class HTTP::CookieJar
|
|
50
46
|
@gc_index = 0
|
51
47
|
end
|
52
48
|
|
49
|
+
# The copy constructor. This store class supports cloning.
|
53
50
|
def initialize_copy(other)
|
54
51
|
@jar = Marshal.load(Marshal.dump(other.instance_variable_get(:@jar)))
|
55
52
|
end
|
@@ -67,7 +64,7 @@ class HTTP::CookieJar
|
|
67
64
|
self
|
68
65
|
end
|
69
66
|
|
70
|
-
def each(uri = nil)
|
67
|
+
def each(uri = nil) # :yield: cookie
|
71
68
|
now = Time.now
|
72
69
|
if uri
|
73
70
|
thost = DomainName.new(uri.host)
|
@@ -113,10 +110,6 @@ class HTTP::CookieJar
|
|
113
110
|
self
|
114
111
|
end
|
115
112
|
|
116
|
-
def empty?
|
117
|
-
@jar.empty?
|
118
|
-
end
|
119
|
-
|
120
113
|
def cleanup(session = false)
|
121
114
|
now = Time.now
|
122
115
|
all_cookies = []
|
@@ -68,6 +68,9 @@ class HTTP::CookieJar
|
|
68
68
|
end
|
69
69
|
# :startdoc:
|
70
70
|
|
71
|
+
# :call-seq:
|
72
|
+
# new(**options)
|
73
|
+
#
|
71
74
|
# Generates a Mozilla cookie store. If the file does not exist,
|
72
75
|
# it is created. If it does and its schema is old, it is
|
73
76
|
# automatically upgraded with a new schema keeping the existing
|
@@ -109,6 +112,7 @@ class HTTP::CookieJar
|
|
109
112
|
@gc_index = 0
|
110
113
|
end
|
111
114
|
|
115
|
+
# Raises TypeError. Cloning is inhibited in this store class.
|
112
116
|
def initialize_copy(other)
|
113
117
|
raise TypeError, 'can\'t clone %s' % self.class
|
114
118
|
end
|
@@ -138,7 +142,7 @@ class HTTP::CookieJar
|
|
138
142
|
|
139
143
|
protected
|
140
144
|
|
141
|
-
def schema_version=
|
145
|
+
def schema_version= version
|
142
146
|
@db.execute("PRAGMA user_version = %d" % version)
|
143
147
|
@schema_version = version
|
144
148
|
end
|
@@ -329,7 +333,7 @@ class HTTP::CookieJar
|
|
329
333
|
expiry >= :expiry
|
330
334
|
SQL
|
331
335
|
|
332
|
-
def each(uri = nil, &block)
|
336
|
+
def each(uri = nil, &block) # :yield: cookie
|
333
337
|
now = Time.now
|
334
338
|
if uri
|
335
339
|
thost = DomainName.new(uri.host)
|
@@ -398,19 +402,6 @@ class HTTP::CookieJar
|
|
398
402
|
self
|
399
403
|
end
|
400
404
|
|
401
|
-
SQL[:count] = <<-'SQL'
|
402
|
-
SELECT COUNT(id) FROM moz_cookies
|
403
|
-
SQL
|
404
|
-
|
405
|
-
def count
|
406
|
-
@stmt[:count].execute.first[0]
|
407
|
-
end
|
408
|
-
protected :count
|
409
|
-
|
410
|
-
def empty?
|
411
|
-
@sjar.empty? && count == 0
|
412
|
-
end
|
413
|
-
|
414
405
|
SQL[:delete_expired] = <<-'SQL'
|
415
406
|
DELETE FROM moz_cookies WHERE expiry < :expiry
|
416
407
|
SQL
|
@@ -1,9 +1,20 @@
|
|
1
|
+
# :markup: markdown
|
1
2
|
require 'http/cookie_jar'
|
2
3
|
require 'psych' if !defined?(YAML) && RUBY_VERSION == "1.9.2"
|
3
4
|
require 'yaml'
|
4
5
|
|
5
|
-
# YAMLSaver saves and loads cookies in the YAML format.
|
6
|
+
# YAMLSaver saves and loads cookies in the YAML format. It can load a
|
7
|
+
# YAML file saved by Mechanize, but the saving format is not
|
8
|
+
# compatible with older versions of Mechanize (< 2.7).
|
6
9
|
class HTTP::CookieJar::YAMLSaver < HTTP::CookieJar::AbstractSaver
|
10
|
+
# :singleton-method: new
|
11
|
+
# :call-seq:
|
12
|
+
# new(**options)
|
13
|
+
#
|
14
|
+
# There is no option keyword supported at the moment.
|
15
|
+
|
16
|
+
##
|
17
|
+
|
7
18
|
def save(io, jar)
|
8
19
|
YAML.dump(@session ? jar.to_a : jar.reject(&:session?), io)
|
9
20
|
end
|
@@ -42,7 +53,11 @@ class HTTP::CookieJar::YAMLSaver < HTTP::CookieJar::AbstractSaver
|
|
42
53
|
# YAML::Object of Syck
|
43
54
|
cookie_hash = cookie_hash.ivars
|
44
55
|
end
|
45
|
-
cookie = HTTP::Cookie.new(
|
56
|
+
cookie = HTTP::Cookie.new({}.tap { |hash|
|
57
|
+
cookie_hash.each_pair { |key, value|
|
58
|
+
hash[key.to_sym] = value
|
59
|
+
}
|
60
|
+
})
|
46
61
|
jar.add(cookie)
|
47
62
|
}
|
48
63
|
}
|
data/test/helper.rb
CHANGED
@@ -3,6 +3,30 @@ require 'test-unit'
|
|
3
3
|
require 'uri'
|
4
4
|
require 'http/cookie'
|
5
5
|
|
6
|
+
module Test
|
7
|
+
module Unit
|
8
|
+
module Assertions
|
9
|
+
def assert_warn(pattern, message = nil, &block)
|
10
|
+
class << (output = "")
|
11
|
+
alias write <<
|
12
|
+
end
|
13
|
+
stderr, $stderr = $stderr, output
|
14
|
+
yield
|
15
|
+
assert_match(pattern, output, message)
|
16
|
+
ensure
|
17
|
+
$stderr = stderr
|
18
|
+
end
|
19
|
+
|
20
|
+
def assert_warning(pattern, message = nil, &block)
|
21
|
+
verbose, $VERBOSE = $VERBOSE, true
|
22
|
+
assert_warn(pattern, message, &block)
|
23
|
+
ensure
|
24
|
+
$VERBOSE = verbose
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
6
30
|
module Enumerable
|
7
31
|
def combine
|
8
32
|
masks = inject([[], 1]){|(ar, m), e| [ar << m, m << 1 ] }[0]
|
@@ -23,3 +47,9 @@ end
|
|
23
47
|
def test_file(filename)
|
24
48
|
File.expand_path(filename, File.dirname(__FILE__))
|
25
49
|
end
|
50
|
+
|
51
|
+
def sleep_until(time)
|
52
|
+
if (s = time - Time.now) > 0
|
53
|
+
sleep s
|
54
|
+
end
|
55
|
+
end
|
data/test/test_http_cookie.rb
CHANGED
@@ -2,13 +2,6 @@
|
|
2
2
|
require File.expand_path('helper', File.dirname(__FILE__))
|
3
3
|
|
4
4
|
class TestHTTPCookie < Test::Unit::TestCase
|
5
|
-
def silently
|
6
|
-
warn_level, $VERBOSE = $VERBOSE, false
|
7
|
-
yield
|
8
|
-
ensure
|
9
|
-
$VERBOSE = warn_level
|
10
|
-
end
|
11
|
-
|
12
5
|
def setup
|
13
6
|
httpdate = 'Sun, 27-Sep-2037 00:00:00 GMT'
|
14
7
|
|
@@ -46,12 +39,10 @@ class TestHTTPCookie < Test::Unit::TestCase
|
|
46
39
|
|
47
40
|
dates.each do |date|
|
48
41
|
cookie = "PREF=1; expires=#{date}"
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
}.size
|
54
|
-
end
|
42
|
+
assert_equal 1, HTTP::Cookie.parse(cookie, url) { |c|
|
43
|
+
assert c.expires, "Tried parsing: #{date}"
|
44
|
+
assert_send [c.expires, :<, yesterday]
|
45
|
+
}.size
|
55
46
|
end
|
56
47
|
|
57
48
|
[
|
@@ -177,14 +168,12 @@ class TestHTTPCookie < Test::Unit::TestCase
|
|
177
168
|
"20/06/95 21:07",
|
178
169
|
]
|
179
170
|
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
assert_equal
|
184
|
-
|
185
|
-
|
186
|
-
end
|
187
|
-
end
|
171
|
+
dates.each { |date|
|
172
|
+
cookie = "PREF=1; expires=#{date}"
|
173
|
+
assert_equal 1, HTTP::Cookie.parse(cookie, url) { |c|
|
174
|
+
assert_equal(true, c.expires.nil?)
|
175
|
+
}.size
|
176
|
+
}
|
188
177
|
end
|
189
178
|
|
190
179
|
def test_parse_domain_dot
|
@@ -537,6 +526,30 @@ class TestHTTPCookie < Test::Unit::TestCase
|
|
537
526
|
cookie.acceptable?
|
538
527
|
}
|
539
528
|
|
529
|
+
# various keywords
|
530
|
+
[
|
531
|
+
["Expires", /use downcased symbol/],
|
532
|
+
].each { |key, pattern|
|
533
|
+
assert_warning(pattern, "warn of key: #{key.inspect}") {
|
534
|
+
cookie = HTTP::Cookie.new(:value => 'value', :name => 'key', key => expires.dup)
|
535
|
+
assert_equal 'key', cookie.name
|
536
|
+
assert_equal 'value', cookie.value
|
537
|
+
assert_equal expires, cookie.expires, "key: #{key.inspect}"
|
538
|
+
}
|
539
|
+
}
|
540
|
+
[
|
541
|
+
[:Expires, /unknown attribute name/],
|
542
|
+
[:expires?, /unknown attribute name/],
|
543
|
+
[[:expires], /invalid keyword/],
|
544
|
+
].each { |key, pattern|
|
545
|
+
assert_warning(pattern, "warn of key: #{key.inspect}") {
|
546
|
+
cookie = HTTP::Cookie.new(:value => 'value', :name => 'key', key => expires.dup)
|
547
|
+
assert_equal 'key', cookie.name
|
548
|
+
assert_equal 'value', cookie.value
|
549
|
+
assert_equal nil, cookie.expires, "key: #{key.inspect}"
|
550
|
+
}
|
551
|
+
}
|
552
|
+
|
540
553
|
cookie = HTTP::Cookie.new(:value => 'value', :name => 'key', :expires => expires.dup)
|
541
554
|
assert_equal 'key', cookie.name
|
542
555
|
assert_equal 'value', cookie.value
|
@@ -2,11 +2,63 @@ require File.expand_path('helper', File.dirname(__FILE__))
|
|
2
2
|
require 'tmpdir'
|
3
3
|
|
4
4
|
module TestHTTPCookieJar
|
5
|
+
class TestAutoloading < Test::Unit::TestCase
|
6
|
+
def test_nonexistent_store
|
7
|
+
assert_raises(NameError) {
|
8
|
+
HTTP::CookieJar::NonexistentStore
|
9
|
+
}
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_erroneous_store
|
13
|
+
Dir.mktmpdir { |dir|
|
14
|
+
Dir.mkdir(File.join(dir, 'http'))
|
15
|
+
Dir.mkdir(File.join(dir, 'http', 'cookie_jar'))
|
16
|
+
rb = File.join(dir, 'http', 'cookie_jar', 'erroneous_store.rb')
|
17
|
+
File.open(rb, 'w').close
|
18
|
+
$LOAD_PATH.unshift(dir)
|
19
|
+
|
20
|
+
assert_raises(NameError) {
|
21
|
+
HTTP::CookieJar::ErroneousStore
|
22
|
+
}
|
23
|
+
if RUBY_VERSION >= "1.9"
|
24
|
+
assert_includes $LOADED_FEATURES, rb
|
25
|
+
else
|
26
|
+
assert_includes $LOADED_FEATURES, rb[(dir.size + 1)..-1]
|
27
|
+
end
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_nonexistent_saver
|
32
|
+
assert_raises(NameError) {
|
33
|
+
HTTP::CookieJar::NonexistentSaver
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_erroneous_saver
|
38
|
+
Dir.mktmpdir { |dir|
|
39
|
+
Dir.mkdir(File.join(dir, 'http'))
|
40
|
+
Dir.mkdir(File.join(dir, 'http', 'cookie_jar'))
|
41
|
+
rb = File.join(dir, 'http', 'cookie_jar', 'erroneous_saver.rb')
|
42
|
+
File.open(rb, 'w').close
|
43
|
+
$LOAD_PATH.unshift(dir)
|
44
|
+
|
45
|
+
assert_raises(NameError) {
|
46
|
+
HTTP::CookieJar::ErroneousSaver
|
47
|
+
}
|
48
|
+
if RUBY_VERSION >= "1.9"
|
49
|
+
assert_includes $LOADED_FEATURES, rb
|
50
|
+
else
|
51
|
+
assert_includes $LOADED_FEATURES, rb[(dir.size + 1)..-1]
|
52
|
+
end
|
53
|
+
}
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
5
57
|
module CommonTests
|
6
58
|
def setup(options = nil, options2 = nil)
|
7
59
|
default_options = {
|
8
60
|
:store => :hash,
|
9
|
-
:gc_threshold =>
|
61
|
+
:gc_threshold => 1500, # increased by 10 for shorter test time
|
10
62
|
}
|
11
63
|
new_options = default_options.merge(options || {})
|
12
64
|
new_options2 = new_options.merge(options2 || {})
|
@@ -692,7 +744,7 @@ module TestHTTPCookieJar
|
|
692
744
|
@jar.cleanup
|
693
745
|
count = @jar.to_a.size
|
694
746
|
assert_equal limit_per_domain, count
|
695
|
-
assert_equal [*1..
|
747
|
+
assert_equal [*1..(limit_per_domain + 1)] - [42], @jar.map { |cookie|
|
696
748
|
cookie.name[/(\d+)$/].to_i
|
697
749
|
}.sort
|
698
750
|
|
@@ -749,6 +801,46 @@ module TestHTTPCookieJar
|
|
749
801
|
assert_equal %w[Akinori Japan], cookies.map { |c| c.value }
|
750
802
|
assert_equal %w[Japan Akinori], @jar.to_a.sort_by { |c| c.name }.map { |c| c.value }
|
751
803
|
end
|
804
|
+
|
805
|
+
def test_expire_by_each_and_cleanup
|
806
|
+
uri = URI('http://www.example.org/')
|
807
|
+
|
808
|
+
ts = Time.now.to_f
|
809
|
+
if ts % 1 > 0.5
|
810
|
+
sleep 0.5
|
811
|
+
ts += 0.5
|
812
|
+
end
|
813
|
+
expires = Time.at(ts.floor)
|
814
|
+
time = expires
|
815
|
+
|
816
|
+
if mozilla_store?
|
817
|
+
# MozillaStore only has the time precision of seconds.
|
818
|
+
time = expires
|
819
|
+
expires -= 1
|
820
|
+
end
|
821
|
+
|
822
|
+
0.upto(2) { |i|
|
823
|
+
c = HTTP::Cookie.new('Foo%d' % (3 - i), 'Bar', :expires => expires + i, :origin => uri)
|
824
|
+
@jar << c
|
825
|
+
@jar2 << c
|
826
|
+
}
|
827
|
+
|
828
|
+
assert_equal %w[Foo1 Foo2], @jar.cookies.map(&:name)
|
829
|
+
assert_equal %w[Foo1 Foo2], @jar2.cookies(uri).map(&:name)
|
830
|
+
|
831
|
+
sleep_until time + 1
|
832
|
+
|
833
|
+
assert_equal %w[Foo1], @jar.cookies.map(&:name)
|
834
|
+
assert_equal %w[Foo1], @jar2.cookies(uri).map(&:name)
|
835
|
+
|
836
|
+
sleep_until time + 2
|
837
|
+
|
838
|
+
@jar.cleanup
|
839
|
+
@jar2.cleanup
|
840
|
+
|
841
|
+
assert_send [@jar, :empty?]
|
842
|
+
assert_send [@jar2, :empty?]
|
843
|
+
end
|
752
844
|
end
|
753
845
|
|
754
846
|
class WithHashStore < Test::Unit::TestCase
|
@@ -770,6 +862,20 @@ module TestHTTPCookieJar
|
|
770
862
|
}
|
771
863
|
end
|
772
864
|
|
865
|
+
def test_clone
|
866
|
+
jar = @jar.clone
|
867
|
+
assert_not_send [
|
868
|
+
@jar.store,
|
869
|
+
:equal?,
|
870
|
+
jar.store
|
871
|
+
]
|
872
|
+
assert_not_send [
|
873
|
+
@jar.store.instance_variable_get(:@jar),
|
874
|
+
:equal?,
|
875
|
+
jar.store.instance_variable_get(:@jar)
|
876
|
+
]
|
877
|
+
assert_equal @jar.cookies, jar.cookies
|
878
|
+
end
|
773
879
|
end
|
774
880
|
|
775
881
|
class WithMozillaStore < Test::Unit::TestCase
|
@@ -789,6 +895,12 @@ module TestHTTPCookieJar
|
|
789
895
|
jar.delete(HTTP::Cookie.new("name", :domain => 'rubyforge.org'))
|
790
896
|
end
|
791
897
|
|
898
|
+
def test_clone
|
899
|
+
assert_raises(TypeError) {
|
900
|
+
@jar.clone
|
901
|
+
}
|
902
|
+
end
|
903
|
+
|
792
904
|
def test_close
|
793
905
|
add_and_delete(@jar)
|
794
906
|
|
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
|
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-17 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: domain_name
|
@@ -161,9 +161,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
161
161
|
version: '0'
|
162
162
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
163
163
|
requirements:
|
164
|
-
- - '
|
164
|
+
- - '>='
|
165
165
|
- !ruby/object:Gem::Version
|
166
|
-
version:
|
166
|
+
version: '0'
|
167
167
|
requirements: []
|
168
168
|
rubyforge_project:
|
169
169
|
rubygems_version: 2.0.3
|