http-cookie 1.0.0.pre12 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|