rack-test 0.6.3 → 0.8.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/History.md +229 -0
- data/README.md +140 -0
- data/lib/rack/mock_session.rb +6 -9
- data/lib/rack/test/cookie_jar.rb +38 -28
- data/lib/rack/test/methods.rb +22 -22
- data/lib/rack/test/mock_digest_request.rb +1 -5
- data/lib/rack/test/uploaded_file.rb +50 -19
- data/lib/rack/test/utils.rb +37 -43
- data/lib/rack/test/version.rb +5 -0
- data/lib/rack/test.rb +86 -85
- metadata +139 -60
- data/.document +0 -4
- data/.gitignore +0 -6
- data/Gemfile +0 -8
- data/Gemfile.lock +0 -41
- data/History.txt +0 -179
- data/README.rdoc +0 -85
- data/Rakefile +0 -33
- data/Thorfile +0 -114
- data/rack-test.gemspec +0 -77
- data/spec/fixtures/bar.txt +0 -1
- data/spec/fixtures/config.ru +0 -3
- data/spec/fixtures/fake_app.rb +0 -143
- data/spec/fixtures/foo.txt +0 -1
- data/spec/rack/test/cookie_spec.rb +0 -219
- data/spec/rack/test/digest_auth_spec.rb +0 -46
- data/spec/rack/test/multipart_spec.rb +0 -145
- data/spec/rack/test/uploaded_file_spec.rb +0 -24
- data/spec/rack/test/utils_spec.rb +0 -193
- data/spec/rack/test_spec.rb +0 -550
- data/spec/spec_helper.rb +0 -69
- data/spec/support/matchers/body.rb +0 -9
- data/spec/support/matchers/challenge.rb +0 -11
@@ -1,16 +1,15 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require 'fileutils'
|
2
|
+
require 'pathname'
|
3
|
+
require 'tempfile'
|
3
4
|
|
4
5
|
module Rack
|
5
6
|
module Test
|
6
|
-
|
7
7
|
# Wraps a Tempfile with a content type. Including one or more UploadedFile's
|
8
8
|
# in the params causes Rack::Test to build and issue a multipart request.
|
9
9
|
#
|
10
10
|
# Example:
|
11
11
|
# post "/photos", "file" => Rack::Test::UploadedFile.new("me.jpg", "image/jpeg")
|
12
12
|
class UploadedFile
|
13
|
-
|
14
13
|
# The filename, *not* including the path, of the "uploaded" file
|
15
14
|
attr_reader :original_filename
|
16
15
|
|
@@ -20,34 +19,66 @@ module Rack
|
|
20
19
|
# The content type of the "uploaded" file
|
21
20
|
attr_accessor :content_type
|
22
21
|
|
23
|
-
|
24
|
-
|
25
|
-
|
22
|
+
# Creates a new UploadedFile instance.
|
23
|
+
#
|
24
|
+
# @param content [IO, Pathname, String, StringIO] a path to a file, or an {IO} or {StringIO} object representing the
|
25
|
+
# file.
|
26
|
+
# @param content_type [String]
|
27
|
+
# @param binary [Boolean] an optional flag that indicates whether the file should be open in binary mode or not.
|
28
|
+
# @param original_filename [String] an optional parameter that provides the original filename if `content` is a StringIO
|
29
|
+
# object. Not used for other kind of `content` objects.
|
30
|
+
def initialize(content, content_type = 'text/plain', binary = false, original_filename: nil)
|
31
|
+
if original_filename
|
32
|
+
initialize_from_stringio(content, original_filename)
|
33
|
+
else
|
34
|
+
initialize_from_file_path(content)
|
35
|
+
end
|
26
36
|
@content_type = content_type
|
27
|
-
@original_filename = ::File.basename(path)
|
28
|
-
|
29
|
-
@tempfile = Tempfile.new(@original_filename)
|
30
|
-
@tempfile.set_encoding(Encoding::BINARY) if @tempfile.respond_to?(:set_encoding)
|
31
37
|
@tempfile.binmode if binary
|
32
|
-
|
33
|
-
FileUtils.copy_file(path, @tempfile.path)
|
34
38
|
end
|
35
39
|
|
36
40
|
def path
|
37
|
-
|
41
|
+
tempfile.path
|
38
42
|
end
|
39
43
|
|
40
|
-
|
44
|
+
alias local_path path
|
41
45
|
|
42
46
|
def method_missing(method_name, *args, &block) #:nodoc:
|
43
|
-
|
47
|
+
tempfile.public_send(method_name, *args, &block)
|
44
48
|
end
|
45
49
|
|
46
|
-
def
|
47
|
-
|
50
|
+
def respond_to_missing?(method_name, include_private = false) #:nodoc:
|
51
|
+
tempfile.respond_to?(method_name, include_private) || super
|
48
52
|
end
|
49
53
|
|
50
|
-
|
54
|
+
def self.finalize(file)
|
55
|
+
proc { actually_finalize file }
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.actually_finalize(file)
|
59
|
+
file.close
|
60
|
+
file.unlink
|
61
|
+
end
|
51
62
|
|
63
|
+
private
|
64
|
+
|
65
|
+
def initialize_from_stringio(stringio, original_filename)
|
66
|
+
@tempfile = stringio
|
67
|
+
@original_filename = original_filename || raise(ArgumentError, 'Missing `original_filename` for StringIO object')
|
68
|
+
end
|
69
|
+
|
70
|
+
def initialize_from_file_path(path)
|
71
|
+
raise "#{path} file does not exist" unless ::File.exist?(path)
|
72
|
+
|
73
|
+
@original_filename = ::File.basename(path)
|
74
|
+
|
75
|
+
@tempfile = Tempfile.new([@original_filename, ::File.extname(path)])
|
76
|
+
@tempfile.set_encoding(Encoding::BINARY) if @tempfile.respond_to?(:set_encoding)
|
77
|
+
|
78
|
+
ObjectSpace.define_finalizer(self, self.class.finalize(@tempfile))
|
79
|
+
|
80
|
+
FileUtils.copy_file(path, @tempfile.path)
|
81
|
+
end
|
82
|
+
end
|
52
83
|
end
|
53
84
|
end
|
data/lib/rack/test/utils.rb
CHANGED
@@ -1,38 +1,36 @@
|
|
1
1
|
module Rack
|
2
2
|
module Test
|
3
|
-
|
4
3
|
module Utils # :nodoc:
|
5
4
|
include Rack::Utils
|
5
|
+
extend Rack::Utils
|
6
6
|
|
7
7
|
def build_nested_query(value, prefix = nil)
|
8
8
|
case value
|
9
9
|
when Array
|
10
|
-
value.
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
10
|
+
if value.empty?
|
11
|
+
"#{prefix}[]="
|
12
|
+
else
|
13
|
+
value.map do |v|
|
14
|
+
prefix = "#{prefix}[]" unless unescape(prefix) =~ /\[\]$/
|
15
|
+
build_nested_query(v, prefix.to_s)
|
16
|
+
end.join('&')
|
17
|
+
end
|
16
18
|
when Hash
|
17
19
|
value.map do |k, v|
|
18
20
|
build_nested_query(v, prefix ? "#{prefix}[#{escape(k)}]" : escape(k))
|
19
|
-
end.join(
|
21
|
+
end.join('&')
|
20
22
|
when NilClass
|
21
23
|
prefix.to_s
|
22
24
|
else
|
23
25
|
"#{prefix}=#{escape(value)}"
|
24
26
|
end
|
25
27
|
end
|
26
|
-
|
27
28
|
module_function :build_nested_query
|
28
29
|
|
29
|
-
def build_multipart(params, first = true)
|
30
|
+
def build_multipart(params, first = true, multipart = false)
|
30
31
|
if first
|
31
|
-
unless params.is_a?(Hash)
|
32
|
-
raise ArgumentError, "value must be a Hash"
|
33
|
-
end
|
32
|
+
raise ArgumentError, 'value must be a Hash' unless params.is_a?(Hash)
|
34
33
|
|
35
|
-
multipart = false
|
36
34
|
query = lambda { |value|
|
37
35
|
case value
|
38
36
|
when Array
|
@@ -47,7 +45,7 @@ module Rack
|
|
47
45
|
return nil unless multipart
|
48
46
|
end
|
49
47
|
|
50
|
-
flattened_params =
|
48
|
+
flattened_params = {}
|
51
49
|
|
52
50
|
params.each do |key, value|
|
53
51
|
k = first ? key.to_s : "[#{key}]"
|
@@ -55,23 +53,21 @@ module Rack
|
|
55
53
|
case value
|
56
54
|
when Array
|
57
55
|
value.map do |v|
|
58
|
-
|
59
|
-
if (v.is_a?(Hash))
|
56
|
+
if v.is_a?(Hash)
|
60
57
|
nested_params = {}
|
61
|
-
build_multipart(v, false).each
|
58
|
+
build_multipart(v, false).each do |subkey, subvalue|
|
62
59
|
nested_params[subkey] = subvalue
|
63
|
-
|
60
|
+
end
|
64
61
|
flattened_params["#{k}[]"] ||= []
|
65
62
|
flattened_params["#{k}[]"] << nested_params
|
66
63
|
else
|
67
64
|
flattened_params["#{k}[]"] = value
|
68
65
|
end
|
69
|
-
|
70
66
|
end
|
71
67
|
when Hash
|
72
|
-
build_multipart(value, false).each
|
68
|
+
build_multipart(value, false).each do |subkey, subvalue|
|
73
69
|
flattened_params[k + subkey] = subvalue
|
74
|
-
|
70
|
+
end
|
75
71
|
else
|
76
72
|
flattened_params[k] = value
|
77
73
|
end
|
@@ -83,27 +79,28 @@ module Rack
|
|
83
79
|
flattened_params
|
84
80
|
end
|
85
81
|
end
|
86
|
-
|
87
82
|
module_function :build_multipart
|
88
83
|
|
89
|
-
|
84
|
+
private
|
85
|
+
|
90
86
|
def build_parts(parameters)
|
91
87
|
get_parts(parameters).join + "--#{MULTIPART_BOUNDARY}--\r"
|
92
88
|
end
|
89
|
+
module_function :build_parts
|
93
90
|
|
94
91
|
def get_parts(parameters)
|
95
|
-
parameters.map
|
96
|
-
if name =~ /\[\]\Z/ && value.is_a?(Array) && value.all? {|v| v.is_a?(Hash)}
|
97
|
-
value.map
|
92
|
+
parameters.map do |name, value|
|
93
|
+
if name =~ /\[\]\Z/ && value.is_a?(Array) && value.all? { |v| v.is_a?(Hash) }
|
94
|
+
value.map do |hash|
|
98
95
|
new_value = {}
|
99
|
-
hash.each { |k, v| new_value[name+k] = v }
|
96
|
+
hash.each { |k, v| new_value[name + k] = v }
|
100
97
|
get_parts(new_value).join
|
101
|
-
|
98
|
+
end.join
|
102
99
|
else
|
103
100
|
if value.respond_to?(:original_filename)
|
104
101
|
build_file_part(name, value)
|
105
102
|
|
106
|
-
elsif value.is_a?(Array)
|
103
|
+
elsif value.is_a?(Array) && value.all? { |v| v.respond_to?(:original_filename) }
|
107
104
|
value.map do |v|
|
108
105
|
build_file_part(name, v)
|
109
106
|
end.join
|
@@ -113,15 +110,14 @@ module Rack
|
|
113
110
|
Rack::Test.encoding_aware_strings? ? primitive_part.force_encoding('BINARY') : primitive_part
|
114
111
|
end
|
115
112
|
end
|
116
|
-
|
113
|
+
end
|
117
114
|
end
|
115
|
+
module_function :get_parts
|
118
116
|
|
119
117
|
def build_primitive_part(parameter_name, value)
|
120
|
-
unless value.is_a? Array
|
121
|
-
value = [value]
|
122
|
-
end
|
118
|
+
value = [value] unless value.is_a? Array
|
123
119
|
value.map do |v|
|
124
|
-
<<-EOF
|
120
|
+
<<-EOF
|
125
121
|
--#{MULTIPART_BOUNDARY}\r
|
126
122
|
Content-Disposition: form-data; name="#{parameter_name}"\r
|
127
123
|
\r
|
@@ -129,22 +125,20 @@ Content-Disposition: form-data; name="#{parameter_name}"\r
|
|
129
125
|
EOF
|
130
126
|
end.join
|
131
127
|
end
|
128
|
+
module_function :build_primitive_part
|
132
129
|
|
133
130
|
def build_file_part(parameter_name, uploaded_file)
|
134
|
-
|
135
|
-
|
136
|
-
<<-EOF
|
131
|
+
uploaded_file.set_encoding(Encoding::BINARY) if uploaded_file.respond_to?(:set_encoding)
|
132
|
+
<<-EOF
|
137
133
|
--#{MULTIPART_BOUNDARY}\r
|
138
134
|
Content-Disposition: form-data; name="#{parameter_name}"; filename="#{escape(uploaded_file.original_filename)}"\r
|
139
135
|
Content-Type: #{uploaded_file.content_type}\r
|
140
|
-
Content-Length: #{
|
136
|
+
Content-Length: #{uploaded_file.size}\r
|
141
137
|
\r
|
142
|
-
#{
|
138
|
+
#{uploaded_file.read}\r
|
143
139
|
EOF
|
144
|
-
end
|
145
140
|
end
|
146
|
-
|
141
|
+
module_function :build_file_part
|
147
142
|
end
|
148
|
-
|
149
143
|
end
|
150
144
|
end
|
data/lib/rack/test.rb
CHANGED
@@ -1,18 +1,17 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
1
|
+
require 'uri'
|
2
|
+
require 'rack'
|
3
|
+
require 'rack/mock_session'
|
4
|
+
require 'rack/test/cookie_jar'
|
5
|
+
require 'rack/test/mock_digest_request'
|
6
|
+
require 'rack/test/utils'
|
7
|
+
require 'rack/test/methods'
|
8
|
+
require 'rack/test/uploaded_file'
|
9
|
+
require 'rack/test/version'
|
9
10
|
|
10
11
|
module Rack
|
11
12
|
module Test
|
12
|
-
|
13
|
-
|
14
|
-
DEFAULT_HOST = "example.org"
|
15
|
-
MULTIPART_BOUNDARY = "----------XnJLe9ZIbbGUYtzPQJ16u1"
|
13
|
+
DEFAULT_HOST = 'example.org'.freeze
|
14
|
+
MULTIPART_BOUNDARY = '----------XnJLe9ZIbbGUYtzPQJ16u1'.freeze
|
16
15
|
|
17
16
|
# The common base class for exceptions raised by Rack::Test
|
18
17
|
class Error < StandardError; end
|
@@ -36,11 +35,13 @@ module Rack
|
|
36
35
|
def initialize(mock_session)
|
37
36
|
@headers = {}
|
38
37
|
@env = {}
|
38
|
+
@digest_username = nil
|
39
|
+
@digest_password = nil
|
39
40
|
|
40
|
-
if mock_session.is_a?(MockSession)
|
41
|
-
|
41
|
+
@rack_mock_session = if mock_session.is_a?(MockSession)
|
42
|
+
mock_session
|
42
43
|
else
|
43
|
-
|
44
|
+
MockSession.new(mock_session)
|
44
45
|
end
|
45
46
|
|
46
47
|
@default_host = @rack_mock_session.default_host
|
@@ -54,8 +55,7 @@ module Rack
|
|
54
55
|
# Example:
|
55
56
|
# get "/"
|
56
57
|
def get(uri, params = {}, env = {}, &block)
|
57
|
-
|
58
|
-
process_request(uri, env, &block)
|
58
|
+
custom_request('GET', uri, params, env, &block)
|
59
59
|
end
|
60
60
|
|
61
61
|
# Issue a POST request for the given URI. See #get
|
@@ -63,8 +63,7 @@ module Rack
|
|
63
63
|
# Example:
|
64
64
|
# post "/signup", "name" => "Bryan"
|
65
65
|
def post(uri, params = {}, env = {}, &block)
|
66
|
-
|
67
|
-
process_request(uri, env, &block)
|
66
|
+
custom_request('POST', uri, params, env, &block)
|
68
67
|
end
|
69
68
|
|
70
69
|
# Issue a PUT request for the given URI. See #get
|
@@ -72,8 +71,7 @@ module Rack
|
|
72
71
|
# Example:
|
73
72
|
# put "/"
|
74
73
|
def put(uri, params = {}, env = {}, &block)
|
75
|
-
|
76
|
-
process_request(uri, env, &block)
|
74
|
+
custom_request('PUT', uri, params, env, &block)
|
77
75
|
end
|
78
76
|
|
79
77
|
# Issue a PATCH request for the given URI. See #get
|
@@ -81,8 +79,7 @@ module Rack
|
|
81
79
|
# Example:
|
82
80
|
# patch "/"
|
83
81
|
def patch(uri, params = {}, env = {}, &block)
|
84
|
-
|
85
|
-
process_request(uri, env, &block)
|
82
|
+
custom_request('PATCH', uri, params, env, &block)
|
86
83
|
end
|
87
84
|
|
88
85
|
# Issue a DELETE request for the given URI. See #get
|
@@ -90,8 +87,7 @@ module Rack
|
|
90
87
|
# Example:
|
91
88
|
# delete "/"
|
92
89
|
def delete(uri, params = {}, env = {}, &block)
|
93
|
-
|
94
|
-
process_request(uri, env, &block)
|
90
|
+
custom_request('DELETE', uri, params, env, &block)
|
95
91
|
end
|
96
92
|
|
97
93
|
# Issue an OPTIONS request for the given URI. See #get
|
@@ -99,8 +95,7 @@ module Rack
|
|
99
95
|
# Example:
|
100
96
|
# options "/"
|
101
97
|
def options(uri, params = {}, env = {}, &block)
|
102
|
-
|
103
|
-
process_request(uri, env, &block)
|
98
|
+
custom_request('OPTIONS', uri, params, env, &block)
|
104
99
|
end
|
105
100
|
|
106
101
|
# Issue a HEAD request for the given URI. See #get
|
@@ -108,8 +103,7 @@ module Rack
|
|
108
103
|
# Example:
|
109
104
|
# head "/"
|
110
105
|
def head(uri, params = {}, env = {}, &block)
|
111
|
-
|
112
|
-
process_request(uri, env, &block)
|
106
|
+
custom_request('HEAD', uri, params, env, &block)
|
113
107
|
end
|
114
108
|
|
115
109
|
# Issue a request to the Rack app for the given URI and optional Rack
|
@@ -120,10 +114,21 @@ module Rack
|
|
120
114
|
# Example:
|
121
115
|
# request "/"
|
122
116
|
def request(uri, env = {}, &block)
|
117
|
+
uri = parse_uri(uri, env)
|
123
118
|
env = env_for(uri, env)
|
124
119
|
process_request(uri, env, &block)
|
125
120
|
end
|
126
121
|
|
122
|
+
# Issue a request using the given verb for the given URI. See #get
|
123
|
+
#
|
124
|
+
# Example:
|
125
|
+
# custom_request "LINK", "/"
|
126
|
+
def custom_request(verb, uri, params = {}, env = {}, &block)
|
127
|
+
uri = parse_uri(uri, env)
|
128
|
+
env = env_for(uri, env.merge(method: verb.to_s.upcase, params: params))
|
129
|
+
process_request(uri, env, &block)
|
130
|
+
end
|
131
|
+
|
127
132
|
# Set a header to be included on all subsequent requests through the
|
128
133
|
# session. Use a value of nil to remove a previously configured header.
|
129
134
|
#
|
@@ -159,11 +164,11 @@ module Rack
|
|
159
164
|
# Example:
|
160
165
|
# basic_authorize "bryan", "secret"
|
161
166
|
def basic_authorize(username, password)
|
162
|
-
encoded_login = ["#{username}:#{password}"].pack(
|
167
|
+
encoded_login = ["#{username}:#{password}"].pack('m0')
|
163
168
|
header('Authorization', "Basic #{encoded_login}")
|
164
169
|
end
|
165
170
|
|
166
|
-
|
171
|
+
alias authorize basic_authorize
|
167
172
|
|
168
173
|
# Set the username and password for HTTP Digest authorization, to be
|
169
174
|
# included in subsequent requests in the HTTP_AUTHORIZATION header.
|
@@ -181,73 +186,73 @@ module Rack
|
|
181
186
|
# a redirect, an error will be raised.
|
182
187
|
def follow_redirect!
|
183
188
|
unless last_response.redirect?
|
184
|
-
raise Error
|
189
|
+
raise Error, 'Last response was not a redirect. Cannot follow_redirect!'
|
190
|
+
end
|
191
|
+
if last_response.status == 307
|
192
|
+
send(last_request.request_method.downcase.to_sym, last_response['Location'], last_request.params, 'HTTP_REFERER' => last_request.url)
|
193
|
+
else
|
194
|
+
get(last_response['Location'], {}, 'HTTP_REFERER' => last_request.url)
|
185
195
|
end
|
186
|
-
|
187
|
-
get(last_response["Location"], {}, { "HTTP_REFERER" => last_request.url })
|
188
196
|
end
|
189
197
|
|
190
|
-
|
198
|
+
private
|
191
199
|
|
192
|
-
def
|
193
|
-
|
194
|
-
|
195
|
-
|
200
|
+
def parse_uri(path, env)
|
201
|
+
URI.parse(path).tap do |uri|
|
202
|
+
uri.path = "/#{uri.path}" unless uri.path[0] == '/'
|
203
|
+
uri.host ||= @default_host
|
204
|
+
uri.scheme ||= 'https' if env['HTTPS'] == 'on'
|
205
|
+
end
|
206
|
+
end
|
196
207
|
|
208
|
+
def env_for(uri, env)
|
197
209
|
env = default_env.merge(env)
|
198
210
|
|
199
|
-
env[
|
211
|
+
env['HTTP_HOST'] ||= [uri.host, (uri.port if uri.port != uri.default_port)].compact.join(':')
|
200
212
|
|
201
|
-
env.update(
|
202
|
-
env[
|
213
|
+
env.update('HTTPS' => 'on') if URI::HTTPS === uri
|
214
|
+
env['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest' if env[:xhr]
|
203
215
|
|
204
216
|
# TODO: Remove this after Rack 1.1 has been released.
|
205
217
|
# Stringifying and upcasing methods has be commit upstream
|
206
|
-
env[
|
218
|
+
env['REQUEST_METHOD'] ||= env[:method] ? env[:method].to_s.upcase : 'GET'
|
219
|
+
|
220
|
+
params = env.delete(:params) do {} end
|
207
221
|
|
208
|
-
if env[
|
222
|
+
if env['REQUEST_METHOD'] == 'GET'
|
209
223
|
# merge :params with the query string
|
210
|
-
if params
|
224
|
+
if params
|
211
225
|
params = parse_nested_query(params) if params.is_a?(String)
|
212
|
-
|
213
|
-
uri.query = build_nested_query(params)
|
226
|
+
|
227
|
+
uri.query = [uri.query, build_nested_query(params)].compact.reject { |v| v == '' }.join('&')
|
214
228
|
end
|
215
|
-
elsif !env.
|
216
|
-
env[
|
229
|
+
elsif !env.key?(:input)
|
230
|
+
env['CONTENT_TYPE'] ||= 'application/x-www-form-urlencoded' unless params.nil?
|
217
231
|
|
218
|
-
if
|
219
|
-
if data = build_multipart(
|
232
|
+
if params.is_a?(Hash)
|
233
|
+
if data = build_multipart(params)
|
220
234
|
env[:input] = data
|
221
|
-
env[
|
222
|
-
env[
|
235
|
+
env['CONTENT_LENGTH'] ||= data.length.to_s
|
236
|
+
env['CONTENT_TYPE'] = "multipart/form-data; boundary=#{MULTIPART_BOUNDARY}"
|
223
237
|
else
|
224
|
-
env[:input] = params_to_string(
|
238
|
+
env[:input] = params_to_string(params)
|
225
239
|
end
|
226
240
|
else
|
227
|
-
env[:input] =
|
241
|
+
env[:input] = params
|
228
242
|
end
|
229
243
|
end
|
230
244
|
|
231
|
-
env.delete(:
|
232
|
-
|
233
|
-
if env.has_key?(:cookie)
|
234
|
-
set_cookie(env.delete(:cookie), uri)
|
235
|
-
end
|
245
|
+
set_cookie(env.delete(:cookie), uri) if env.key?(:cookie)
|
236
246
|
|
237
247
|
Rack::MockRequest.env_for(uri.to_s, env)
|
238
248
|
end
|
239
249
|
|
240
250
|
def process_request(uri, env)
|
241
|
-
uri = URI.parse(uri)
|
242
|
-
uri.host ||= @default_host
|
243
|
-
|
244
251
|
@rack_mock_session.request(uri, env)
|
245
252
|
|
246
253
|
if retry_with_digest_auth?(env)
|
247
|
-
auth_env = env.merge(
|
248
|
-
|
249
|
-
"rack-test.digest_auth_retry" => true
|
250
|
-
})
|
254
|
+
auth_env = env.merge('HTTP_AUTHORIZATION' => digest_auth_header,
|
255
|
+
'rack-test.digest_auth_retry' => true)
|
251
256
|
auth_env.delete('rack.request')
|
252
257
|
process_request(uri.path, auth_env)
|
253
258
|
else
|
@@ -258,26 +263,24 @@ module Rack
|
|
258
263
|
end
|
259
264
|
|
260
265
|
def digest_auth_header
|
261
|
-
challenge = last_response[
|
266
|
+
challenge = last_response['WWW-Authenticate'].split(' ', 2).last
|
262
267
|
params = Rack::Auth::Digest::Params.parse(challenge)
|
263
268
|
|
264
|
-
params.merge!(
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
"method" => last_request.env["REQUEST_METHOD"],
|
270
|
-
})
|
269
|
+
params.merge!('username' => @digest_username,
|
270
|
+
'nc' => '00000001',
|
271
|
+
'cnonce' => 'nonsensenonce',
|
272
|
+
'uri' => last_request.fullpath,
|
273
|
+
'method' => last_request.env['REQUEST_METHOD'])
|
271
274
|
|
272
|
-
params[
|
275
|
+
params['response'] = MockDigestRequest.new(params).response(@digest_password)
|
273
276
|
|
274
277
|
"Digest #{params}"
|
275
278
|
end
|
276
279
|
|
277
280
|
def retry_with_digest_auth?(env)
|
278
281
|
last_response.status == 401 &&
|
279
|
-
|
280
|
-
|
282
|
+
digest_auth_configured? &&
|
283
|
+
!env['rack-test.digest_auth_retry']
|
281
284
|
end
|
282
285
|
|
283
286
|
def digest_auth_configured?
|
@@ -285,15 +288,15 @@ module Rack
|
|
285
288
|
end
|
286
289
|
|
287
290
|
def default_env
|
288
|
-
{
|
291
|
+
{ 'rack.test' => true, 'REMOTE_ADDR' => '127.0.0.1' }.merge(@env).merge(headers_for_env)
|
289
292
|
end
|
290
293
|
|
291
294
|
def headers_for_env
|
292
295
|
converted_headers = {}
|
293
296
|
|
294
297
|
@headers.each do |name, value|
|
295
|
-
env_key = name.upcase.
|
296
|
-
env_key =
|
298
|
+
env_key = name.upcase.tr('-', '_')
|
299
|
+
env_key = 'HTTP_' + env_key unless env_key == 'CONTENT_TYPE'
|
297
300
|
converted_headers[env_key] = value
|
298
301
|
end
|
299
302
|
|
@@ -303,16 +306,14 @@ module Rack
|
|
303
306
|
def params_to_string(params)
|
304
307
|
case params
|
305
308
|
when Hash then build_nested_query(params)
|
306
|
-
when nil then
|
309
|
+
when nil then ''
|
307
310
|
else params
|
308
311
|
end
|
309
312
|
end
|
310
|
-
|
311
313
|
end
|
312
314
|
|
313
315
|
def self.encoding_aware_strings?
|
314
|
-
defined?(Encoding) &&
|
316
|
+
defined?(Encoding) && ''.respond_to?(:encode)
|
315
317
|
end
|
316
|
-
|
317
318
|
end
|
318
319
|
end
|