cookiejar 0.3.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +10 -0
- data/README.markdown +17 -0
- data/Rakefile +31 -0
- data/contributors.json +14 -0
- data/lib/cookiejar/cookie.rb +64 -53
- data/lib/cookiejar/cookie_validation.rb +50 -45
- data/lib/cookiejar/jar.rb +110 -106
- data/{test/cookie_test.rb → spec/cookie_spec.rb} +1 -1
- data/{test/cookie_validation_test.rb → spec/cookie_validation_spec.rb} +5 -0
- data/{test/jar_test.rb → spec/jar_spec.rb} +11 -2
- metadata +74 -47
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 97cc2e91638c2a60db2cc19a4ccf0ad0e2d97954
|
4
|
+
data.tar.gz: 8f4800820d1c7430437e4105dec116324f3db4ee
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8f42ea0a868ff3c9d17c141756b3f8596f23d0e00a233ca9c13090de983b97e0093e4a59aba121e875113dfef635c9994d0d8ba5d852fd3a4e2ff2dca82025d7
|
7
|
+
data.tar.gz: bb6215c18b5c5ac93523f6fa208ea8939904a75da4eeaa95c868022af83242998af70e627e3ffc2977b8869d742651b385e1ee47bdc12f7373dd34cce46a5592
|
data/LICENSE
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
Copyright (c) 2009 - 2014, David Waite and Other Contributors
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
5
|
+
|
6
|
+
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
7
|
+
|
8
|
+
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
9
|
+
|
10
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.markdown
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
Ruby CookieJar
|
2
|
+
==============
|
3
|
+
|
4
|
+
**Git**: [http://github.com/dwaite/cookiejar](http://github.com/dwaite/cookiejar)
|
5
|
+
|
6
|
+
**Author**: David Waite
|
7
|
+
|
8
|
+
Synopsis
|
9
|
+
--------
|
10
|
+
|
11
|
+
The Ruby CookieJar is a library to help manage client-side cookies in pure Ruby. It enables parsing and setting of cookie headers, alternating between multiple 'jars' of cookies at one time (such as having a set of cookies for each browser or thread), and supports persistence of the cookies in a JSON string.
|
12
|
+
|
13
|
+
Both Netscape/RFC 2109 cookies and RFC 2965 cookies are supported.
|
14
|
+
|
15
|
+
COPYRIGHT
|
16
|
+
---------
|
17
|
+
The Ruby CookieJar is Copyright © 2009 David Waite. Licensing terms are given within the LICENSE file.
|
data/Rakefile
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'rake'
|
2
|
+
|
3
|
+
require 'rake/clean'
|
4
|
+
require 'rake/packagetask'
|
5
|
+
require 'yard'
|
6
|
+
require 'yard/rake/yardoc_task'
|
7
|
+
|
8
|
+
require 'fileutils'
|
9
|
+
include FileUtils
|
10
|
+
|
11
|
+
# Default Rake task is to run all tests
|
12
|
+
task :default => :test
|
13
|
+
CLEAN << Rake::FileList['doc/**', '.yardoc']
|
14
|
+
#Yard
|
15
|
+
YARD::Rake::YardocTask.new do |t|
|
16
|
+
t.files = ['lib/**/*.rb'] # optional
|
17
|
+
t.options = ['--title', 'CookieJar, a HTTP Client Cookie Parsing Library',
|
18
|
+
'--main', 'README.markdown', '--files', 'LICENSE']
|
19
|
+
end
|
20
|
+
|
21
|
+
begin
|
22
|
+
require 'rspec/core/rake_task'
|
23
|
+
|
24
|
+
RSpec::Core::RakeTask.new do |t|
|
25
|
+
# t.libs << 'lib'
|
26
|
+
# t.pattern = 'test/**/*_test.rb'
|
27
|
+
end
|
28
|
+
task :test => :spec
|
29
|
+
rescue LoadError
|
30
|
+
puts "Warning: unable to load rspec tasks"
|
31
|
+
end
|
data/contributors.json
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
[
|
2
|
+
{
|
3
|
+
"author": {
|
4
|
+
"github": "http://github.com/secobarbital",
|
5
|
+
"name": "Seggy Umboh"
|
6
|
+
},
|
7
|
+
"contributions": [
|
8
|
+
"widen supported IP addresses",
|
9
|
+
"fix case-sensitivity issue with HTTP headers",
|
10
|
+
"correct issue when running under Ruby 1.8.x",
|
11
|
+
"made Jar act more like a browser (dropping cookies w/o exception)"
|
12
|
+
]
|
13
|
+
}
|
14
|
+
]
|
data/lib/cookiejar/cookie.rb
CHANGED
@@ -3,25 +3,25 @@ require 'uri'
|
|
3
3
|
require 'cookiejar/cookie_validation'
|
4
4
|
|
5
5
|
module CookieJar
|
6
|
-
|
6
|
+
|
7
7
|
# Cookie is an immutable object which defines the data model of a HTTP Cookie.
|
8
8
|
# The data values within the cookie may be different from the
|
9
9
|
# values described in the literal cookie declaration.
|
10
|
-
# Specifically, the 'domain' and 'path' values may be set to defaults
|
10
|
+
# Specifically, the 'domain' and 'path' values may be set to defaults
|
11
11
|
# based on the requested resource that resulted in the cookie being set.
|
12
12
|
class Cookie
|
13
|
-
|
13
|
+
|
14
14
|
# [String] The name of the cookie.
|
15
15
|
attr_reader :name
|
16
16
|
# [String] The value of the cookie, without any attempts at decoding.
|
17
17
|
attr_reader :value
|
18
|
-
|
19
|
-
# [String] The domain scope of the cookie. Follows the RFC 2965
|
18
|
+
|
19
|
+
# [String] The domain scope of the cookie. Follows the RFC 2965
|
20
20
|
# 'effective host' rules. A 'dot' prefix indicates that it applies both
|
21
21
|
# to the non-dotted domain and child domains, while no prefix indicates
|
22
22
|
# that only exact matches of the domain are in scope.
|
23
23
|
attr_reader :domain
|
24
|
-
|
24
|
+
|
25
25
|
# [String] The path scope of the cookie. The cookie applies to URI paths
|
26
26
|
# that prefix match this value.
|
27
27
|
attr_reader :path
|
@@ -35,7 +35,7 @@ module CookieJar
|
|
35
35
|
# [Boolean] Popular browser extension to mark a cookie as invisible
|
36
36
|
# to code running within the browser, such as JavaScript
|
37
37
|
attr_reader :http_only
|
38
|
-
|
38
|
+
|
39
39
|
# [Fixnum] Version indicator, currently either
|
40
40
|
# * 0 for netscape cookies
|
41
41
|
# * 1 for RFC 2965 cookies
|
@@ -43,11 +43,11 @@ module CookieJar
|
|
43
43
|
# [String] RFC 2965 field for indicating comment (or a location)
|
44
44
|
# describing the cookie to a usesr agent.
|
45
45
|
attr_reader :comment, :comment_url
|
46
|
-
# [Boolean] RFC 2965 field for indicating session lifetime for a cookie
|
46
|
+
# [Boolean] RFC 2965 field for indicating session lifetime for a cookie
|
47
47
|
attr_reader :discard
|
48
48
|
# [Array<FixNum>, nil] RFC 2965 port scope for the cookie. If not nil,
|
49
49
|
# indicates specific ports on the HTTP server which should receive this
|
50
|
-
# cookie if contacted.
|
50
|
+
# cookie if contacted.
|
51
51
|
attr_reader :ports
|
52
52
|
# [Time] Time when this cookie was first evaluated and created.
|
53
53
|
attr_reader :created_at
|
@@ -63,7 +63,7 @@ module CookieJar
|
|
63
63
|
@created_at + @expiry
|
64
64
|
end
|
65
65
|
end
|
66
|
-
|
66
|
+
|
67
67
|
# Indicates whether the cookie is currently considered valid
|
68
68
|
#
|
69
69
|
# @param [Time] time to compare against, or 'now' if omitted
|
@@ -74,11 +74,11 @@ module CookieJar
|
|
74
74
|
|
75
75
|
# Indicates whether the cookie will be considered invalid after the end
|
76
76
|
# of the current user session
|
77
|
-
# @return [Boolean]
|
77
|
+
# @return [Boolean]
|
78
78
|
def session?
|
79
79
|
@expiry == nil || @discard
|
80
80
|
end
|
81
|
-
|
81
|
+
|
82
82
|
# Create a cookie based on an absolute URI and the string value of a
|
83
83
|
# 'Set-Cookie' header.
|
84
84
|
#
|
@@ -88,10 +88,12 @@ module CookieJar
|
|
88
88
|
# @param set_cookie_value [String] HTTP value for the Set-Cookie header.
|
89
89
|
# @return [Cookie] created from the header string and request URI
|
90
90
|
# @raise [InvalidCookieError] on validation failure(s)
|
91
|
-
def self.from_set_cookie request_uri, set_cookie_value
|
91
|
+
def self.from_set_cookie request_uri, set_cookie_value
|
92
92
|
args = CookieJar::CookieValidation.parse_set_cookie set_cookie_value
|
93
|
-
args[:domain] = CookieJar::CookieValidation.
|
94
|
-
|
93
|
+
args[:domain] = CookieJar::CookieValidation.
|
94
|
+
determine_cookie_domain request_uri, args[:domain]
|
95
|
+
args[:path] = CookieJar::CookieValidation.
|
96
|
+
determine_cookie_path request_uri, args[:path]
|
95
97
|
cookie = Cookie.new args
|
96
98
|
CookieJar::CookieValidation.validate_cookie request_uri, cookie
|
97
99
|
cookie
|
@@ -106,18 +108,20 @@ module CookieJar
|
|
106
108
|
# @param set_cookie_value [String] HTTP value for the Set-Cookie2 header.
|
107
109
|
# @return [Cookie] created from the header string and request URI
|
108
110
|
# @raise [InvalidCookieError] on validation failure(s)
|
109
|
-
def self.from_set_cookie2 request_uri, set_cookie_value
|
111
|
+
def self.from_set_cookie2 request_uri, set_cookie_value
|
110
112
|
args = CookieJar::CookieValidation.parse_set_cookie2 set_cookie_value
|
111
|
-
args[:domain] = CookieJar::CookieValidation.
|
112
|
-
|
113
|
+
args[:domain] = CookieJar::CookieValidation.
|
114
|
+
determine_cookie_domain request_uri, args[:domain]
|
115
|
+
args[:path] = CookieJar::CookieValidation.
|
116
|
+
determine_cookie_path request_uri, args[:path]
|
113
117
|
cookie = Cookie.new args
|
114
118
|
CookieJar::CookieValidation.validate_cookie request_uri, cookie
|
115
119
|
cookie
|
116
120
|
end
|
117
|
-
|
121
|
+
|
118
122
|
# Returns cookie in a format appropriate to send to a server.
|
119
123
|
#
|
120
|
-
# @param [FixNum] 0 version, 0 for Netscape-style cookies, 1 for
|
124
|
+
# @param [FixNum] 0 version, 0 for Netscape-style cookies, 1 for
|
121
125
|
# RFC2965-style.
|
122
126
|
# @param [Boolean] true prefix, for RFC2965, whether to prefix with
|
123
127
|
# "$Version=<version>;". Ignored for Netscape-style cookies
|
@@ -140,6 +144,33 @@ module CookieJar
|
|
140
144
|
end
|
141
145
|
end
|
142
146
|
|
147
|
+
|
148
|
+
# Return a hash representation of the cookie.
|
149
|
+
|
150
|
+
def to_hash
|
151
|
+
result = {
|
152
|
+
:name => @name,
|
153
|
+
:value => @value,
|
154
|
+
:domain => @domain,
|
155
|
+
:path => @path,
|
156
|
+
:created_at => @created_at
|
157
|
+
}
|
158
|
+
{
|
159
|
+
:expiry => @expiry,
|
160
|
+
:secure => (true if @secure),
|
161
|
+
:http_only => (true if @http_only),
|
162
|
+
:version => (@version if version != 0),
|
163
|
+
:comment => @comment,
|
164
|
+
:comment_url => @comment_url,
|
165
|
+
:discard => (true if @discard),
|
166
|
+
:ports => @ports
|
167
|
+
}.each do |name, value|
|
168
|
+
result[name] = value if value
|
169
|
+
end
|
170
|
+
|
171
|
+
result
|
172
|
+
end
|
173
|
+
|
143
174
|
# Determine if a cookie should be sent given a request URI along with
|
144
175
|
# other options.
|
145
176
|
#
|
@@ -156,47 +187,27 @@ module CookieJar
|
|
156
187
|
# being sent over http, and it must not be a http_only cookie sent to
|
157
188
|
# a script
|
158
189
|
path_match = uri.path.start_with? @path
|
159
|
-
secure_match = !(@secure && uri.scheme == 'http')
|
190
|
+
secure_match = !(@secure && uri.scheme == 'http')
|
160
191
|
script_match = !(script && @http_only)
|
161
192
|
expiry_match = !expired?
|
162
193
|
ports_match = ports.nil? || (ports.include? uri.port)
|
163
194
|
path_match && secure_match && script_match && expiry_match && ports_match
|
164
195
|
end
|
165
|
-
|
196
|
+
|
166
197
|
def decoded_value
|
167
198
|
CookieJar::CookieValidation::decode_value value
|
168
199
|
end
|
169
|
-
|
200
|
+
|
170
201
|
# Return a JSON 'object' for the various data values. Allows for
|
171
202
|
# persistence of the cookie information
|
172
203
|
#
|
173
|
-
# @param [Array] a options controlling output JSON text
|
204
|
+
# @param [Array] a options controlling output JSON text
|
174
205
|
# (usually a State and a depth)
|
175
206
|
# @return [String] JSON representation of object data
|
176
207
|
def to_json *a
|
177
|
-
|
178
|
-
:json_class => self.class.name,
|
179
|
-
:name => @name,
|
180
|
-
:value => @value,
|
181
|
-
:domain => @domain,
|
182
|
-
:path => @path,
|
183
|
-
:created_at => @created_at
|
184
|
-
}
|
185
|
-
{
|
186
|
-
:expiry => @expiry,
|
187
|
-
:secure => (true if @secure),
|
188
|
-
:http_only => (true if @http_only),
|
189
|
-
:version => (@version if version != 0),
|
190
|
-
:comment => @comment,
|
191
|
-
:comment_url => @comment_url,
|
192
|
-
:discard => (true if @discard),
|
193
|
-
:ports => @ports
|
194
|
-
}.each do |name, value|
|
195
|
-
result[name] = value if value
|
196
|
-
end
|
197
|
-
result.to_json(*a)
|
208
|
+
to_hash.merge(:json_class => self.class.name).to_json(*a)
|
198
209
|
end
|
199
|
-
|
210
|
+
|
200
211
|
# Given a Hash representation of a JSON document, create a local cookie
|
201
212
|
# from the included data.
|
202
213
|
#
|
@@ -218,7 +229,7 @@ module CookieJar
|
|
218
229
|
|
219
230
|
self.new params
|
220
231
|
end
|
221
|
-
|
232
|
+
|
222
233
|
# Compute the cookie search domains for a given request URI
|
223
234
|
# This will be the effective host of the request uri, along with any
|
224
235
|
# possibly matching dot-prefixed domains
|
@@ -231,22 +242,22 @@ module CookieJar
|
|
231
242
|
protected
|
232
243
|
# Call {from_set_cookie} to create a new Cookie instance
|
233
244
|
def initialize args
|
234
|
-
|
235
|
-
@created_at, @name, @value, @domain, @path, @secure,
|
245
|
+
|
246
|
+
@created_at, @name, @value, @domain, @path, @secure,
|
236
247
|
@http_only, @version, @comment, @comment_url, @discard, @ports \
|
237
248
|
= args.values_at \
|
238
|
-
:created_at, :name, :value, :domain, :path, :secure,
|
249
|
+
:created_at, :name, :value, :domain, :path, :secure,
|
239
250
|
:http_only, :version, :comment, :comment_url, :discard, :ports
|
240
251
|
|
241
252
|
@created_at ||= Time.now
|
242
|
-
@expiry = args[:max_age] || args[:expires_at]
|
253
|
+
@expiry = args[:max_age] || args[:expires_at]
|
243
254
|
@secure ||= false
|
244
255
|
@http_only ||= false
|
245
256
|
@discard ||= false
|
246
|
-
|
257
|
+
|
247
258
|
if @ports.is_a? Integer
|
248
259
|
@ports = [@ports]
|
249
260
|
end
|
250
261
|
end
|
251
262
|
end
|
252
|
-
end
|
263
|
+
end
|
@@ -5,7 +5,7 @@ module CookieJar
|
|
5
5
|
class InvalidCookieError < StandardError
|
6
6
|
# [Array<String>] the specific validation issues encountered
|
7
7
|
attr_reader :messages
|
8
|
-
|
8
|
+
|
9
9
|
# Create a new instance
|
10
10
|
# @param [String, Array<String>] the validation issue(s) encountered
|
11
11
|
def initialize message
|
@@ -18,7 +18,7 @@ module CookieJar
|
|
18
18
|
super message
|
19
19
|
end
|
20
20
|
end
|
21
|
-
|
21
|
+
|
22
22
|
# Contains logic to parse and validate cookie headers
|
23
23
|
module CookieValidation
|
24
24
|
module PATTERN
|
@@ -45,7 +45,7 @@ module CookieJar
|
|
45
45
|
PARAM1 = /\A(#{PATTERN::TOKEN})(?:=#{PATTERN::VALUE1})?\Z/
|
46
46
|
PARAM2 = Regexp.new "(#{PATTERN::TOKEN})(?:=(#{PATTERN::VALUE2}))?(?:\\Z|;)", '', 'n'
|
47
47
|
# TWO_DOT_DOMAINS = /\A\.(com|edu|net|mil|gov|int|org)\Z/
|
48
|
-
|
48
|
+
|
49
49
|
# Converts the input object to a URI (if not already a URI)
|
50
50
|
#
|
51
51
|
# @param [String, URI] request_uri URI we are normalizing
|
@@ -53,7 +53,7 @@ module CookieJar
|
|
53
53
|
def self.to_uri request_uri
|
54
54
|
(request_uri.is_a? URI)? request_uri : (URI.parse request_uri)
|
55
55
|
end
|
56
|
-
|
56
|
+
|
57
57
|
# Converts an input cookie or uri to a string representing the path.
|
58
58
|
# Assume strings are already paths
|
59
59
|
#
|
@@ -66,10 +66,10 @@ module CookieJar
|
|
66
66
|
uri_or_path
|
67
67
|
end
|
68
68
|
end
|
69
|
-
|
69
|
+
|
70
70
|
# Converts an input cookie or uri to a string representing the domain.
|
71
71
|
# Assume strings are already domains. Value may not be an effective host.
|
72
|
-
#
|
72
|
+
#
|
73
73
|
# @param [String, URI, Cookie] object containing the domain
|
74
74
|
# @return [String] domain information.
|
75
75
|
def self.to_domain uri_or_domain
|
@@ -81,7 +81,7 @@ module CookieJar
|
|
81
81
|
uri_or_domain
|
82
82
|
end
|
83
83
|
end
|
84
|
-
|
84
|
+
|
85
85
|
# Compare a tested domain against the base domain to see if they match, or
|
86
86
|
# if the base domain is reachable.
|
87
87
|
#
|
@@ -91,11 +91,11 @@ module CookieJar
|
|
91
91
|
def self.domains_match tested_domain, base_domain
|
92
92
|
base = effective_host base_domain
|
93
93
|
search_domains = compute_search_domains_for_host base
|
94
|
-
result = search_domains.find do |domain|
|
95
|
-
domain == tested_domain
|
94
|
+
result = search_domains.find do |domain|
|
95
|
+
domain == tested_domain
|
96
96
|
end
|
97
97
|
end
|
98
|
-
|
98
|
+
|
99
99
|
# Compute the reach of a hostname (RFC 2965, section 1)
|
100
100
|
# Determines the next highest superdomain
|
101
101
|
#
|
@@ -109,7 +109,7 @@ module CookieJar
|
|
109
109
|
match[1]
|
110
110
|
end
|
111
111
|
end
|
112
|
-
|
112
|
+
|
113
113
|
# Compute the base of a path, for default cookie path assignment
|
114
114
|
#
|
115
115
|
# @param [String, URI, Cookie] path, or object holding path
|
@@ -117,7 +117,7 @@ module CookieJar
|
|
117
117
|
def self.cookie_base_path path
|
118
118
|
BASE_PATH.match(to_path path)[1]
|
119
119
|
end
|
120
|
-
|
120
|
+
|
121
121
|
# Processes cookie path data using the following rules:
|
122
122
|
# Paths are separated by '/' characters, and accepted values are truncated
|
123
123
|
# to the last '/' character. If no path is specified in the cookie, a path
|
@@ -131,17 +131,17 @@ module CookieJar
|
|
131
131
|
def self.determine_cookie_path request_uri, cookie_path
|
132
132
|
uri = to_uri request_uri
|
133
133
|
cookie_path = to_path cookie_path
|
134
|
-
|
134
|
+
|
135
135
|
if cookie_path == nil || cookie_path.empty?
|
136
136
|
cookie_path = cookie_base_path uri.path
|
137
137
|
end
|
138
138
|
cookie_path
|
139
139
|
end
|
140
|
-
|
140
|
+
|
141
141
|
# Given a URI, compute the relevant search domains for pre-existing
|
142
142
|
# cookies. This includes all the valid dotted forms for a named or IP
|
143
143
|
# domains.
|
144
|
-
#
|
144
|
+
#
|
145
145
|
# @param [String, URI] request_uri requested uri
|
146
146
|
# @return [Array<String>] all cookie domain values which would match the
|
147
147
|
# requested uri
|
@@ -150,7 +150,7 @@ module CookieJar
|
|
150
150
|
host = uri.host
|
151
151
|
compute_search_domains_for_host host
|
152
152
|
end
|
153
|
-
|
153
|
+
|
154
154
|
# Given a host, compute the relevant search domains for pre-existing
|
155
155
|
# cookies
|
156
156
|
#
|
@@ -169,7 +169,7 @@ module CookieJar
|
|
169
169
|
end
|
170
170
|
result
|
171
171
|
end
|
172
|
-
|
172
|
+
|
173
173
|
# Processes cookie domain data using the following rules:
|
174
174
|
# Domains strings of the form .foo.com match 'foo.com' and all immediate
|
175
175
|
# subdomains of 'foo.com'. Domain strings specified of the form 'foo.com' are
|
@@ -189,7 +189,7 @@ module CookieJar
|
|
189
189
|
def self.determine_cookie_domain request_uri, cookie_domain
|
190
190
|
uri = to_uri request_uri
|
191
191
|
domain = to_domain cookie_domain
|
192
|
-
|
192
|
+
|
193
193
|
if domain == nil || domain.empty?
|
194
194
|
domain = effective_host uri.host
|
195
195
|
else
|
@@ -197,11 +197,11 @@ module CookieJar
|
|
197
197
|
if domain =~ IPADDR || domain.start_with?('.')
|
198
198
|
domain
|
199
199
|
else
|
200
|
-
".#{domain}"
|
200
|
+
".#{domain}"
|
201
201
|
end
|
202
202
|
end
|
203
203
|
end
|
204
|
-
|
204
|
+
|
205
205
|
# Compute the effective host (RFC 2965, section 1)
|
206
206
|
#
|
207
207
|
# Has the added additional logic of searching for interior dots specifically, and
|
@@ -212,15 +212,15 @@ module CookieJar
|
|
212
212
|
def self.effective_host host_or_uri
|
213
213
|
hostname = to_domain host_or_uri
|
214
214
|
hostname = hostname.downcase
|
215
|
-
|
215
|
+
|
216
216
|
if /.[\.:]./.match(hostname) || hostname == '.local'
|
217
217
|
hostname
|
218
218
|
else
|
219
219
|
hostname + '.local'
|
220
220
|
end
|
221
221
|
end
|
222
|
-
|
223
|
-
# Check whether a cookie meets all of the rules to be created, based on
|
222
|
+
|
223
|
+
# Check whether a cookie meets all of the rules to be created, based on
|
224
224
|
# its internal settings and the URI it came from.
|
225
225
|
#
|
226
226
|
# @param [String,URI] request_uri originally requested URI
|
@@ -234,12 +234,12 @@ module CookieJar
|
|
234
234
|
request_secure = (uri.scheme == 'https')
|
235
235
|
cookie_host = cookie.domain
|
236
236
|
cookie_path = cookie.path
|
237
|
-
|
237
|
+
|
238
238
|
errors = []
|
239
|
-
|
239
|
+
|
240
240
|
# From RFC 2965, Section 3.3.2 Rejecting Cookies
|
241
|
-
|
242
|
-
# A user agent rejects (SHALL NOT store its information) if the
|
241
|
+
|
242
|
+
# A user agent rejects (SHALL NOT store its information) if the
|
243
243
|
# Version attribute is missing. Note that the legacy Set-Cookie
|
244
244
|
# directive will result in an implicit version 0.
|
245
245
|
unless cookie.version
|
@@ -247,7 +247,7 @@ module CookieJar
|
|
247
247
|
end
|
248
248
|
|
249
249
|
# The value for the Path attribute is not a prefix of the request-URI
|
250
|
-
unless request_path.start_with? cookie_path
|
250
|
+
unless request_path.start_with? cookie_path
|
251
251
|
errors << "Path is not a prefix of the request uri path"
|
252
252
|
end
|
253
253
|
|
@@ -256,7 +256,7 @@ module CookieJar
|
|
256
256
|
cookie_host == '.local' #is the domain cookie for local addresses
|
257
257
|
errors << "Domain format is illegal"
|
258
258
|
end
|
259
|
-
|
259
|
+
|
260
260
|
# The effective host name that derives from the request-host does
|
261
261
|
# not domain-match the Domain attribute.
|
262
262
|
#
|
@@ -266,7 +266,7 @@ module CookieJar
|
|
266
266
|
unless domains_match cookie_host, uri
|
267
267
|
errors << "Domain is inappropriate based on request URI hostname"
|
268
268
|
end
|
269
|
-
|
269
|
+
|
270
270
|
# The Port attribute has a "port-list", and the request-port was
|
271
271
|
# not in the list.
|
272
272
|
unless cookie.ports.nil? || cookie.ports.length != 0
|
@@ -275,24 +275,24 @@ module CookieJar
|
|
275
275
|
end
|
276
276
|
end
|
277
277
|
|
278
|
-
raise
|
278
|
+
raise InvalidCookieError.new(errors) unless errors.empty?
|
279
279
|
|
280
280
|
# Note: 'secure' is not explicitly defined as an SSL channel, and no
|
281
281
|
# test is defined around validity and the 'secure' attribute
|
282
282
|
true
|
283
283
|
end
|
284
|
-
|
284
|
+
|
285
285
|
# Break apart a traditional (non RFC 2965) cookie value into its core
|
286
286
|
# components. This does not do any validation, or defaulting of values
|
287
287
|
# based on requested URI
|
288
|
-
#
|
288
|
+
#
|
289
289
|
# @param [String] set_cookie_value a Set-Cookie header formatted cookie
|
290
290
|
# definition
|
291
291
|
# @return [Hash] Contains the parsed values of the cookie
|
292
292
|
def self.parse_set_cookie set_cookie_value
|
293
293
|
args = { }
|
294
|
-
params=set_cookie_value.split
|
295
|
-
|
294
|
+
params=set_cookie_value.split(/;\s*/)
|
295
|
+
|
296
296
|
first=true
|
297
297
|
params.each do |param|
|
298
298
|
result = PARAM1.match param
|
@@ -308,7 +308,12 @@ module CookieJar
|
|
308
308
|
else
|
309
309
|
case key
|
310
310
|
when :expires
|
311
|
-
|
311
|
+
begin
|
312
|
+
args[:expires_at] = Time.parse keyvalue
|
313
|
+
rescue ArgumentError
|
314
|
+
raise unless $!.message == "time out of range"
|
315
|
+
args[:expires_at] = Time.at(0x7FFFFFFF)
|
316
|
+
end
|
312
317
|
when *[:domain, :path]
|
313
318
|
args[key] = keyvalue
|
314
319
|
when :secure
|
@@ -323,7 +328,7 @@ module CookieJar
|
|
323
328
|
args[:version] = 0
|
324
329
|
args
|
325
330
|
end
|
326
|
-
|
331
|
+
|
327
332
|
# Parse a RFC 2965 value and convert to a literal string
|
328
333
|
def self.value_to_string value
|
329
334
|
if /\A"(.*)"\Z/.match value
|
@@ -333,7 +338,7 @@ module CookieJar
|
|
333
338
|
value
|
334
339
|
end
|
335
340
|
end
|
336
|
-
|
341
|
+
|
337
342
|
# Attempt to decipher a partially decoded version of text cookie values
|
338
343
|
def self.decode_value value
|
339
344
|
if /\A"(.*)"\Z/.match value
|
@@ -342,11 +347,11 @@ module CookieJar
|
|
342
347
|
CGI.unescape value
|
343
348
|
end
|
344
349
|
end
|
345
|
-
|
346
|
-
# Break apart a RFC 2965 cookie value into its core components.
|
350
|
+
|
351
|
+
# Break apart a RFC 2965 cookie value into its core components.
|
347
352
|
# This does not do any validation, or defaulting of values
|
348
353
|
# based on requested URI
|
349
|
-
#
|
354
|
+
#
|
350
355
|
# @param [String] set_cookie_value a Set-Cookie2 header formatted cookie
|
351
356
|
# definition
|
352
357
|
# @return [Hash] Contains the parsed values of the cookie
|
@@ -360,7 +365,7 @@ module CookieJar
|
|
360
365
|
raise InvalidCookieError.new "Invalid Set-Cookie2 header '#{set_cookie_value}'"
|
361
366
|
end
|
362
367
|
index+=md.offset(0)[1]
|
363
|
-
|
368
|
+
|
364
369
|
key = md[1].downcase.to_sym
|
365
370
|
keyvalue = md[2] || md[3]
|
366
371
|
if first
|
@@ -382,7 +387,7 @@ module CookieJar
|
|
382
387
|
args[:version] = keyvalue.to_i
|
383
388
|
when :port
|
384
389
|
# must be in format '"port,port"'
|
385
|
-
ports = keyvalue.split
|
390
|
+
ports = keyvalue.split(/,\s*/)
|
386
391
|
args[:ports] = ports.map do |portstr| portstr.to_i end
|
387
392
|
else
|
388
393
|
raise InvalidCookieError.new "Unknown cookie parameter '#{key}'"
|
@@ -393,8 +398,8 @@ module CookieJar
|
|
393
398
|
if args[:version] != 1
|
394
399
|
raise InvalidCookieError.new "Set-Cookie2 declares a non RFC2965 version cookie"
|
395
400
|
end
|
396
|
-
|
401
|
+
|
397
402
|
args
|
398
|
-
end
|
403
|
+
end
|
399
404
|
end
|
400
405
|
end
|
data/lib/cookiejar/jar.rb
CHANGED
@@ -1,23 +1,23 @@
|
|
1
1
|
require 'cookiejar/cookie'
|
2
|
-
|
2
|
+
|
3
3
|
module CookieJar
|
4
|
-
# A cookie store for client side usage.
|
4
|
+
# A cookie store for client side usage.
|
5
5
|
# - Enforces cookie validity rules
|
6
6
|
# - Returns just the cookies valid for a given URI
|
7
7
|
# - Handles expiration of cookies
|
8
|
-
# - Allows for persistence of cookie data (with or without session)
|
8
|
+
# - Allows for persistence of cookie data (with or without session)
|
9
9
|
#
|
10
10
|
#--
|
11
11
|
#
|
12
12
|
# Internal format:
|
13
|
-
#
|
13
|
+
#
|
14
14
|
# Internally, the data structure is a set of nested hashes.
|
15
15
|
# Domain Level:
|
16
16
|
# At the domain level, the hashes are of individual domains,
|
17
17
|
# down-cased and without any leading period. For instance, imagine cookies
|
18
18
|
# for .foo.com, .bar.com, and .auth.bar.com:
|
19
19
|
#
|
20
|
-
# {
|
20
|
+
# {
|
21
21
|
# "foo.com" : (host data),
|
22
22
|
# "bar.com" : (host data),
|
23
23
|
# "auth.bar.com" : (host data)
|
@@ -25,7 +25,7 @@ module CookieJar
|
|
25
25
|
#
|
26
26
|
# Lookups are done both for the matching entry, and for an entry without
|
27
27
|
# the first segment up to the dot, ie. for /^\.?[^\.]+\.(.*)$/.
|
28
|
-
# A lookup of auth.bar.com would match both bar.com and
|
28
|
+
# A lookup of auth.bar.com would match both bar.com and
|
29
29
|
# auth.bar.com, but not entries for com or www.auth.bar.com.
|
30
30
|
#
|
31
31
|
# Host Level:
|
@@ -39,47 +39,49 @@ module CookieJar
|
|
39
39
|
#
|
40
40
|
# Paths are given a straight prefix string comparison to match.
|
41
41
|
# Further filters <secure, http only, ports> are not represented in this
|
42
|
-
# heirarchy.
|
42
|
+
# heirarchy.
|
43
43
|
#
|
44
44
|
# Cookies returned are ordered solely by specificity (length) of the
|
45
45
|
# path.
|
46
46
|
class Jar
|
47
47
|
# Create a new empty Jar
|
48
48
|
def initialize
|
49
|
-
|
49
|
+
@domains = {}
|
50
50
|
end
|
51
|
-
|
51
|
+
|
52
52
|
# Given a request URI and a literal Set-Cookie header value, attempt to
|
53
|
-
# add the cookie to the cookie store.
|
54
|
-
#
|
53
|
+
# add the cookie(s) to the cookie store.
|
54
|
+
#
|
55
55
|
# @param [String, URI] request_uri the resource returning the header
|
56
56
|
# @param [String] cookie_header_value the contents of the Set-Cookie
|
57
57
|
# @return [Cookie] which was created and stored
|
58
58
|
# @raise [InvalidCookieError] if the cookie header did not validate
|
59
|
-
def set_cookie request_uri,
|
60
|
-
|
61
|
-
|
59
|
+
def set_cookie request_uri, cookie_header_values
|
60
|
+
cookie_header_values.split(/, (?=[\w]+=)/).each do |cookie_header_value|
|
61
|
+
cookie = Cookie.from_set_cookie request_uri, cookie_header_value
|
62
|
+
add_cookie cookie
|
63
|
+
end
|
62
64
|
end
|
63
65
|
|
64
66
|
# Given a request URI and a literal Set-Cookie2 header value, attempt to
|
65
67
|
# add the cookie to the cookie store.
|
66
|
-
#
|
68
|
+
#
|
67
69
|
# @param [String, URI] request_uri the resource returning the header
|
68
70
|
# @param [String] cookie_header_value the contents of the Set-Cookie2
|
69
71
|
# @return [Cookie] which was created and stored
|
70
72
|
# @raise [InvalidCookieError] if the cookie header did not validate
|
71
73
|
def set_cookie2 request_uri, cookie_header_value
|
72
|
-
|
73
|
-
|
74
|
+
cookie = Cookie.from_set_cookie2 request_uri, cookie_header_value
|
75
|
+
add_cookie cookie
|
74
76
|
end
|
75
|
-
|
77
|
+
|
76
78
|
# Given a request URI and some HTTP headers, attempt to add the cookie(s)
|
77
79
|
# (from Set-Cookie or Set-Cookie2 headers) to the cookie store. If a
|
78
|
-
# cookie is defined (by equivalent name, domain, and path) via Set-Cookie
|
80
|
+
# cookie is defined (by equivalent name, domain, and path) via Set-Cookie
|
79
81
|
# and Set-Cookie2, the Set-Cookie version is ignored.
|
80
82
|
#
|
81
83
|
# @param [String, URI] request_uri the resource returning the header
|
82
|
-
# @param [Hash<String,[String,Array<String>]>] http_headers a Hash
|
84
|
+
# @param [Hash<String,[String,Array<String>]>] http_headers a Hash
|
83
85
|
# which may have a key of "Set-Cookie" or "Set-Cookie2", and values of
|
84
86
|
# either strings or arrays of strings
|
85
87
|
# @return [Array<Cookie>,nil] the cookies created, or nil if none found.
|
@@ -93,7 +95,7 @@ module CookieJar
|
|
93
95
|
rescue InvalidCookieError
|
94
96
|
end
|
95
97
|
end
|
96
|
-
|
98
|
+
|
97
99
|
set_cookie2_key = http_headers.keys.detect { |k| /\ASet-Cookie2\Z/i.match k }
|
98
100
|
cookies += gather_header_values(http_headers[set_cookie2_key]) do |value|
|
99
101
|
begin
|
@@ -101,7 +103,7 @@ module CookieJar
|
|
101
103
|
rescue InvalidCookieError
|
102
104
|
end
|
103
105
|
end
|
104
|
-
|
106
|
+
|
105
107
|
# build the list of cookies, using a Jar. Since Set-Cookie2 values
|
106
108
|
# come second, they will replace the Set-Cookie versions.
|
107
109
|
jar = Jar.new
|
@@ -109,65 +111,68 @@ module CookieJar
|
|
109
111
|
jar.add_cookie cookie
|
110
112
|
end
|
111
113
|
cookies = jar.to_a
|
112
|
-
|
114
|
+
|
113
115
|
# now add them all to our own store.
|
114
116
|
cookies.each do |cookie|
|
115
117
|
add_cookie cookie
|
116
118
|
end
|
117
119
|
cookies
|
118
120
|
end
|
119
|
-
|
121
|
+
|
120
122
|
# Add a pre-existing cookie object to the jar.
|
121
123
|
#
|
122
124
|
# @param [Cookie] cookie a pre-existing cookie object
|
123
125
|
# @return [Cookie] the cookie added to the store
|
124
126
|
def add_cookie cookie
|
125
127
|
domain_paths = find_or_add_domain_for_cookie cookie
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
128
|
+
add_cookie_to_path domain_paths, cookie
|
129
|
+
cookie
|
130
|
+
end
|
131
|
+
|
132
|
+
# Return an array of all cookie objects in the jar
|
133
|
+
#
|
134
|
+
# @return [Array<Cookie>] all cookies. Includes any expired cookies
|
135
|
+
# which have not yet been removed with expire_cookies
|
136
|
+
def to_a
|
137
|
+
result = []
|
138
|
+
@domains.values.each do |paths|
|
139
|
+
paths.values.each do |cookies|
|
140
|
+
cookies.values.inject result, :<<
|
141
|
+
end
|
140
142
|
end
|
141
143
|
result
|
142
|
-
|
143
|
-
|
144
|
-
|
144
|
+
end
|
145
|
+
|
146
|
+
# Return a JSON 'object' for the various data values. Allows for
|
145
147
|
# persistence of the cookie information
|
146
148
|
#
|
147
|
-
# @param [Array] a options controlling output JSON text
|
149
|
+
# @param [Array] a options controlling output JSON text
|
148
150
|
# (usually a State and a depth)
|
149
|
-
# @return [String] JSON representation of object data
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
}.to_json
|
151
|
+
# @return [String] JSON representation of object data
|
152
|
+
def to_json *a
|
153
|
+
{
|
154
|
+
'json_class' => self.class.name,
|
155
|
+
'cookies' => to_a.to_json(*a)
|
156
|
+
}.to_json(*a)
|
155
157
|
end
|
156
|
-
|
158
|
+
|
157
159
|
# Create a new Jar from a JSON-backed hash
|
158
160
|
#
|
159
161
|
# @param o [Hash] the expanded JSON object
|
160
162
|
# @return [CookieJar] a new CookieJar instance
|
161
163
|
def self.json_create o
|
164
|
+
if o.is_a? String
|
165
|
+
o = JSON.parse(o)
|
166
|
+
end
|
162
167
|
if o.is_a? Hash
|
163
168
|
o = o['cookies']
|
164
169
|
end
|
165
|
-
cookies = o.inject
|
170
|
+
cookies = o.inject([]) do |result, cookie_json|
|
166
171
|
result << (Cookie.json_create cookie_json)
|
167
172
|
end
|
168
173
|
self.from_a cookies
|
169
174
|
end
|
170
|
-
|
175
|
+
|
171
176
|
# Create a new Jar from an array of Cookie objects. Expired cookies
|
172
177
|
# will still be added to the archive, and conflicting cookies will
|
173
178
|
# be overwritten by the last cookie in the array.
|
@@ -198,7 +203,7 @@ module CookieJar
|
|
198
203
|
paths.empty?
|
199
204
|
end
|
200
205
|
end
|
201
|
-
|
206
|
+
|
202
207
|
# Given a request URI, return a sorted list of Cookie objects. Cookies
|
203
208
|
# will be in order per RFC 2965 - sorted by longest path length, but
|
204
209
|
# otherwise unordered.
|
@@ -210,26 +215,26 @@ module CookieJar
|
|
210
215
|
# if true
|
211
216
|
# @return [Array<Cookie>] cookies which should be sent in the HTTP request
|
212
217
|
def get_cookies request_uri, opts = { }
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
218
|
+
uri = to_uri request_uri
|
219
|
+
hosts = Cookie.compute_search_domains uri
|
220
|
+
|
221
|
+
results = []
|
222
|
+
hosts.each do |host|
|
223
|
+
domain = find_domain host
|
224
|
+
domain.each do |path, cookies|
|
225
|
+
if uri.path.start_with? path
|
226
|
+
results += cookies.values.select do |cookie|
|
227
|
+
cookie.should_send? uri, opts[:script]
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
#Sort by path length, longest first
|
233
|
+
results.sort do |lhs, rhs|
|
234
|
+
rhs.path.length <=> lhs.path.length
|
226
235
|
end
|
227
|
-
#Sort by path length, longest first
|
228
|
-
results.sort do |lhs, rhs|
|
229
|
-
rhs.path.length <=> lhs.path.length
|
230
|
-
end
|
231
236
|
end
|
232
|
-
|
237
|
+
|
233
238
|
# Given a request URI, return a string Cookie header.Cookies will be in
|
234
239
|
# order per RFC 2965 - sorted by longest path length, but otherwise
|
235
240
|
# unordered.
|
@@ -242,44 +247,43 @@ module CookieJar
|
|
242
247
|
# @return String value of the Cookie header which should be sent on the
|
243
248
|
# HTTP request
|
244
249
|
def get_cookie_header request_uri, opts = { }
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
250
|
+
cookies = get_cookies request_uri, opts
|
251
|
+
version = 0
|
252
|
+
ver = [[],[]]
|
253
|
+
cookies.each do |cookie|
|
254
|
+
ver[cookie.version] << cookie
|
255
|
+
end
|
256
|
+
if (ver[1].empty?)
|
257
|
+
# can do a netscape-style cookie header, relish the opportunity
|
258
|
+
cookies.map do |cookie|
|
259
|
+
cookie.to_s
|
260
|
+
end.join ";"
|
261
|
+
else
|
262
|
+
# build a RFC 2965-style cookie header. Split the cookies into
|
263
|
+
# version 0 and 1 groups so that we can reuse the '$Version' header
|
264
|
+
result = ''
|
265
|
+
unless ver[0].empty?
|
266
|
+
result << '$Version=0;'
|
267
|
+
result << ver[0].map do |cookie|
|
268
|
+
(cookie.to_s 1,false)
|
269
|
+
end.join(';')
|
270
|
+
# separate version 0 and 1 with a comma
|
271
|
+
result << ','
|
267
272
|
end
|
268
273
|
result << '$Version=1;'
|
269
|
-
|
270
|
-
|
274
|
+
ver[1].map do |cookie|
|
275
|
+
result << (cookie.to_s 1,false)
|
271
276
|
end
|
272
|
-
|
277
|
+
result
|
273
278
|
end
|
274
279
|
end
|
275
280
|
|
276
|
-
protected
|
281
|
+
protected
|
277
282
|
|
278
283
|
def gather_header_values http_header_value, &block
|
279
284
|
result = []
|
280
|
-
http_header_value
|
281
285
|
if http_header_value.is_a? Array
|
282
|
-
http_header_value.each do |value|
|
286
|
+
http_header_value.each do |value|
|
283
287
|
result << block.call(value)
|
284
288
|
end
|
285
289
|
elsif http_header_value.is_a? String
|
@@ -287,22 +291,22 @@ module CookieJar
|
|
287
291
|
end
|
288
292
|
result.compact
|
289
293
|
end
|
290
|
-
|
294
|
+
|
291
295
|
def to_uri request_uri
|
292
296
|
(request_uri.is_a? URI)? request_uri : (URI.parse request_uri)
|
293
297
|
end
|
294
|
-
|
298
|
+
|
295
299
|
def find_domain host
|
296
|
-
|
300
|
+
@domains[host] || {}
|
297
301
|
end
|
298
302
|
|
299
303
|
def find_or_add_domain_for_cookie cookie
|
300
|
-
|
304
|
+
@domains[cookie.domain] ||= {}
|
301
305
|
end
|
302
|
-
|
306
|
+
|
303
307
|
def add_cookie_to_path paths, cookie
|
304
|
-
|
305
|
-
|
308
|
+
path_entry = (paths[cookie.path] ||= {})
|
309
|
+
path_entry[cookie.name] = cookie
|
306
310
|
end
|
307
311
|
end
|
308
|
-
end
|
312
|
+
end
|
@@ -163,7 +163,7 @@ describe Cookie do
|
|
163
163
|
end
|
164
164
|
it "should automatically deserialize to a cookie" do
|
165
165
|
json = "{\"json_class\":\"CookieJar::Cookie\",\"name\":\"foo\",\"value\":\"bar\",\"domain\":\"localhost.local\",\"path\":\"\\/\",\"created_at\":\"2009-09-11 12:51:03 -0600\",\"expiry\":\"2009-09-11 19:10:00 -0600\",\"secure\":true}"
|
166
|
-
c = JSON.parse json
|
166
|
+
c = JSON.parse json, :create_additions => true
|
167
167
|
c.should be_a Cookie
|
168
168
|
CookieValidation.validate_cookie 'https://localhost/', c
|
169
169
|
end
|
@@ -236,4 +236,9 @@ describe CookieValidation do
|
|
236
236
|
end
|
237
237
|
end
|
238
238
|
end
|
239
|
+
describe '#parse_set_cookie' do
|
240
|
+
it "should max out at 2038 on 32bit systems" do
|
241
|
+
CookieValidation.parse_set_cookie("TRACK_USER_P=98237480810003948000782774;expires=Sat, 30-Jun-2040 05:39:49 GMT;path=/")[:expires_at].to_i.should >= 0x7FFFFFFF
|
242
|
+
end
|
243
|
+
end
|
239
244
|
end
|
@@ -17,6 +17,10 @@ describe Jar do
|
|
17
17
|
jar.set_cookie 'http://auth.foo.com/', 'foo=bar'
|
18
18
|
jar.set_cookie 'http://auth.foo.com/', 'auth=135121...;domain=foo.com'
|
19
19
|
end
|
20
|
+
it "should allow me to set multiple cookies in 1 header" do
|
21
|
+
jar = Jar.new
|
22
|
+
jar.set_cookie 'http://foo.com/', 'my_cookie=123456; Domain=foo.com; expires=Thu, 31 Dec 2037 23:59:59 GMT; Path=/, other_cookie=helloworld; Domain=foo.com; expires=Thu, 31 Dec 2037 23:59:59 GMT, last_cookie=098765'
|
23
|
+
end
|
20
24
|
end
|
21
25
|
describe '.get_cookies' do
|
22
26
|
it "should let me read back cookies which are set" do
|
@@ -27,6 +31,11 @@ describe Jar do
|
|
27
31
|
jar.set_cookie 'http://auth.foo.com/', 'auth=135121...;domain=foo.com'
|
28
32
|
jar.get_cookies('http://foo.com/').should have(3).items
|
29
33
|
end
|
34
|
+
it "should let me read back a multiple cookies from 1 header" do
|
35
|
+
jar = Jar.new
|
36
|
+
jar.set_cookie 'http://foo.com/', 'my_cookie=123456; Domain=foo.com; expires=Thu, 31 Dec 2037 23:59:59 GMT; Path=/, other_cookie=helloworld; Domain=foo.com; expires=Thu, 31 Dec 2037 23:59:59 GMT, last_cookie=098765'
|
37
|
+
jar.get_cookie_header('http://foo.com/').should == 'last_cookie=098765;my_cookie=123456;other_cookie=helloworld'
|
38
|
+
end
|
30
39
|
it "should return cookies longest path first" do
|
31
40
|
jar = Jar.new
|
32
41
|
uri = 'http://foo.com/a/b/c/d'
|
@@ -200,7 +209,7 @@ describe Jar do
|
|
200
209
|
it "should deserialize a JSON array to a jar" do
|
201
210
|
json = "[{\"name\":\"foo\",\"value\":\"bar\",\"domain\":\"localhost.local\",\"path\":\"\\/\",\"created_at\":\"2009-09-11 12:51:03 -0600\",\"expiry\":\"2028-11-01 12:00:00 GMT\",\"secure\":true}]"
|
202
211
|
array = JSON.parse json
|
203
|
-
|
212
|
+
|
204
213
|
jar = Jar.json_create array
|
205
214
|
jar.get_cookies('https://localhost/').should have(1).items
|
206
215
|
end
|
@@ -214,7 +223,7 @@ describe Jar do
|
|
214
223
|
|
215
224
|
it "should automatically deserialize to a jar" do
|
216
225
|
json = "{\"json_class\":\"CookieJar::Jar\",\"cookies\":[{\"name\":\"foo\",\"value\":\"bar\",\"domain\":\"localhost.local\",\"path\":\"\\/\",\"created_at\":\"2009-09-11 12:51:03 -0600\",\"expiry\":\"2028-11-01 12:00:00 GMT\",\"secure\":true}]}"
|
217
|
-
jar = JSON.parse json
|
226
|
+
jar = JSON.parse json, :create_additions => true
|
218
227
|
jar.get_cookies('https://localhost/').should have(1).items
|
219
228
|
end
|
220
229
|
end
|
metadata
CHANGED
@@ -1,72 +1,99 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: cookiejar
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
segments:
|
6
|
-
- 0
|
7
|
-
- 3
|
8
|
-
- 0
|
9
|
-
version: 0.3.0
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.1
|
10
5
|
platform: ruby
|
11
|
-
authors:
|
6
|
+
authors:
|
12
7
|
- David Waite
|
13
8
|
autorequire:
|
14
9
|
bindir: bin
|
15
10
|
cert_chain: []
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
11
|
+
date: 2014-02-16 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rake
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '10'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '10'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.14'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.14'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: yard
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.8.7
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.8.7
|
21
55
|
description: Allows for parsing and returning cookies in Ruby HTTP client code
|
22
56
|
email: david@alkaline-solutions.com
|
23
57
|
executables: []
|
24
|
-
|
25
58
|
extensions: []
|
26
|
-
|
27
59
|
extra_rdoc_files: []
|
28
|
-
|
29
|
-
|
60
|
+
files:
|
61
|
+
- LICENSE
|
62
|
+
- README.markdown
|
63
|
+
- Rakefile
|
64
|
+
- contributors.json
|
65
|
+
- lib/cookiejar.rb
|
30
66
|
- lib/cookiejar/cookie.rb
|
31
67
|
- lib/cookiejar/cookie_validation.rb
|
32
68
|
- lib/cookiejar/jar.rb
|
33
|
-
-
|
34
|
-
-
|
35
|
-
-
|
36
|
-
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
69
|
+
- spec/cookie_spec.rb
|
70
|
+
- spec/cookie_validation_spec.rb
|
71
|
+
- spec/jar_spec.rb
|
72
|
+
homepage: https://alkaline-solutions.com
|
73
|
+
licenses:
|
74
|
+
- BSD-2-Clause
|
75
|
+
metadata: {}
|
41
76
|
post_install_message:
|
42
|
-
rdoc_options:
|
43
|
-
- --title
|
77
|
+
rdoc_options:
|
78
|
+
- "--title"
|
44
79
|
- CookieJar -- Client-side HTTP Cookies
|
45
|
-
require_paths:
|
80
|
+
require_paths:
|
46
81
|
- lib
|
47
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
-
|
49
|
-
requirements:
|
82
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
83
|
+
requirements:
|
50
84
|
- - ">="
|
51
|
-
- !ruby/object:Gem::Version
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
version: "0"
|
56
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
|
-
requirements:
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: '0'
|
87
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
59
89
|
- - ">="
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
|
62
|
-
- 0
|
63
|
-
version: "0"
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '0'
|
64
92
|
requirements: []
|
65
|
-
|
66
93
|
rubyforge_project:
|
67
|
-
rubygems_version:
|
94
|
+
rubygems_version: 2.2.0
|
68
95
|
signing_key:
|
69
96
|
specification_version: 3
|
70
97
|
summary: Client-side HTTP Cookie library
|
71
98
|
test_files: []
|
72
|
-
|
99
|
+
has_rdoc:
|