rack-test 1.1.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/History.md +82 -1
- data/MIT-LICENSE.txt +1 -0
- data/README.md +52 -63
- data/lib/rack/mock_session.rb +2 -63
- data/lib/rack/test/cookie_jar.rb +101 -49
- data/lib/rack/test/methods.rb +57 -45
- data/lib/rack/test/mock_digest_request.rb +11 -1
- data/lib/rack/test/uploaded_file.rb +35 -11
- data/lib/rack/test/utils.rb +75 -61
- data/lib/rack/test/version.rb +1 -1
- data/lib/rack/test.rb +223 -143
- metadata +27 -96
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f6f9d525a0e1136056dcc7ebfb288dd4a0f2d82b02bc7f6b4de8a8b1e1b2f653
|
4
|
+
data.tar.gz: 2503679c0681795e9db75ec5963eaea12f2f934b4e5e3d23a30396a318e2ad3c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2b593ae59ec047f4048c96af421865855129563be719e9a0da088d275f20b3143300d83b4783aa073230bc8cc9118289562f83797682dd1a09073e0cbedc8fcb
|
7
|
+
data.tar.gz: 9f98f0e2d36fe2cf33193a279acca2c62bcf3e5c91bb8adc3a0a71d929ff92b24ab27e7bb826c70cecc52fda5c67c7af57a7d471ff7456c13421d6c719ace434
|
data/History.md
CHANGED
@@ -1,3 +1,84 @@
|
|
1
|
+
## 2.0.0 / 2022-06-24
|
2
|
+
|
3
|
+
* Breaking changes:
|
4
|
+
* Digest authentication support is now deprecated, as it relies on
|
5
|
+
digest authentication support in rack, which has been deprecated
|
6
|
+
(Jeremy Evans #294)
|
7
|
+
* `Rack::Test::Utils.build_primitive_part` no longer handles array
|
8
|
+
values (Jeremy Evans #292)
|
9
|
+
* `Rack::Test::Utils` module methods other than `build_nested_query`
|
10
|
+
and `build_multipart` are now private methods (Jeremy Evans #297)
|
11
|
+
* `Rack::MockSession` has been combined into `Rack::Test::Session`,
|
12
|
+
and remains as an alias to `Rack::Test::Session`, but to keep some
|
13
|
+
backwards compatibility, `Rack::Test::Session.new` will accept a
|
14
|
+
`Rack::Test::Session` instance and return it (Jeremy Evans #297)
|
15
|
+
* Previously protected methods in `Rack::Test::Cookie{,Jar}` are now
|
16
|
+
private methods (Jeremy Evans #297)
|
17
|
+
* `Rack::Test::Methods` no longer defines `build_rack_mock_session`,
|
18
|
+
but for backwards compatibility, `build_rack_test_session` will call
|
19
|
+
`build_rack_mock_session` if it is defined (Jeremy Evans #297)
|
20
|
+
* `Rack::Test::Methods::METHODS` is no longer defined
|
21
|
+
(Jeremy Evans #297)
|
22
|
+
* `Rack::Test::Methods#_current_session_names` has been removed
|
23
|
+
(Jeremy Evans #297)
|
24
|
+
* Headers used/accessed by rack-test are now lower case, for rack 3
|
25
|
+
compliance (Jeremy Evans #295)
|
26
|
+
* Frozen literal strings are now used internally, which may break
|
27
|
+
code that mutates static strings returned by rack-test, if any
|
28
|
+
(Jeremy Evans #304)
|
29
|
+
|
30
|
+
* Minor enhancements:
|
31
|
+
* rack-test now works with the rack main branch (what will be rack 3)
|
32
|
+
(Jeremy Evans #280 #292)
|
33
|
+
* rack-test only loads the parts of rack it uses when running on the
|
34
|
+
rack main branch (what will be rack 3) (Jeremy Evans #292)
|
35
|
+
* Development dependencies have been significantly reduced, and are
|
36
|
+
now a subset of the development dependencies of rack itself
|
37
|
+
(Jeremy Evans #292)
|
38
|
+
* Avoid creating multiple large copies of uploaded file data in
|
39
|
+
memory (Jeremy Evans #286)
|
40
|
+
* Specify HTTP/1.0 when submitting requests, to avoid responses with
|
41
|
+
Transfer-Encoding: chunked (Jeremy Evans #288)
|
42
|
+
* Support `:query_params` in rack environment for parameters that
|
43
|
+
are appended to the query string instead of used in the request
|
44
|
+
body (Jeremy Evans #150 #287)
|
45
|
+
* Reduce required ruby version to 2.0, since tests run fine on
|
46
|
+
Ruby 2.0 (Jeremy Evans #292)
|
47
|
+
* Support :multipart env key for request methods to force multipart
|
48
|
+
input (Jeremy Evans #303)
|
49
|
+
* Force multipart input for request methods if content type starts
|
50
|
+
with multipart (Jeremy Evans #303)
|
51
|
+
* Improve performance of Utils.build_multipart by using an
|
52
|
+
append-only design (Jeremy Evans #304)
|
53
|
+
* Improve performance of Utils.build_nested_query for array values
|
54
|
+
(Jeremy Evans #304)
|
55
|
+
|
56
|
+
* Bug fixes:
|
57
|
+
* The `CONTENT_TYPE` of multipart requests is now respected, if it
|
58
|
+
starts with `multipart/` (Tom Knig #238)
|
59
|
+
* Work correctly with responses that respond to `to_a` but not
|
60
|
+
`to_ary` (Sergio Faria #276)
|
61
|
+
* Raise an ArgumentError instead of a TypeError when providing a
|
62
|
+
StringIO without an original filename when creating an
|
63
|
+
UploadedFile (Nuno Correia #279)
|
64
|
+
* Allow combining both an UploadedFile and a plain string when
|
65
|
+
building a multipart upload (Mitsuhiro Shibuya #278)
|
66
|
+
* Fix the generation of filenames with spaces to use path
|
67
|
+
escaping instead of regular escaping, since path unescaping is
|
68
|
+
used to decode it (Muir Manders, Jeremy Evans #275 #284)
|
69
|
+
* Rewind tempfile used for multipart uploads before it is
|
70
|
+
submitted to the application
|
71
|
+
(Jeremy Evans, Alexander Dervish #261 #268 #286)
|
72
|
+
* Fix Rack::Test.encoding_aware_strings to be true only on rack
|
73
|
+
1.6+ (Jeremy Evans #292)
|
74
|
+
* Make Rack::Test::CookieJar#valid? return true/false
|
75
|
+
(Jeremy Evans #292)
|
76
|
+
* Cookies without a domain attribute no longer are submitted to
|
77
|
+
requests for subdomains of that domain, for RFC 6265
|
78
|
+
compliance (Jeremy Evans #292)
|
79
|
+
* Increase required rack version to 1.3, since tests fail on
|
80
|
+
rack 1.2 and below (Jeremy Evans #293)
|
81
|
+
|
1
82
|
## 1.1.0 / 2018-07-21
|
2
83
|
|
3
84
|
* Breaking changes:
|
@@ -8,7 +89,7 @@
|
|
8
89
|
* follow_direct: Include rack.session.options (Mark Edmondson #233)
|
9
90
|
* [CI] Add simplecov (fatkodima #227)
|
10
91
|
|
11
|
-
Bug fixes:
|
92
|
+
* Bug fixes:
|
12
93
|
* Follow relative locations correctly. (Samuel Williams #230)
|
13
94
|
|
14
95
|
## 1.0.0 / 2018-03-27
|
data/MIT-LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -1,10 +1,7 @@
|
|
1
1
|
# Rack::Test
|
2
2
|
[![Gem Version](https://badge.fury.io/rb/rack-test.svg)](https://badge.fury.io/rb/rack-test)
|
3
|
-
[<img src="https://travis-ci.org/rack-test/rack-test.svg?branch=master" />](https://travis-ci.org/rack-test/rack-test)
|
4
|
-
[![Code Climate](https://codeclimate.com/github/rack-test/rack-test/badges/gpa.svg)](https://codeclimate.com/github/rack-test/rack-test)
|
5
|
-
[![Test Coverage](https://codeclimate.com/github/rack-test/rack-test/badges/coverage.svg)](https://codeclimate.com/github/rack-test/rack-test/coverage)
|
6
3
|
|
7
|
-
Code: https://github.com/rack
|
4
|
+
Code: https://github.com/rack/rack-test
|
8
5
|
|
9
6
|
## Description
|
10
7
|
|
@@ -14,76 +11,66 @@ to build on.
|
|
14
11
|
|
15
12
|
## Features
|
16
13
|
|
14
|
+
* Allows for submitting requests and testing responses
|
17
15
|
* Maintains a cookie jar across requests
|
18
|
-
*
|
19
|
-
*
|
20
|
-
* Small footprint. Approximately 200 LOC
|
21
|
-
|
22
|
-
## Supported platforms
|
23
|
-
|
24
|
-
* 2.2.2+
|
25
|
-
* 2.3
|
26
|
-
* 2.4
|
27
|
-
* JRuby 9.1.+
|
28
|
-
|
29
|
-
If you are using Ruby 1.8, 1.9 or JRuby 1.7, use rack-test 0.6.3.
|
30
|
-
|
31
|
-
## Known incompatibilites
|
32
|
-
|
33
|
-
* `rack-test >= 0.71` _does not_ work with older Capybara versions (`< 2.17`). See [#214](https://github.com/rack-test/rack-test/issues/214) for more details.
|
16
|
+
* Supports request headers used for subsequent requests
|
17
|
+
* Follow redirects when requested
|
34
18
|
|
35
19
|
## Examples
|
36
|
-
|
20
|
+
|
21
|
+
These examples use `test/unit` but it's equally possible to use `rack-test` with
|
22
|
+
other testing frameworks such as `minitest` or `rspec`.
|
37
23
|
|
38
24
|
```ruby
|
39
25
|
require "test/unit"
|
40
26
|
require "rack/test"
|
27
|
+
require "json"
|
41
28
|
|
42
29
|
class HomepageTest < Test::Unit::TestCase
|
43
30
|
include Rack::Test::Methods
|
44
31
|
|
45
32
|
def app
|
46
|
-
|
47
|
-
builder = Rack::Builder.new
|
48
|
-
builder.run app
|
33
|
+
lambda { |env| [200, {'content-type' => 'text/plain'}, ['All responses are OK']] }
|
49
34
|
end
|
50
35
|
|
51
36
|
def test_response_is_ok
|
52
|
-
|
37
|
+
# Optionally set headers used for all requests in this spec:
|
38
|
+
#header 'accept-charset', 'utf-8'
|
53
39
|
|
54
|
-
|
55
|
-
assert_equal last_response.body, 'All responses are OK'
|
56
|
-
end
|
57
|
-
|
58
|
-
def set_request_headers
|
59
|
-
header 'Accept-Charset', 'utf-8'
|
40
|
+
# First argument is treated as the path
|
60
41
|
get '/'
|
61
42
|
|
62
43
|
assert last_response.ok?
|
63
44
|
assert_equal last_response.body, 'All responses are OK'
|
64
45
|
end
|
65
46
|
|
66
|
-
def
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
47
|
+
def delete_with_url_params_and_body
|
48
|
+
# First argument can have a query string
|
49
|
+
#
|
50
|
+
# Second argument is used as the parameters for the request, which will be
|
51
|
+
# included in the request body for non-GET requests.
|
52
|
+
delete '/?foo=bar', JSON.generate('baz' => 'zot')
|
71
53
|
end
|
72
54
|
|
73
55
|
def post_with_json
|
74
|
-
#
|
75
|
-
#
|
76
|
-
#
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
56
|
+
# Third argument is the rack environment to use for the request. The following
|
57
|
+
# entries in the submitted rack environment are treated specially (in addition
|
58
|
+
# to options supported by `Rack::MockRequest#env_for`:
|
59
|
+
#
|
60
|
+
# :cookie : Set a cookie for the current session before submitting the request.
|
61
|
+
#
|
62
|
+
# :query_params : Set parameters for the query string (as opposed to the body).
|
63
|
+
# Value should be a hash of parameters.
|
64
|
+
#
|
65
|
+
# :xhr : Set HTTP_X_REQUESTED_WITH env key to XMLHttpRequest.
|
66
|
+
post(uri, JSON.generate('baz' => 'zot'), 'CONTENT_TYPE' => 'application/json')
|
82
67
|
end
|
83
68
|
end
|
84
69
|
```
|
85
70
|
|
86
|
-
|
71
|
+
`rack-test` will test the app returned by the `app` method. If you are loading middleware
|
72
|
+
in a `config.ru` file, and want to test that, you should load the Rack app created from
|
73
|
+
the `config.ru` file:
|
87
74
|
|
88
75
|
```ruby
|
89
76
|
OUTER_APP = Rack::Builder.parse_file("config.ru").first
|
@@ -102,7 +89,6 @@ class TestApp < Test::Unit::TestCase
|
|
102
89
|
end
|
103
90
|
```
|
104
91
|
|
105
|
-
|
106
92
|
## Install
|
107
93
|
|
108
94
|
To install the latest release as a gem:
|
@@ -111,40 +97,43 @@ To install the latest release as a gem:
|
|
111
97
|
gem install rack-test
|
112
98
|
```
|
113
99
|
|
114
|
-
Or
|
100
|
+
Or add to your `Gemfile`:
|
115
101
|
|
116
102
|
```
|
117
103
|
gem 'rack-test'
|
118
104
|
```
|
119
105
|
|
120
|
-
|
106
|
+
## Contribution
|
121
107
|
|
122
|
-
|
123
|
-
|
124
|
-
|
108
|
+
Contributions are welcome. Please make sure to:
|
109
|
+
|
110
|
+
* Use a regular forking workflow
|
111
|
+
* Write tests for the new or changed behaviour
|
112
|
+
* Provide an explanation/motivation in your commit message / PR message
|
113
|
+
* Ensure `History.md` is updated
|
125
114
|
|
126
115
|
## Authors
|
127
116
|
|
128
|
-
- Contributions from Bryan Helmkamp, Simon Rozet,
|
117
|
+
- Contributions from Bryan Helmkamp, Jeremy Evans, Simon Rozet, and others
|
129
118
|
- Much of the original code was extracted from Merb 1.0's request helper
|
130
119
|
|
131
120
|
## License
|
132
|
-
`rack-test` is released under the [MIT License](MIT-LICENSE.txt).
|
133
121
|
|
134
|
-
|
122
|
+
`rack-test` is released under the [MIT License](MIT-LICENSE.txt).
|
135
123
|
|
136
|
-
|
124
|
+
## Supported platforms
|
137
125
|
|
138
|
-
*
|
139
|
-
*
|
140
|
-
* Provide an explanation/motivation in your commit message / PR message
|
141
|
-
* Ensure History.txt is updated
|
126
|
+
* Ruby 2.0+
|
127
|
+
* JRuby 9.1+
|
142
128
|
|
143
129
|
## Releasing
|
144
130
|
|
145
|
-
* Ensure `History.md` is up-to-date
|
146
131
|
* Bump VERSION in lib/rack/test/version.rb
|
147
|
-
* `
|
132
|
+
* Ensure `History.md` is up-to-date, including correct version and date
|
133
|
+
* `git commit . -m 'Release $VERSION'`
|
148
134
|
* `git push`
|
149
|
-
*
|
150
|
-
*
|
135
|
+
* `git tag -a -m 'Tag the $VERSION release' $VERSION`
|
136
|
+
* `git push --tags`
|
137
|
+
* `gem build rack-test.gemspec`
|
138
|
+
* `gem push rack-test-$VERSION.gem`
|
139
|
+
* Add a discussion post for the release
|
data/lib/rack/mock_session.rb
CHANGED
@@ -1,63 +1,2 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
attr_writer :cookie_jar
|
4
|
-
attr_reader :default_host
|
5
|
-
|
6
|
-
def initialize(app, default_host = Rack::Test::DEFAULT_HOST)
|
7
|
-
@app = app
|
8
|
-
@after_request = []
|
9
|
-
@default_host = default_host
|
10
|
-
@last_request = nil
|
11
|
-
@last_response = nil
|
12
|
-
end
|
13
|
-
|
14
|
-
def after_request(&block)
|
15
|
-
@after_request << block
|
16
|
-
end
|
17
|
-
|
18
|
-
def clear_cookies
|
19
|
-
@cookie_jar = Rack::Test::CookieJar.new([], @default_host)
|
20
|
-
end
|
21
|
-
|
22
|
-
def set_cookie(cookie, uri = nil)
|
23
|
-
cookie_jar.merge(cookie, uri)
|
24
|
-
end
|
25
|
-
|
26
|
-
def request(uri, env)
|
27
|
-
env['HTTP_COOKIE'] ||= cookie_jar.for(uri)
|
28
|
-
@last_request = Rack::Request.new(env)
|
29
|
-
status, headers, body = @app.call(@last_request.env)
|
30
|
-
|
31
|
-
@last_response = MockResponse.new(status, headers, body, env['rack.errors'].flush)
|
32
|
-
body.close if body.respond_to?(:close)
|
33
|
-
|
34
|
-
cookie_jar.merge(last_response.headers['Set-Cookie'], uri)
|
35
|
-
|
36
|
-
@after_request.each(&:call)
|
37
|
-
|
38
|
-
if @last_response.respond_to?(:finish)
|
39
|
-
@last_response.finish
|
40
|
-
else
|
41
|
-
@last_response
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
# Return the last request issued in the session. Raises an error if no
|
46
|
-
# requests have been sent yet.
|
47
|
-
def last_request
|
48
|
-
raise Rack::Test::Error, 'No request yet. Request a page first.' unless @last_request
|
49
|
-
@last_request
|
50
|
-
end
|
51
|
-
|
52
|
-
# Return the last response received in the session. Raises an error if
|
53
|
-
# no requests have been sent yet.
|
54
|
-
def last_response
|
55
|
-
raise Rack::Test::Error, 'No response yet. Request a page first.' unless @last_response
|
56
|
-
@last_response
|
57
|
-
end
|
58
|
-
|
59
|
-
def cookie_jar
|
60
|
-
@cookie_jar ||= Rack::Test::CookieJar.new([], @default_host)
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
1
|
+
warn("requiring rack/mock_session is deprecated, require rack/test and use Rack::Test::Session", uplevel: 1)
|
2
|
+
require_relative 'test'
|
data/lib/rack/test/cookie_jar.rb
CHANGED
@@ -1,94 +1,114 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'uri'
|
2
4
|
require 'time'
|
3
5
|
|
4
6
|
module Rack
|
5
7
|
module Test
|
8
|
+
# Represents individual cookies in the cookie jar. This is considered private
|
9
|
+
# API and behavior of this class can change at any time.
|
6
10
|
class Cookie # :nodoc:
|
7
11
|
include Rack::Utils
|
8
12
|
|
9
|
-
#
|
10
|
-
attr_reader :name
|
13
|
+
# The name of the cookie, will be a string
|
14
|
+
attr_reader :name
|
15
|
+
|
16
|
+
# The value of the cookie, will be a string or nil if there is no value.
|
17
|
+
attr_reader :value
|
18
|
+
|
19
|
+
# The raw string for the cookie, without options. Will generally be in
|
20
|
+
# name=value format is name and value are provided.
|
21
|
+
attr_reader :raw
|
11
22
|
|
12
|
-
# :api: private
|
13
23
|
def initialize(raw, uri = nil, default_host = DEFAULT_HOST)
|
14
24
|
@default_host = default_host
|
15
25
|
uri ||= default_uri
|
16
26
|
|
17
27
|
# separate the name / value pair from the cookie options
|
18
|
-
@
|
28
|
+
@raw, options = raw.split(/[;,] */n, 2)
|
19
29
|
|
20
|
-
@name, @value = parse_query(@
|
30
|
+
@name, @value = parse_query(@raw, ';').to_a.first
|
21
31
|
@options = parse_query(options, ';')
|
22
32
|
|
23
|
-
@options['domain']
|
24
|
-
|
33
|
+
if @options['domain']
|
34
|
+
@exact_domain_match = false
|
35
|
+
else
|
36
|
+
# If the domain attribute is not present in the cookie,
|
37
|
+
# the domain must match exactly.
|
38
|
+
@exact_domain_match = true
|
39
|
+
@options['domain'] = (uri.host || default_host)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Set the path for the cookie to the directory containing
|
43
|
+
# the request if it isn't set.
|
44
|
+
@options['path'] ||= uri.path.sub(/\/[^\/]*\Z/, '')
|
25
45
|
end
|
26
46
|
|
47
|
+
# Wether the given cookie can replace the current cookie in the cookie jar.
|
27
48
|
def replaces?(other)
|
28
49
|
[name.downcase, domain, path] == [other.name.downcase, other.domain, other.path]
|
29
50
|
end
|
30
51
|
|
31
|
-
#
|
32
|
-
def raw
|
33
|
-
@name_value_raw
|
34
|
-
end
|
35
|
-
|
36
|
-
# :api: private
|
52
|
+
# Whether the cookie has a value.
|
37
53
|
def empty?
|
38
54
|
@value.nil? || @value.empty?
|
39
55
|
end
|
40
56
|
|
41
|
-
#
|
57
|
+
# The explicit or implicit domain for the cookie.
|
42
58
|
def domain
|
43
59
|
@options['domain']
|
44
60
|
end
|
45
61
|
|
62
|
+
# Whether the cookie has the secure flag, indicating it can only be sent over
|
63
|
+
# an encrypted connection.
|
46
64
|
def secure?
|
47
65
|
@options.key?('secure')
|
48
66
|
end
|
49
67
|
|
68
|
+
# Whether the cookie has the httponly flag, indicating it is not available via
|
69
|
+
# a javascript API.
|
50
70
|
def http_only?
|
51
|
-
@options.key?('HttpOnly')
|
71
|
+
@options.key?('HttpOnly') || @options.key?('httponly')
|
52
72
|
end
|
53
73
|
|
54
|
-
#
|
74
|
+
# The explicit or implicit path for the cookie.
|
55
75
|
def path
|
56
76
|
([*@options['path']].first.split(',').first || '/').strip
|
57
77
|
end
|
58
78
|
|
59
|
-
#
|
79
|
+
# A Time value for when the cookie expires, if the expires option is set.
|
60
80
|
def expires
|
61
81
|
Time.parse(@options['expires']) if @options['expires']
|
62
82
|
end
|
63
83
|
|
64
|
-
#
|
84
|
+
# Whether the cookie is currently expired.
|
65
85
|
def expired?
|
66
86
|
expires && expires < Time.now
|
67
87
|
end
|
68
88
|
|
69
|
-
#
|
89
|
+
# Whether the cookie is valid for the given URI.
|
70
90
|
def valid?(uri)
|
71
91
|
uri ||= default_uri
|
72
92
|
|
73
93
|
uri.host = @default_host if uri.host.nil?
|
74
94
|
|
75
95
|
real_domain = domain =~ /^\./ ? domain[1..-1] : domain
|
76
|
-
(!secure? || (secure? && uri.scheme == 'https')) &&
|
77
|
-
uri.host =~ Regexp.new("#{Regexp.escape(real_domain)}$", Regexp::IGNORECASE) &&
|
78
|
-
uri.path =~ Regexp.new("^#{Regexp.escape(path)}")
|
96
|
+
!!((!secure? || (secure? && uri.scheme == 'https')) &&
|
97
|
+
uri.host =~ Regexp.new("#{'^' if @exact_domain_match}#{Regexp.escape(real_domain)}$", Regexp::IGNORECASE) &&
|
98
|
+
uri.path =~ Regexp.new("^#{Regexp.escape(path)}"))
|
79
99
|
end
|
80
100
|
|
81
|
-
#
|
101
|
+
# Cookies that do not match the URI will not be sent in requests to the URI.
|
82
102
|
def matches?(uri)
|
83
103
|
!expired? && valid?(uri)
|
84
104
|
end
|
85
105
|
|
86
|
-
#
|
106
|
+
# Order cookies by name, path, and domain.
|
87
107
|
def <=>(other)
|
88
|
-
# Orders the cookies from least specific to most
|
89
108
|
[name, path, domain.reverse] <=> [other.name, other.path, other.domain.reverse]
|
90
109
|
end
|
91
110
|
|
111
|
+
# A hash of cookie options, including the cookie value, but excluding the cookie name.
|
92
112
|
def to_h
|
93
113
|
@options.merge(
|
94
114
|
'value' => @value,
|
@@ -98,43 +118,62 @@ module Rack
|
|
98
118
|
end
|
99
119
|
alias to_hash to_h
|
100
120
|
|
101
|
-
|
121
|
+
private
|
102
122
|
|
123
|
+
# The default URI to use for the cookie, including just the host.
|
103
124
|
def default_uri
|
104
125
|
URI.parse('//' + @default_host + '/')
|
105
126
|
end
|
106
127
|
end
|
107
128
|
|
129
|
+
# Represents all cookies for a session, handling adding and
|
130
|
+
# removing cookies, and finding which cookies apply to a given
|
131
|
+
# request. This is considered private API and behavior of this
|
132
|
+
# class can change at any time.
|
108
133
|
class CookieJar # :nodoc:
|
109
134
|
DELIMITER = '; '.freeze
|
110
135
|
|
111
|
-
# :api: private
|
112
136
|
def initialize(cookies = [], default_host = DEFAULT_HOST)
|
113
137
|
@default_host = default_host
|
114
|
-
@cookies = cookies
|
115
|
-
@cookies.sort!
|
138
|
+
@cookies = cookies.sort!
|
116
139
|
end
|
117
140
|
|
141
|
+
# Return the value for first cookie with the given name, or nil
|
142
|
+
# if no such cookie exists.
|
118
143
|
def [](name)
|
119
|
-
|
120
|
-
|
121
|
-
|
144
|
+
name = name.to_s
|
145
|
+
@cookies.each do |cookie|
|
146
|
+
return cookie.value if cookie.name == name
|
147
|
+
end
|
148
|
+
nil
|
122
149
|
end
|
123
150
|
|
151
|
+
# Set a cookie with the given name and value in the
|
152
|
+
# cookie jar.
|
124
153
|
def []=(name, value)
|
125
154
|
merge("#{name}=#{Rack::Utils.escape(value)}")
|
126
155
|
end
|
127
156
|
|
157
|
+
# Return the first cookie with the given name, or nil if
|
158
|
+
# no such cookie exists.
|
128
159
|
def get_cookie(name)
|
129
|
-
|
160
|
+
@cookies.each do |cookie|
|
161
|
+
return cookie if cookie.name == name
|
162
|
+
end
|
163
|
+
nil
|
130
164
|
end
|
131
165
|
|
166
|
+
# Delete all cookies with the given name from the cookie jar.
|
132
167
|
def delete(name)
|
133
168
|
@cookies.reject! do |cookie|
|
134
169
|
cookie.name == name
|
135
170
|
end
|
171
|
+
nil
|
136
172
|
end
|
137
173
|
|
174
|
+
# Add a string of raw cookie information to the cookie jar,
|
175
|
+
# if the cookie is valid for the given URI.
|
176
|
+
# Cookies should be separated with a newline.
|
138
177
|
def merge(raw_cookies, uri = nil)
|
139
178
|
return unless raw_cookies
|
140
179
|
|
@@ -149,6 +188,7 @@ module Rack
|
|
149
188
|
end
|
150
189
|
end
|
151
190
|
|
191
|
+
# Add a Cookie to the cookie jar.
|
152
192
|
def <<(new_cookie)
|
153
193
|
@cookies.reject! do |existing_cookie|
|
154
194
|
new_cookie.replaces?(existing_cookie)
|
@@ -158,36 +198,48 @@ module Rack
|
|
158
198
|
@cookies.sort!
|
159
199
|
end
|
160
200
|
|
161
|
-
#
|
201
|
+
# Return a raw cookie string for the cookie header to
|
202
|
+
# use for the given URI.
|
162
203
|
def for(uri)
|
163
|
-
|
204
|
+
buf = String.new
|
205
|
+
delimiter = nil
|
206
|
+
|
207
|
+
each_cookie_for(uri) do |cookie|
|
208
|
+
if delimiter
|
209
|
+
buf << delimiter
|
210
|
+
else
|
211
|
+
delimiter = DELIMITER
|
212
|
+
end
|
213
|
+
buf << cookie.raw
|
214
|
+
end
|
215
|
+
|
216
|
+
buf
|
164
217
|
end
|
165
218
|
|
219
|
+
# Return a hash cookie names and cookie values for cookies in the jar.
|
166
220
|
def to_hash
|
167
221
|
cookies = {}
|
168
222
|
|
169
|
-
|
170
|
-
cookies[name] = cookie.value
|
223
|
+
@cookies.each do |cookie|
|
224
|
+
cookies[cookie.name] = cookie.value
|
171
225
|
end
|
172
226
|
|
173
227
|
cookies
|
174
228
|
end
|
175
229
|
|
176
|
-
|
230
|
+
private
|
177
231
|
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
232
|
+
# Yield each cookie that matches for the URI.
|
233
|
+
#
|
234
|
+
# The cookies are sorted by most specific first. So, we loop through
|
235
|
+
# all the cookies in order and add it to a hash by cookie name if
|
236
|
+
# the cookie can be sent to the current URI. It's added to the hash
|
237
|
+
# so that when we are done, the cookies will be unique by name and
|
238
|
+
# we'll have grabbed the most specific to the URI.
|
239
|
+
def each_cookie_for(uri)
|
186
240
|
@cookies.each do |cookie|
|
187
|
-
|
241
|
+
yield cookie if !uri || cookie.matches?(uri)
|
188
242
|
end
|
189
|
-
|
190
|
-
cookies
|
191
243
|
end
|
192
244
|
end
|
193
245
|
end
|