cookiejar2 0.3.4
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 +7 -0
- data/.circleci/config.yml +15 -0
- data/.gitignore +8 -0
- data/.rspec +2 -0
- data/.travis.yml +17 -0
- data/Gemfile +2 -0
- data/LICENSE +10 -0
- data/README.markdown +37 -0
- data/Rakefile +30 -0
- data/_config.yml +1 -0
- data/contributors.json +14 -0
- data/cookiejar.gemspec +28 -0
- data/lib/cookiejar/cookie.rb +257 -0
- data/lib/cookiejar/cookie_validation.rb +410 -0
- data/lib/cookiejar/jar.rb +314 -0
- data/lib/cookiejar/version.rb +4 -0
- data/lib/cookiejar.rb +3 -0
- data/spec/cookie_spec.rb +176 -0
- data/spec/cookie_validation_spec.rb +236 -0
- data/spec/jar_spec.rb +232 -0
- data/spec/spec_helper.rb +9 -0
- metadata +139 -0
@@ -0,0 +1,314 @@
|
|
1
|
+
require 'cookiejar/cookie'
|
2
|
+
|
3
|
+
module CookieJar
|
4
|
+
# A cookie store for client side usage.
|
5
|
+
# - Enforces cookie validity rules
|
6
|
+
# - Returns just the cookies valid for a given URI
|
7
|
+
# - Handles expiration of cookies
|
8
|
+
# - Allows for persistence of cookie data (with or without session)
|
9
|
+
#
|
10
|
+
#--
|
11
|
+
#
|
12
|
+
# Internal format:
|
13
|
+
#
|
14
|
+
# Internally, the data structure is a set of nested hashes.
|
15
|
+
# Domain Level:
|
16
|
+
# At the domain level, the hashes are of individual domains,
|
17
|
+
# down-cased and without any leading period. For instance, imagine cookies
|
18
|
+
# for .foo.com, .bar.com, and .auth.bar.com:
|
19
|
+
#
|
20
|
+
# {
|
21
|
+
# "foo.com" : (host data),
|
22
|
+
# "bar.com" : (host data),
|
23
|
+
# "auth.bar.com" : (host data)
|
24
|
+
# }
|
25
|
+
#
|
26
|
+
# Lookups are done both for the matching entry, and for an entry without
|
27
|
+
# the first segment up to the dot, ie. for /^\.?[^\.]+\.(.*)$/.
|
28
|
+
# A lookup of auth.bar.com would match both bar.com and
|
29
|
+
# auth.bar.com, but not entries for com or www.auth.bar.com.
|
30
|
+
#
|
31
|
+
# Host Level:
|
32
|
+
# Entries are in an hash, with keys of the path and values of a hash of
|
33
|
+
# cookie names to cookie object
|
34
|
+
#
|
35
|
+
# {
|
36
|
+
# "/" : {"session" : (Cookie object), "cart_id" : (Cookie object)}
|
37
|
+
# "/protected" : {"authentication" : (Cookie Object)}
|
38
|
+
# }
|
39
|
+
#
|
40
|
+
# Paths are given a straight prefix string comparison to match.
|
41
|
+
# Further filters <secure, http only, ports> are not represented in this
|
42
|
+
# hierarchy.
|
43
|
+
#
|
44
|
+
# Cookies returned are ordered solely by specificity (length) of the
|
45
|
+
# path.
|
46
|
+
class Jar
|
47
|
+
# Create a new empty Jar
|
48
|
+
def initialize
|
49
|
+
@domains = {}
|
50
|
+
end
|
51
|
+
|
52
|
+
# Given a request URI and a literal Set-Cookie header value, attempt to
|
53
|
+
# add the cookie(s) to the cookie store.
|
54
|
+
#
|
55
|
+
# @param [String, URI] request_uri the resource returning the header
|
56
|
+
# @param [String] cookie_header_value the contents of the Set-Cookie
|
57
|
+
# @return [Cookie] which was created and stored
|
58
|
+
# @raise [InvalidCookieError] if the cookie header did not validate
|
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
|
64
|
+
end
|
65
|
+
|
66
|
+
# Given a request URI and a literal Set-Cookie2 header value, attempt to
|
67
|
+
# add the cookie to the cookie store.
|
68
|
+
#
|
69
|
+
# @param [String, URI] request_uri the resource returning the header
|
70
|
+
# @param [String] cookie_header_value the contents of the Set-Cookie2
|
71
|
+
# @return [Cookie] which was created and stored
|
72
|
+
# @raise [InvalidCookieError] if the cookie header did not validate
|
73
|
+
def set_cookie2(request_uri, cookie_header_value)
|
74
|
+
cookie = Cookie.from_set_cookie2 request_uri, cookie_header_value
|
75
|
+
add_cookie cookie
|
76
|
+
end
|
77
|
+
|
78
|
+
# Given a request URI and some HTTP headers, attempt to add the cookie(s)
|
79
|
+
# (from Set-Cookie or Set-Cookie2 headers) to the cookie store. If a
|
80
|
+
# cookie is defined (by equivalent name, domain, and path) via Set-Cookie
|
81
|
+
# and Set-Cookie2, the Set-Cookie version is ignored.
|
82
|
+
#
|
83
|
+
# @param [String, URI] request_uri the resource returning the header
|
84
|
+
# @param [Hash<String,[String,Array<String>]>] http_headers a Hash
|
85
|
+
# which may have a key of "Set-Cookie" or "Set-Cookie2", and values of
|
86
|
+
# either strings or arrays of strings
|
87
|
+
# @return [Array<Cookie>,nil] the cookies created, or nil if none found.
|
88
|
+
# @raise [InvalidCookieError] if one of the cookie headers contained
|
89
|
+
# invalid formatting or data
|
90
|
+
def set_cookies_from_headers(request_uri, http_headers)
|
91
|
+
set_cookie_key = http_headers.keys.detect { |k| /\ASet-Cookie\Z/i.match k }
|
92
|
+
cookies = gather_header_values http_headers[set_cookie_key] do |value|
|
93
|
+
begin
|
94
|
+
Cookie.from_set_cookie request_uri, value
|
95
|
+
rescue InvalidCookieError
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
set_cookie2_key = http_headers.keys.detect { |k| /\ASet-Cookie2\Z/i.match k }
|
100
|
+
cookies += gather_header_values(http_headers[set_cookie2_key]) do |value|
|
101
|
+
begin
|
102
|
+
Cookie.from_set_cookie2 request_uri, value
|
103
|
+
rescue InvalidCookieError
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# build the list of cookies, using a Jar. Since Set-Cookie2 values
|
108
|
+
# come second, they will replace the Set-Cookie versions.
|
109
|
+
jar = Jar.new
|
110
|
+
cookies.each do |cookie|
|
111
|
+
jar.add_cookie cookie
|
112
|
+
end
|
113
|
+
cookies = jar.to_a
|
114
|
+
|
115
|
+
# now add them all to our own store.
|
116
|
+
cookies.each do |cookie|
|
117
|
+
add_cookie cookie
|
118
|
+
end
|
119
|
+
cookies
|
120
|
+
end
|
121
|
+
|
122
|
+
# Add a pre-existing cookie object to the jar.
|
123
|
+
#
|
124
|
+
# @param [Cookie] cookie a pre-existing cookie object
|
125
|
+
# @return [Cookie] the cookie added to the store
|
126
|
+
def add_cookie(cookie)
|
127
|
+
domain_paths = find_or_add_domain_for_cookie cookie
|
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
|
142
|
+
end
|
143
|
+
result
|
144
|
+
end
|
145
|
+
|
146
|
+
# Return a JSON 'object' for the various data values. Allows for
|
147
|
+
# persistence of the cookie information
|
148
|
+
#
|
149
|
+
# @param [Array] a options controlling output JSON text
|
150
|
+
# (usually a State and a depth)
|
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)
|
157
|
+
end
|
158
|
+
|
159
|
+
# Create a new Jar from a JSON-backed hash
|
160
|
+
#
|
161
|
+
# @param o [Hash] the expanded JSON object
|
162
|
+
# @return [CookieJar] a new CookieJar instance
|
163
|
+
def self.json_create(o)
|
164
|
+
o = JSON.parse(o) if o.is_a? String
|
165
|
+
o = o['cookies'] if o.is_a? Hash
|
166
|
+
cookies = o.inject([]) do |result, cookie_json|
|
167
|
+
result << (Cookie.json_create cookie_json)
|
168
|
+
end
|
169
|
+
from_a cookies
|
170
|
+
end
|
171
|
+
|
172
|
+
# Create a new Jar from an array of Cookie objects. Expired cookies
|
173
|
+
# will still be added to the archive, and conflicting cookies will
|
174
|
+
# be overwritten by the last cookie in the array.
|
175
|
+
#
|
176
|
+
# @param [Array<Cookie>] cookies array of cookie objects
|
177
|
+
# @return [CookieJar] a new CookieJar instance
|
178
|
+
def self.from_a(cookies)
|
179
|
+
jar = new
|
180
|
+
cookies.each do |cookie|
|
181
|
+
jar.add_cookie cookie
|
182
|
+
end
|
183
|
+
jar
|
184
|
+
end
|
185
|
+
|
186
|
+
# Look through the jar for any cookies which have passed their expiration
|
187
|
+
# date, or session cookies from a previous session
|
188
|
+
#
|
189
|
+
# @param session [Boolean] whether session cookies should be expired,
|
190
|
+
# or just cookies past their expiration date.
|
191
|
+
def expire_cookies(session = false)
|
192
|
+
@domains.delete_if do |_domain, paths|
|
193
|
+
paths.delete_if do |_path, cookies|
|
194
|
+
cookies.delete_if do |_cookie_name, cookie|
|
195
|
+
cookie.expired? || (session && cookie.session?)
|
196
|
+
end
|
197
|
+
cookies.empty?
|
198
|
+
end
|
199
|
+
paths.empty?
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
# Given a request URI, return a sorted list of Cookie objects. Cookies
|
204
|
+
# will be in order per RFC 2965 - sorted by longest path length, but
|
205
|
+
# otherwise unordered.
|
206
|
+
#
|
207
|
+
# @param [String, URI] request_uri the address the HTTP request will be
|
208
|
+
# sent to. This must be a full URI, i.e. must include the protocol,
|
209
|
+
# if you pass digi.ninja it will fail to find the domain, you must pass
|
210
|
+
# http://digi.ninja
|
211
|
+
# @param [Hash] opts options controlling returned cookies
|
212
|
+
# @option opts [Boolean] :script (false) Cookies marked HTTP-only will be
|
213
|
+
# ignored if true
|
214
|
+
# @return [Array<Cookie>] cookies which should be sent in the HTTP request
|
215
|
+
def get_cookies(request_uri, opts = {})
|
216
|
+
uri = to_uri request_uri
|
217
|
+
hosts = Cookie.compute_search_domains uri
|
218
|
+
|
219
|
+
return [] if hosts.nil?
|
220
|
+
|
221
|
+
path = if uri.path == ''
|
222
|
+
'/'
|
223
|
+
else
|
224
|
+
uri.path
|
225
|
+
end
|
226
|
+
|
227
|
+
results = []
|
228
|
+
hosts.each do |host|
|
229
|
+
domain = find_domain host
|
230
|
+
domain.each do |apath, cookies|
|
231
|
+
next unless path.start_with? apath
|
232
|
+
results += cookies.values.select do |cookie|
|
233
|
+
cookie.should_send? uri, opts[:script]
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
# Sort by path length, longest first
|
238
|
+
results.sort do |lhs, rhs|
|
239
|
+
rhs.path.length <=> lhs.path.length
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
# Given a request URI, return a string Cookie header.Cookies will be in
|
244
|
+
# order per RFC 2965 - sorted by longest path length, but otherwise
|
245
|
+
# unordered.
|
246
|
+
#
|
247
|
+
# @param [String, URI] request_uri the address the HTTP request will be
|
248
|
+
# sent to
|
249
|
+
# @param [Hash] opts options controlling returned cookies
|
250
|
+
# @option opts [Boolean] :script (false) Cookies marked HTTP-only will be
|
251
|
+
# ignored if true
|
252
|
+
# @return String value of the Cookie header which should be sent on the
|
253
|
+
# HTTP request
|
254
|
+
def get_cookie_header(request_uri, opts = {})
|
255
|
+
cookies = get_cookies request_uri, opts
|
256
|
+
ver = [[], []]
|
257
|
+
cookies.each do |cookie|
|
258
|
+
ver[cookie.version] << cookie
|
259
|
+
end
|
260
|
+
if ver[1].empty?
|
261
|
+
# can do a netscape-style cookie header, relish the opportunity
|
262
|
+
cookies.map(&:to_s).join ';'
|
263
|
+
else
|
264
|
+
# build a RFC 2965-style cookie header. Split the cookies into
|
265
|
+
# version 0 and 1 groups so that we can reuse the '$Version' header
|
266
|
+
result = ''
|
267
|
+
unless ver[0].empty?
|
268
|
+
result << '$Version=0;'
|
269
|
+
result << ver[0].map do |cookie|
|
270
|
+
(cookie.to_s 1, false)
|
271
|
+
end.join(';')
|
272
|
+
# separate version 0 and 1 with a comma
|
273
|
+
result << ','
|
274
|
+
end
|
275
|
+
result << '$Version=1;'
|
276
|
+
ver[1].map do |cookie|
|
277
|
+
result << (cookie.to_s 1, false)
|
278
|
+
end
|
279
|
+
result
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
protected
|
284
|
+
|
285
|
+
def gather_header_values(http_header_value, &_block)
|
286
|
+
result = []
|
287
|
+
if http_header_value.is_a? Array
|
288
|
+
http_header_value.each do |value|
|
289
|
+
result << yield(value)
|
290
|
+
end
|
291
|
+
elsif http_header_value.is_a? String
|
292
|
+
result << yield(http_header_value)
|
293
|
+
end
|
294
|
+
result.compact
|
295
|
+
end
|
296
|
+
|
297
|
+
def to_uri(request_uri)
|
298
|
+
(request_uri.is_a? URI) ? request_uri : (URI.parse request_uri)
|
299
|
+
end
|
300
|
+
|
301
|
+
def find_domain(host)
|
302
|
+
@domains[host] || {}
|
303
|
+
end
|
304
|
+
|
305
|
+
def find_or_add_domain_for_cookie(cookie)
|
306
|
+
@domains[cookie.domain] ||= {}
|
307
|
+
end
|
308
|
+
|
309
|
+
def add_cookie_to_path(paths, cookie)
|
310
|
+
path_entry = (paths[cookie.path] ||= {})
|
311
|
+
path_entry[cookie.name] = cookie
|
312
|
+
end
|
313
|
+
end
|
314
|
+
end
|
data/lib/cookiejar.rb
ADDED
data/spec/cookie_spec.rb
ADDED
@@ -0,0 +1,176 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
include CookieJar
|
5
|
+
|
6
|
+
FOO_URL = 'http://localhost/foo'.freeze
|
7
|
+
AMMO_URL = 'http://localhost/ammo'.freeze
|
8
|
+
NETSCAPE_SPEC_SET_COOKIE_HEADERS =
|
9
|
+
[['CUSTOMER=WILE_E_COYOTE; path=/; expires=Wednesday, 09-Nov-99 23:12:40 GMT',
|
10
|
+
FOO_URL],
|
11
|
+
['PART_NUMBER=ROCKET_LAUNCHER_0001; path=/',
|
12
|
+
FOO_URL],
|
13
|
+
['SHIPPING=FEDEX; path=/foo',
|
14
|
+
FOO_URL],
|
15
|
+
['PART_NUMBER=ROCKET_LAUNCHER_0001; path=/',
|
16
|
+
FOO_URL],
|
17
|
+
['PART_NUMBER=RIDING_ROCKET_0023; path=/ammo',
|
18
|
+
AMMO_URL]].freeze
|
19
|
+
|
20
|
+
describe Cookie do
|
21
|
+
describe '#from_set_cookie' do
|
22
|
+
it 'should handle cookies from the netscape spec' do
|
23
|
+
NETSCAPE_SPEC_SET_COOKIE_HEADERS.each do |value|
|
24
|
+
header, url = *value
|
25
|
+
Cookie.from_set_cookie url, header
|
26
|
+
end
|
27
|
+
end
|
28
|
+
it 'should give back the input names and values' do
|
29
|
+
cookie = Cookie.from_set_cookie 'http://localhost/', 'foo=bar'
|
30
|
+
expect(cookie.name).to eq 'foo'
|
31
|
+
expect(cookie.value).to eq 'bar'
|
32
|
+
end
|
33
|
+
it 'should normalize domain names' do
|
34
|
+
cookie = Cookie.from_set_cookie 'http://localhost/', 'foo=Bar;domain=LoCaLHoSt.local'
|
35
|
+
expect(cookie.domain).to eq '.localhost.local'
|
36
|
+
end
|
37
|
+
it 'should accept non-normalized .local' do
|
38
|
+
cookie = Cookie.from_set_cookie 'http://localhost/', 'foo=bar;domain=.local'
|
39
|
+
expect(cookie.domain).to eq '.local'
|
40
|
+
end
|
41
|
+
it 'should accept secure cookies' do
|
42
|
+
cookie = Cookie.from_set_cookie 'https://www.google.com/a/blah', 'GALX=RgmSftjnbPM;Path=/a/;Secure'
|
43
|
+
expect(cookie.name).to eq 'GALX'
|
44
|
+
expect(cookie.secure).to be_truthy
|
45
|
+
end
|
46
|
+
end
|
47
|
+
describe '#from_set_cookie2' do
|
48
|
+
it 'should give back the input names and values' do
|
49
|
+
cookie = Cookie.from_set_cookie2 'http://localhost/', 'foo=bar;Version=1'
|
50
|
+
expect(cookie.name).to eq 'foo'
|
51
|
+
expect(cookie.value).to eq 'bar'
|
52
|
+
end
|
53
|
+
it 'should normalize domain names' do
|
54
|
+
cookie = Cookie.from_set_cookie2 'http://localhost/', 'foo=Bar;domain=LoCaLHoSt.local;Version=1'
|
55
|
+
expect(cookie.domain).to eq '.localhost.local'
|
56
|
+
end
|
57
|
+
it 'should accept non-normalized .local' do
|
58
|
+
cookie = Cookie.from_set_cookie2 'http://localhost/', 'foo=bar;domain=.local;Version=1'
|
59
|
+
expect(cookie.domain).to eq '.local'
|
60
|
+
end
|
61
|
+
it 'should accept secure cookies' do
|
62
|
+
cookie = Cookie.from_set_cookie2 'https://www.google.com/a/blah', 'GALX=RgmSftjnbPM;Path="/a/";Secure;Version=1'
|
63
|
+
expect(cookie.name).to eq 'GALX'
|
64
|
+
expect(cookie.path).to eq '/a/'
|
65
|
+
expect(cookie.secure).to be_truthy
|
66
|
+
end
|
67
|
+
it 'should fail on unquoted paths' do
|
68
|
+
expect {
|
69
|
+
Cookie.from_set_cookie2 'https://www.google.com/a/blah',
|
70
|
+
'GALX=RgmSftjnbPM;Path=/a/;Secure;Version=1'
|
71
|
+
}.to raise_error InvalidCookieError
|
72
|
+
end
|
73
|
+
it 'should accept quoted values' do
|
74
|
+
cookie = Cookie.from_set_cookie2 'http://localhost/', 'foo="bar";Version=1'
|
75
|
+
expect(cookie.name).to eq 'foo'
|
76
|
+
expect(cookie.value).to eq '"bar"'
|
77
|
+
end
|
78
|
+
it 'should accept poorly chosen names' do
|
79
|
+
cookie = Cookie.from_set_cookie2 'http://localhost/', 'Version=mine;Version=1'
|
80
|
+
expect(cookie.name).to eq 'Version'
|
81
|
+
expect(cookie.value).to eq 'mine'
|
82
|
+
end
|
83
|
+
it 'should accept quoted parameter values' do
|
84
|
+
Cookie.from_set_cookie2 'http://localhost/', 'foo=bar;Version="1"'
|
85
|
+
end
|
86
|
+
it 'should honor the discard and max-age parameters' do
|
87
|
+
cookie = Cookie.from_set_cookie2 'http://localhost/', 'f=b;max-age=100;discard;Version=1'
|
88
|
+
expect(cookie).to be_session
|
89
|
+
expect(cookie).to_not be_expired
|
90
|
+
|
91
|
+
cookie = Cookie.from_set_cookie2 'http://localhost/', 'f=b;max-age=100;Version=1'
|
92
|
+
expect(cookie).to_not be_session
|
93
|
+
|
94
|
+
cookie = Cookie.from_set_cookie2 'http://localhost/', 'f=b;Version=1'
|
95
|
+
expect(cookie).to be_session
|
96
|
+
end
|
97
|
+
it 'should handle quotable quotes' do
|
98
|
+
cookie = Cookie.from_set_cookie2 'http://localhost/', 'f="\"";Version=1'
|
99
|
+
expect(cookie.value).to eq '"\""'
|
100
|
+
end
|
101
|
+
it 'should handle quotable apostrophes' do
|
102
|
+
cookie = Cookie.from_set_cookie2 'http://localhost/', 'f="\;";Version=1'
|
103
|
+
expect(cookie.value).to eq '"\;"'
|
104
|
+
end
|
105
|
+
end
|
106
|
+
describe '#decoded_value' do
|
107
|
+
it 'should leave normal values alone' do
|
108
|
+
cookie = Cookie.from_set_cookie2 'http://localhost/', 'f=b;Version=1'
|
109
|
+
expect(cookie.decoded_value).to eq 'b'
|
110
|
+
end
|
111
|
+
it 'should attempt to unencode quoted values' do
|
112
|
+
cookie = Cookie.from_set_cookie2 'http://localhost/', 'f="\"b";Version=1'
|
113
|
+
expect(cookie.value).to eq '"\"b"'
|
114
|
+
expect(cookie.decoded_value).to eq '"b'
|
115
|
+
end
|
116
|
+
end
|
117
|
+
describe '#to_s' do
|
118
|
+
it 'should handle a simple cookie' do
|
119
|
+
cookie = Cookie.from_set_cookie 'http://localhost/', 'f=b'
|
120
|
+
expect(cookie.to_s).to eq 'f=b'
|
121
|
+
expect(cookie.to_s(1)).to eq '$Version=0;f=b;$Path="/"'
|
122
|
+
end
|
123
|
+
it 'should report an explicit domain' do
|
124
|
+
cookie = Cookie.from_set_cookie2 'http://localhost/', 'f=b;Version=1;Domain=.local'
|
125
|
+
expect(cookie.to_s(1)).to eq '$Version=1;f=b;$Path="/";$Domain=.local'
|
126
|
+
end
|
127
|
+
it 'should return specified ports' do
|
128
|
+
cookie = Cookie.from_set_cookie2 'http://localhost/', 'f=b;Version=1;Port="80,443"'
|
129
|
+
expect(cookie.to_s(1)).to eq '$Version=1;f=b;$Path="/";$Port="80,443"'
|
130
|
+
end
|
131
|
+
it 'should handle specified paths' do
|
132
|
+
cookie = Cookie.from_set_cookie 'http://localhost/bar/', 'f=b;path=/bar/'
|
133
|
+
expect(cookie.to_s).to eq 'f=b'
|
134
|
+
expect(cookie.to_s(1)).to eq '$Version=0;f=b;$Path="/bar/"'
|
135
|
+
end
|
136
|
+
it 'should omit $Version header when asked' do
|
137
|
+
cookie = Cookie.from_set_cookie 'http://localhost/', 'f=b'
|
138
|
+
expect(cookie.to_s(1, false)).to eq 'f=b;$Path="/"'
|
139
|
+
end
|
140
|
+
end
|
141
|
+
describe '#should_send?' do
|
142
|
+
it 'should not send if ports do not match' do
|
143
|
+
cookie = Cookie.from_set_cookie2 'http://localhost/', 'f=b;Version=1;Port="80"'
|
144
|
+
expect(cookie.should_send?('http://localhost/', false)).to be_truthy
|
145
|
+
expect(cookie.should_send?('https://localhost/', false)).to be_falsey
|
146
|
+
end
|
147
|
+
end
|
148
|
+
begin
|
149
|
+
require 'json'
|
150
|
+
describe '.to_json' do
|
151
|
+
it 'should serialize a cookie to JSON' do
|
152
|
+
c = Cookie.from_set_cookie 'https://localhost/', 'foo=bar;secure;expires=Fri, September 11 2009 18:10:00 -0700'
|
153
|
+
json = c.to_json
|
154
|
+
expect(json).to be_a String
|
155
|
+
end
|
156
|
+
end
|
157
|
+
describe '.json_create' do
|
158
|
+
it 'should deserialize JSON to a cookie' do
|
159
|
+
json = '{"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}'
|
160
|
+
hash = JSON.parse json
|
161
|
+
c = Cookie.json_create hash
|
162
|
+
CookieValidation.validate_cookie 'https://localhost/', c
|
163
|
+
end
|
164
|
+
it 'should automatically deserialize to a cookie' do
|
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, create_additions: true
|
167
|
+
expect(c).to be_a Cookie
|
168
|
+
CookieValidation.validate_cookie 'https://localhost/', c
|
169
|
+
end
|
170
|
+
end
|
171
|
+
rescue LoadError
|
172
|
+
it 'does not appear the JSON library is installed' do
|
173
|
+
raise 'please install the JSON library'
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|