cookiejar2 0.3.5 → 0.3.5.2

Sign up to get free protection for your applications and to get access to all the features.
data/lib/cookiejar/jar.rb DELETED
@@ -1,314 +0,0 @@
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
@@ -1,4 +0,0 @@
1
- # frozen_string_literal: true
2
- module CookieJar
3
- VERSION = '0.3.5'.freeze
4
- end
data/lib/cookiejar.rb DELETED
@@ -1,3 +0,0 @@
1
- require 'cookiejar/cookie'
2
- require 'cookiejar/jar'
3
- require 'cookiejar/version'
data/spec/cookie_spec.rb DELETED
@@ -1,176 +0,0 @@
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