secobarbital-cookiejar 0.2.9.1
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/cookiejar/cookie.rb +252 -0
- data/lib/cookiejar/cookie_validation.rb +400 -0
- data/lib/cookiejar/jar.rb +308 -0
- data/lib/cookiejar.rb +2 -0
- data/test/cookie_test.rb +176 -0
- data/test/cookie_validation_test.rb +251 -0
- data/test/jar_test.rb +226 -0
- metadata +73 -0
@@ -0,0 +1,308 @@
|
|
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
|
+
# heirarchy.
|
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 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_value
|
60
|
+
cookie = Cookie.from_set_cookie request_uri, cookie_header_value
|
61
|
+
add_cookie cookie
|
62
|
+
end
|
63
|
+
|
64
|
+
# Given a request URI and a literal Set-Cookie2 header value, attempt to
|
65
|
+
# add the cookie to the cookie store.
|
66
|
+
#
|
67
|
+
# @param [String, URI] request_uri the resource returning the header
|
68
|
+
# @param [String] cookie_header_value the contents of the Set-Cookie2
|
69
|
+
# @return [Cookie] which was created and stored
|
70
|
+
# @raise [InvalidCookieError] if the cookie header did not validate
|
71
|
+
def set_cookie2 request_uri, cookie_header_value
|
72
|
+
cookie = Cookie.from_set_cookie2 request_uri, cookie_header_value
|
73
|
+
add_cookie cookie
|
74
|
+
end
|
75
|
+
|
76
|
+
# Given a request URI and some HTTP headers, attempt to add the cookie(s)
|
77
|
+
# (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
|
79
|
+
# and Set-Cookie2, the Set-Cookie version is ignored.
|
80
|
+
#
|
81
|
+
# @param [String, URI] request_uri the resource returning the header
|
82
|
+
# @param [Hash<String,[String,Array<String>]>] http_headers a Hash
|
83
|
+
# which may have a key of "Set-Cookie" or "Set-Cookie2", and values of
|
84
|
+
# either strings or arrays of strings
|
85
|
+
# @return [Array<Cookie>,nil] the cookies created, or nil if none found.
|
86
|
+
# @raise [InvalidCookieError] if one of the cookie headers contained
|
87
|
+
# invalid formatting or data
|
88
|
+
def set_cookies_from_headers request_uri, http_headers
|
89
|
+
set_cookie_key = http_headers.keys.detect { |k| /\ASet-Cookie\Z/i.match k }
|
90
|
+
cookies = gather_header_values http_headers[set_cookie_key] do |value|
|
91
|
+
begin
|
92
|
+
Cookie.from_set_cookie request_uri, value
|
93
|
+
rescue InvalidCookieError
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
set_cookie2_key = http_headers.keys.detect { |k| /\ASet-Cookie2\Z/i.match k }
|
98
|
+
cookies += gather_header_values(http_headers[set_cookie2_key]) do |value|
|
99
|
+
begin
|
100
|
+
Cookie.from_set_cookie2 request_uri, value
|
101
|
+
rescue InvalidCookieError
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# build the list of cookies, using a Jar. Since Set-Cookie2 values
|
106
|
+
# come second, they will replace the Set-Cookie versions.
|
107
|
+
jar = Jar.new
|
108
|
+
cookies.each do |cookie|
|
109
|
+
jar.add_cookie cookie
|
110
|
+
end
|
111
|
+
cookies = jar.to_a
|
112
|
+
|
113
|
+
# now add them all to our own store.
|
114
|
+
cookies.each do |cookie|
|
115
|
+
add_cookie cookie
|
116
|
+
end
|
117
|
+
cookies
|
118
|
+
end
|
119
|
+
|
120
|
+
# Add a pre-existing cookie object to the jar.
|
121
|
+
#
|
122
|
+
# @param [Cookie] cookie a pre-existing cookie object
|
123
|
+
# @return [Cookie] the cookie added to the store
|
124
|
+
def add_cookie cookie
|
125
|
+
domain_paths = find_or_add_domain_for_cookie cookie
|
126
|
+
add_cookie_to_path domain_paths, cookie
|
127
|
+
cookie
|
128
|
+
end
|
129
|
+
|
130
|
+
# Return an array of all cookie objects in the jar
|
131
|
+
#
|
132
|
+
# @return [Array<Cookie>] all cookies. Includes any expired cookies
|
133
|
+
# which have not yet been removed with expire_cookies
|
134
|
+
def to_a
|
135
|
+
result = []
|
136
|
+
@domains.values.each do |paths|
|
137
|
+
paths.values.each do |cookies|
|
138
|
+
cookies.values.inject result, :<<
|
139
|
+
end
|
140
|
+
end
|
141
|
+
result
|
142
|
+
end
|
143
|
+
|
144
|
+
# Return a JSON 'object' for the various data values. Allows for
|
145
|
+
# persistence of the cookie information
|
146
|
+
#
|
147
|
+
# @param [Array] a options controlling output JSON text
|
148
|
+
# (usually a State and a depth)
|
149
|
+
# @return [String] JSON representation of object data
|
150
|
+
def to_json *a
|
151
|
+
{
|
152
|
+
'json_class' => self.class.name,
|
153
|
+
'cookies' => (to_a.to_json *a)
|
154
|
+
}.to_json *a
|
155
|
+
end
|
156
|
+
|
157
|
+
# Create a new Jar from a JSON-backed hash
|
158
|
+
#
|
159
|
+
# @param o [Hash] the expanded JSON object
|
160
|
+
# @return [CookieJar] a new CookieJar instance
|
161
|
+
def self.json_create o
|
162
|
+
if o.is_a? Hash
|
163
|
+
o = o['cookies']
|
164
|
+
end
|
165
|
+
cookies = o.inject [] do |result, cookie_json|
|
166
|
+
result << (Cookie.json_create cookie_json)
|
167
|
+
end
|
168
|
+
self.from_a cookies
|
169
|
+
end
|
170
|
+
|
171
|
+
# Create a new Jar from an array of Cookie objects. Expired cookies
|
172
|
+
# will still be added to the archive, and conflicting cookies will
|
173
|
+
# be overwritten by the last cookie in the array.
|
174
|
+
#
|
175
|
+
# @param [Array<Cookie>] cookies array of cookie objects
|
176
|
+
# @return [CookieJar] a new CookieJar instance
|
177
|
+
def self.from_a cookies
|
178
|
+
jar = new
|
179
|
+
cookies.each do |cookie|
|
180
|
+
jar.add_cookie cookie
|
181
|
+
end
|
182
|
+
jar
|
183
|
+
end
|
184
|
+
|
185
|
+
# Look through the jar for any cookies which have passed their expiration
|
186
|
+
# date, or session cookies from a previous session
|
187
|
+
#
|
188
|
+
# @param session [Boolean] whether session cookies should be expired,
|
189
|
+
# or just cookies past their expiration date.
|
190
|
+
def expire_cookies session = false
|
191
|
+
@domains.delete_if do |domain, paths|
|
192
|
+
paths.delete_if do |path, cookies|
|
193
|
+
cookies.delete_if do |cookie_name, cookie|
|
194
|
+
cookie.expired? || (session && cookie.session?)
|
195
|
+
end
|
196
|
+
cookies.empty?
|
197
|
+
end
|
198
|
+
paths.empty?
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
# Given a request URI, return a sorted list of Cookie objects. Cookies
|
203
|
+
# will be in order per RFC 2965 - sorted by longest path length, but
|
204
|
+
# otherwise unordered.
|
205
|
+
#
|
206
|
+
# @param [String, URI] request_uri the address the HTTP request will be
|
207
|
+
# sent to
|
208
|
+
# @param [Hash] opts options controlling returned cookies
|
209
|
+
# @option opts [Boolean] :script (false) Cookies marked HTTP-only will be ignored
|
210
|
+
# if true
|
211
|
+
# @return [Array<Cookie>] cookies which should be sent in the HTTP request
|
212
|
+
def get_cookies request_uri, opts = { }
|
213
|
+
uri = to_uri request_uri
|
214
|
+
hosts = Cookie.compute_search_domains uri
|
215
|
+
|
216
|
+
results = []
|
217
|
+
hosts.each do |host|
|
218
|
+
domain = find_domain host
|
219
|
+
domain.each do |path, cookies|
|
220
|
+
if uri.path.start_with? path
|
221
|
+
results += cookies.values.select do |cookie|
|
222
|
+
cookie.should_send? uri, opts[:script]
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
#Sort by path length, longest first
|
228
|
+
results.sort do |lhs, rhs|
|
229
|
+
rhs.path.length <=> lhs.path.length
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
# Given a request URI, return a string Cookie header.Cookies will be in
|
234
|
+
# order per RFC 2965 - sorted by longest path length, but otherwise
|
235
|
+
# unordered.
|
236
|
+
#
|
237
|
+
# @param [String, URI] request_uri the address the HTTP request will be
|
238
|
+
# sent to
|
239
|
+
# @param [Hash] opts options controlling returned cookies
|
240
|
+
# @option opts [Boolean] :script (false) Cookies marked HTTP-only will be ignored
|
241
|
+
# if true
|
242
|
+
# @return String value of the Cookie header which should be sent on the
|
243
|
+
# HTTP request
|
244
|
+
def get_cookie_header request_uri, opts = { }
|
245
|
+
cookies = get_cookies request_uri, opts
|
246
|
+
version = 0
|
247
|
+
ver = [[],[]]
|
248
|
+
cookies.each do |cookie|
|
249
|
+
ver[cookie.version] << cookie
|
250
|
+
end
|
251
|
+
if (ver[1].empty?)
|
252
|
+
# can do a netscape-style cookie header, relish the opportunity
|
253
|
+
cookies.map do |cookie|
|
254
|
+
cookie.to_s
|
255
|
+
end.join ";"
|
256
|
+
else
|
257
|
+
# build a RFC 2965-style cookie header. Split the cookies into
|
258
|
+
# version 0 and 1 groups so that we can reuse the '$Version' header
|
259
|
+
result = ''
|
260
|
+
unless ver[0].empty?
|
261
|
+
result << '$Version=0;'
|
262
|
+
result << ver[0].map do |cookie|
|
263
|
+
(cookie.to_s 1,false)
|
264
|
+
end.join(';')
|
265
|
+
# separate version 0 and 1 with a comma
|
266
|
+
result << ','
|
267
|
+
end
|
268
|
+
result << '$Version=1;'
|
269
|
+
ver[1].map do |cookie|
|
270
|
+
result << (cookie.to_s 1,false)
|
271
|
+
end
|
272
|
+
result
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
protected
|
277
|
+
|
278
|
+
def gather_header_values http_header_value, &block
|
279
|
+
result = []
|
280
|
+
http_header_value
|
281
|
+
if http_header_value.is_a? Array
|
282
|
+
http_header_value.each do |value|
|
283
|
+
result << block.call(value)
|
284
|
+
end
|
285
|
+
elsif http_header_value.is_a? String
|
286
|
+
result << block.call(http_header_value)
|
287
|
+
end
|
288
|
+
result.compact
|
289
|
+
end
|
290
|
+
|
291
|
+
def to_uri request_uri
|
292
|
+
(request_uri.is_a? URI)? request_uri : (URI.parse request_uri)
|
293
|
+
end
|
294
|
+
|
295
|
+
def find_domain host
|
296
|
+
@domains[host] || {}
|
297
|
+
end
|
298
|
+
|
299
|
+
def find_or_add_domain_for_cookie cookie
|
300
|
+
@domains[cookie.domain] ||= {}
|
301
|
+
end
|
302
|
+
|
303
|
+
def add_cookie_to_path paths, cookie
|
304
|
+
path_entry = (paths[cookie.path] ||= {})
|
305
|
+
path_entry[cookie.name] = cookie
|
306
|
+
end
|
307
|
+
end
|
308
|
+
end
|
data/lib/cookiejar.rb
ADDED
data/test/cookie_test.rb
ADDED
@@ -0,0 +1,176 @@
|
|
1
|
+
require 'cookiejar'
|
2
|
+
require 'rubygems'
|
3
|
+
|
4
|
+
include CookieJar
|
5
|
+
|
6
|
+
FOO_URL = 'http://localhost/foo'
|
7
|
+
AMMO_URL = 'http://localhost/ammo'
|
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]]
|
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 = 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
|
+
cookie.name.should == 'foo'
|
31
|
+
cookie.value.should == 'bar'
|
32
|
+
end
|
33
|
+
it "should normalize domain names" do
|
34
|
+
cookie = Cookie.from_set_cookie 'http://localhost/', 'foo=Bar;domain=LoCaLHoSt.local'
|
35
|
+
cookie.domain.should == '.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
|
+
cookie.domain.should == '.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
|
+
cookie.name.should == 'GALX'
|
44
|
+
cookie.secure.should be_true
|
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
|
+
cookie.name.should == 'foo'
|
51
|
+
cookie.value.should == '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
|
+
cookie.domain.should == '.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
|
+
cookie.domain.should == '.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
|
+
cookie.name.should == 'GALX'
|
64
|
+
cookie.path.should == '/a/'
|
65
|
+
cookie.secure.should be_true
|
66
|
+
end
|
67
|
+
it "should fail on unquoted paths" do
|
68
|
+
lambda do
|
69
|
+
Cookie.from_set_cookie2 'https://www.google.com/a/blah',
|
70
|
+
'GALX=RgmSftjnbPM;Path=/a/;Secure;Version=1'
|
71
|
+
end.should 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
|
+
cookie.name.should == 'foo'
|
76
|
+
cookie.value.should == '"bar"'
|
77
|
+
end
|
78
|
+
it "should accept poorly chosen names" do
|
79
|
+
cookie = Cookie.from_set_cookie2 'http://localhost/', 'Version=mine;Version=1'
|
80
|
+
cookie.name.should == 'Version'
|
81
|
+
cookie.value.should == 'mine'
|
82
|
+
end
|
83
|
+
it "should accept quoted parameter values" do
|
84
|
+
cookie = 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
|
+
cookie.should be_session
|
89
|
+
cookie.should_not be_expired
|
90
|
+
|
91
|
+
cookie = Cookie.from_set_cookie2 'http://localhost/', 'f=b;max-age=100;Version=1'
|
92
|
+
cookie.should_not be_session
|
93
|
+
|
94
|
+
cookie = Cookie.from_set_cookie2 'http://localhost/', 'f=b;Version=1'
|
95
|
+
cookie.should be_session
|
96
|
+
end
|
97
|
+
it "should handle quotable quotes" do
|
98
|
+
cookie = Cookie.from_set_cookie2 'http://localhost/', 'f="\"";Version=1'
|
99
|
+
cookie.value.should eql '"\""'
|
100
|
+
end
|
101
|
+
it "should handle quotable apostrophes" do
|
102
|
+
cookie = Cookie.from_set_cookie2 'http://localhost/', 'f="\;";Version=1'
|
103
|
+
cookie.value.should eql '"\;"'
|
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
|
+
cookie.decoded_value.should eql '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
|
+
cookie.value.should eql '"\"b"'
|
114
|
+
cookie.decoded_value.should eql '"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
|
+
cookie.to_s.should == 'f=b'
|
121
|
+
cookie.to_s(1).should == '$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
|
+
cookie.to_s(1).should == '$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
|
+
cookie.to_s(1).should == '$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
|
+
cookie.to_s.should == 'f=b'
|
134
|
+
cookie.to_s(1).should == '$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
|
+
cookie.to_s(1,false).should == '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
|
+
cookie.should_send?("http://localhost/", false).should be_true
|
145
|
+
cookie.should_send?("https://localhost/", false).should be_false
|
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
|
+
json.should 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
|
167
|
+
c.should 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
|