rack 1.6.13 → 2.0.9.3
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of rack might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/COPYING +1 -1
- data/HISTORY.md +153 -8
- data/README.rdoc +35 -31
- data/Rakefile +6 -14
- data/SPEC +10 -11
- data/contrib/rack_logo.svg +164 -111
- data/example/protectedlobster.rb +1 -1
- data/example/protectedlobster.ru +1 -1
- data/lib/rack/auth/abstract/request.rb +5 -1
- data/lib/rack/auth/digest/params.rb +2 -3
- data/lib/rack/auth/digest/request.rb +1 -1
- data/lib/rack/body_proxy.rb +14 -9
- data/lib/rack/builder.rb +3 -3
- data/lib/rack/chunked.rb +5 -5
- data/lib/rack/{commonlogger.rb → common_logger.rb} +6 -3
- data/lib/rack/content_length.rb +2 -2
- data/lib/rack/deflater.rb +4 -39
- data/lib/rack/directory.rb +66 -54
- data/lib/rack/etag.rb +5 -4
- data/lib/rack/events.rb +154 -0
- data/lib/rack/file.rb +64 -40
- data/lib/rack/handler/cgi.rb +15 -16
- data/lib/rack/handler/fastcgi.rb +13 -14
- data/lib/rack/handler/lsws.rb +11 -11
- data/lib/rack/handler/scgi.rb +15 -15
- data/lib/rack/handler/thin.rb +3 -0
- data/lib/rack/handler/webrick.rb +24 -26
- data/lib/rack/handler.rb +3 -25
- data/lib/rack/head.rb +15 -17
- data/lib/rack/lint.rb +41 -41
- data/lib/rack/lobster.rb +1 -1
- data/lib/rack/lock.rb +15 -10
- data/lib/rack/logger.rb +2 -2
- data/lib/rack/media_type.rb +38 -0
- data/lib/rack/{methodoverride.rb → method_override.rb} +6 -6
- data/lib/rack/mime.rb +18 -5
- data/lib/rack/mock.rb +36 -54
- data/lib/rack/multipart/generator.rb +5 -5
- data/lib/rack/multipart/parser.rb +283 -157
- data/lib/rack/multipart/uploaded_file.rb +1 -2
- data/lib/rack/multipart.rb +36 -8
- data/lib/rack/{nulllogger.rb → null_logger.rb} +1 -1
- data/lib/rack/query_parser.rb +192 -0
- data/lib/rack/recursive.rb +8 -8
- data/lib/rack/request.rb +394 -305
- data/lib/rack/response.rb +130 -57
- data/lib/rack/rewindable_input.rb +1 -12
- data/lib/rack/runtime.rb +10 -18
- data/lib/rack/sendfile.rb +5 -7
- data/lib/rack/server.rb +30 -23
- data/lib/rack/session/abstract/id.rb +110 -75
- data/lib/rack/session/cookie.rb +24 -17
- data/lib/rack/session/memcache.rb +9 -9
- data/lib/rack/session/pool.rb +8 -8
- data/lib/rack/show_exceptions.rb +386 -0
- data/lib/rack/{showstatus.rb → show_status.rb} +3 -3
- data/lib/rack/static.rb +30 -5
- data/lib/rack/tempfile_reaper.rb +2 -2
- data/lib/rack/urlmap.rb +15 -14
- data/lib/rack/utils.rb +156 -217
- data/lib/rack.rb +70 -21
- data/rack.gemspec +10 -9
- data/test/builder/an_underscore_app.rb +5 -0
- data/test/builder/options.ru +1 -1
- data/test/cgi/test.fcgi +1 -0
- data/test/cgi/test.gz +0 -0
- data/test/helper.rb +34 -0
- data/test/multipart/filename_with_encoded_words +7 -0
- data/test/multipart/filename_with_escaped_quotes_and_modification_param +1 -1
- data/test/multipart/filename_with_single_quote +7 -0
- data/test/multipart/quoted +15 -0
- data/test/multipart/rack-logo.png +0 -0
- data/test/multipart/unity3d_wwwform +11 -0
- data/test/registering_handler/rack/handler/registering_myself.rb +1 -1
- data/test/spec_auth_basic.rb +27 -19
- data/test/spec_auth_digest.rb +47 -46
- data/test/spec_body_proxy.rb +27 -27
- data/test/spec_builder.rb +51 -41
- data/test/spec_cascade.rb +24 -22
- data/test/spec_cgi.rb +49 -67
- data/test/spec_chunked.rb +37 -35
- data/test/{spec_commonlogger.rb → spec_common_logger.rb} +35 -21
- data/test/{spec_conditionalget.rb → spec_conditional_get.rb} +29 -28
- data/test/spec_config.rb +3 -2
- data/test/spec_content_length.rb +18 -17
- data/test/spec_content_type.rb +13 -12
- data/test/spec_deflater.rb +85 -49
- data/test/spec_directory.rb +87 -27
- data/test/spec_etag.rb +32 -31
- data/test/spec_events.rb +133 -0
- data/test/spec_fastcgi.rb +50 -72
- data/test/spec_file.rb +120 -77
- data/test/spec_handler.rb +19 -34
- data/test/spec_head.rb +15 -14
- data/test/spec_lint.rb +169 -199
- data/test/spec_lobster.rb +24 -23
- data/test/spec_lock.rb +79 -39
- data/test/spec_logger.rb +4 -3
- data/test/spec_media_type.rb +42 -0
- data/test/{spec_methodoverride.rb → spec_method_override.rb} +34 -35
- data/test/spec_mime.rb +19 -19
- data/test/spec_mock.rb +206 -144
- data/test/spec_multipart.rb +329 -208
- data/test/{spec_nulllogger.rb → spec_null_logger.rb} +5 -4
- data/test/spec_recursive.rb +17 -14
- data/test/spec_request.rb +796 -605
- data/test/spec_response.rb +233 -112
- data/test/spec_rewindable_input.rb +50 -40
- data/test/spec_runtime.rb +11 -10
- data/test/spec_sendfile.rb +30 -35
- data/test/spec_server.rb +78 -52
- data/test/spec_session_abstract_id.rb +11 -33
- data/test/spec_session_abstract_session_hash.rb +45 -0
- data/test/spec_session_cookie.rb +99 -67
- data/test/spec_session_memcache.rb +67 -68
- data/test/spec_session_pool.rb +52 -51
- data/test/{spec_showexceptions.rb → spec_show_exceptions.rb} +23 -28
- data/test/{spec_showstatus.rb → spec_show_status.rb} +36 -35
- data/test/spec_static.rb +71 -32
- data/test/spec_tempfile_reaper.rb +11 -10
- data/test/spec_thin.rb +55 -50
- data/test/spec_urlmap.rb +79 -78
- data/test/spec_utils.rb +441 -346
- data/test/spec_version.rb +2 -8
- data/test/spec_webrick.rb +93 -71
- data/test/static/foo.html +1 -0
- data/test/testrequest.rb +1 -1
- data/test/unregistered_handler/rack/handler/unregistered.rb +1 -1
- data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +1 -1
- metadata +95 -74
- data/KNOWN-ISSUES +0 -44
- data/lib/rack/backports/uri/common_18.rb +0 -56
- data/lib/rack/backports/uri/common_192.rb +0 -52
- data/lib/rack/backports/uri/common_193.rb +0 -29
- data/lib/rack/handler/evented_mongrel.rb +0 -8
- data/lib/rack/handler/mongrel.rb +0 -106
- data/lib/rack/handler/swiftiplied_mongrel.rb +0 -8
- data/lib/rack/showexceptions.rb +0 -387
- data/lib/rack/utils/okjson.rb +0 -600
- data/test/spec_mongrel.rb +0 -182
- /data/lib/rack/{conditionalget.rb → conditional_get.rb} +0 -0
data/test/spec_request.rb
CHANGED
@@ -1,574 +1,724 @@
|
|
1
|
+
require 'minitest/autorun'
|
1
2
|
require 'stringio'
|
2
3
|
require 'cgi'
|
3
4
|
require 'rack/request'
|
4
5
|
require 'rack/mock'
|
6
|
+
require 'rack/multipart'
|
5
7
|
require 'securerandom'
|
6
8
|
|
7
|
-
|
8
|
-
|
9
|
-
req =
|
9
|
+
class RackRequestTest < Minitest::Spec
|
10
|
+
it "copies the env when duping" do
|
11
|
+
req = make_request(Rack::MockRequest.env_for("http://example.com:8080/"))
|
12
|
+
refute_same req.env, req.dup.env
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'can check if something has been set' do
|
16
|
+
req = make_request(Rack::MockRequest.env_for("http://example.com:8080/"))
|
17
|
+
refute req.has_header?("FOO")
|
18
|
+
end
|
19
|
+
|
20
|
+
it "can get a key from the env" do
|
21
|
+
req = make_request(Rack::MockRequest.env_for("http://example.com:8080/"))
|
22
|
+
assert_equal "example.com", req.get_header("SERVER_NAME")
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'can calculate the authority' do
|
26
|
+
req = make_request(Rack::MockRequest.env_for("http://example.com:8080/"))
|
27
|
+
assert_equal "example.com:8080", req.authority
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'can calculate the authority without a port' do
|
31
|
+
req = make_request(Rack::MockRequest.env_for("http://example.com/"))
|
32
|
+
assert_equal "example.com:80", req.authority
|
33
|
+
end
|
10
34
|
|
11
|
-
|
12
|
-
req.
|
13
|
-
|
35
|
+
it 'can calculate the authority without a port on ssl' do
|
36
|
+
req = make_request(Rack::MockRequest.env_for("https://example.com/"))
|
37
|
+
assert_equal "example.com:443", req.authority
|
38
|
+
end
|
14
39
|
|
15
|
-
|
16
|
-
req.
|
17
|
-
|
18
|
-
req.
|
19
|
-
|
20
|
-
|
40
|
+
it 'yields to the block if no value has been set' do
|
41
|
+
req = make_request(Rack::MockRequest.env_for("http://example.com:8080/"))
|
42
|
+
yielded = false
|
43
|
+
req.fetch_header("FOO") do
|
44
|
+
yielded = true
|
45
|
+
req.set_header "FOO", 'bar'
|
46
|
+
end
|
21
47
|
|
22
|
-
|
23
|
-
req.
|
24
|
-
|
48
|
+
assert yielded
|
49
|
+
assert_equal "bar", req.get_header("FOO")
|
50
|
+
end
|
25
51
|
|
26
|
-
|
27
|
-
req.
|
52
|
+
it 'can iterate over values' do
|
53
|
+
req = make_request(Rack::MockRequest.env_for("http://example.com:8080/"))
|
54
|
+
req.set_header 'foo', 'bar'
|
55
|
+
hash = {}
|
56
|
+
req.each_header do |k,v|
|
57
|
+
hash[k] = v
|
58
|
+
end
|
59
|
+
assert_equal 'bar', hash['foo']
|
60
|
+
end
|
28
61
|
|
29
|
-
|
30
|
-
req.
|
62
|
+
it 'can set values in the env' do
|
63
|
+
req = make_request(Rack::MockRequest.env_for("http://example.com:8080/"))
|
64
|
+
req.set_header("FOO", "BAR")
|
65
|
+
assert_equal "BAR", req.get_header("FOO")
|
31
66
|
end
|
32
67
|
|
33
|
-
|
34
|
-
req = Rack::
|
68
|
+
it 'can add to multivalued headers in the env' do
|
69
|
+
req = make_request(Rack::MockRequest.env_for('http://example.com:8080/'))
|
70
|
+
|
71
|
+
assert_equal '1', req.add_header('FOO', '1')
|
72
|
+
assert_equal '1', req.get_header('FOO')
|
73
|
+
|
74
|
+
assert_equal '1,2', req.add_header('FOO', '2')
|
75
|
+
assert_equal '1,2', req.get_header('FOO')
|
76
|
+
|
77
|
+
assert_equal '1,2', req.add_header('FOO', nil)
|
78
|
+
assert_equal '1,2', req.get_header('FOO')
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'can delete env values' do
|
82
|
+
req = make_request(Rack::MockRequest.env_for("http://example.com:8080/"))
|
83
|
+
req.set_header 'foo', 'bar'
|
84
|
+
assert req.has_header? 'foo'
|
85
|
+
req.delete_header 'foo'
|
86
|
+
refute req.has_header? 'foo'
|
87
|
+
end
|
88
|
+
|
89
|
+
it "wrap the rack variables" do
|
90
|
+
req = make_request(Rack::MockRequest.env_for("http://example.com:8080/"))
|
91
|
+
|
92
|
+
req.body.must_respond_to :gets
|
93
|
+
req.scheme.must_equal "http"
|
94
|
+
req.request_method.must_equal "GET"
|
95
|
+
|
96
|
+
req.must_be :get?
|
97
|
+
req.wont_be :post?
|
98
|
+
req.wont_be :put?
|
99
|
+
req.wont_be :delete?
|
100
|
+
req.wont_be :head?
|
101
|
+
req.wont_be :patch?
|
102
|
+
|
103
|
+
req.script_name.must_equal ""
|
104
|
+
req.path_info.must_equal "/"
|
105
|
+
req.query_string.must_equal ""
|
106
|
+
|
107
|
+
req.host.must_equal "example.com"
|
108
|
+
req.port.must_equal 8080
|
109
|
+
|
110
|
+
req.content_length.must_equal "0"
|
111
|
+
req.content_type.must_be_nil
|
112
|
+
end
|
113
|
+
|
114
|
+
it "figure out the correct host" do
|
115
|
+
req = make_request \
|
35
116
|
Rack::MockRequest.env_for("/", "HTTP_HOST" => "www2.example.org")
|
36
|
-
req.host.
|
117
|
+
req.host.must_equal "www2.example.org"
|
37
118
|
|
38
|
-
req =
|
119
|
+
req = make_request \
|
39
120
|
Rack::MockRequest.env_for("/", "SERVER_NAME" => "example.org", "SERVER_PORT" => "9292")
|
40
|
-
req.host.
|
121
|
+
req.host.must_equal "example.org"
|
41
122
|
|
42
|
-
req =
|
123
|
+
req = make_request \
|
43
124
|
Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org:9292")
|
44
|
-
req.host.
|
125
|
+
req.host.must_equal "example.org"
|
45
126
|
|
46
127
|
env = Rack::MockRequest.env_for("/", "SERVER_ADDR" => "192.168.1.1", "SERVER_PORT" => "9292")
|
47
128
|
env.delete("SERVER_NAME")
|
48
|
-
req =
|
49
|
-
req.host.
|
129
|
+
req = make_request(env)
|
130
|
+
req.host.must_equal "192.168.1.1"
|
50
131
|
|
51
132
|
env = Rack::MockRequest.env_for("/")
|
52
133
|
env.delete("SERVER_NAME")
|
53
|
-
req =
|
54
|
-
req.host.
|
134
|
+
req = make_request(env)
|
135
|
+
req.host.must_equal ""
|
55
136
|
end
|
56
137
|
|
57
|
-
|
58
|
-
req =
|
138
|
+
it "figure out the correct port" do
|
139
|
+
req = make_request \
|
59
140
|
Rack::MockRequest.env_for("/", "HTTP_HOST" => "www2.example.org")
|
60
|
-
req.port.
|
141
|
+
req.port.must_equal 80
|
61
142
|
|
62
|
-
req =
|
143
|
+
req = make_request \
|
63
144
|
Rack::MockRequest.env_for("/", "HTTP_HOST" => "www2.example.org:81")
|
64
|
-
req.port.
|
145
|
+
req.port.must_equal 81
|
65
146
|
|
66
|
-
req =
|
147
|
+
req = make_request \
|
67
148
|
Rack::MockRequest.env_for("/", "SERVER_NAME" => "example.org", "SERVER_PORT" => "9292")
|
68
|
-
req.port.
|
149
|
+
req.port.must_equal 9292
|
69
150
|
|
70
|
-
req =
|
151
|
+
req = make_request \
|
71
152
|
Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org:9292")
|
72
|
-
req.port.
|
153
|
+
req.port.must_equal 9292
|
73
154
|
|
74
|
-
req =
|
155
|
+
req = make_request \
|
75
156
|
Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org")
|
76
|
-
req.port.
|
157
|
+
req.port.must_equal 80
|
77
158
|
|
78
|
-
req =
|
159
|
+
req = make_request \
|
79
160
|
Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org", "HTTP_X_FORWARDED_SSL" => "on")
|
80
|
-
req.port.
|
161
|
+
req.port.must_equal 443
|
81
162
|
|
82
|
-
req =
|
163
|
+
req = make_request \
|
83
164
|
Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org", "HTTP_X_FORWARDED_PROTO" => "https")
|
84
|
-
req.port.
|
165
|
+
req.port.must_equal 443
|
85
166
|
|
86
|
-
req =
|
167
|
+
req = make_request \
|
87
168
|
Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org", "HTTP_X_FORWARDED_PORT" => "9393")
|
88
|
-
req.port.
|
169
|
+
req.port.must_equal 9393
|
89
170
|
|
90
|
-
req =
|
171
|
+
req = make_request \
|
91
172
|
Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org:9393", "SERVER_PORT" => "80")
|
92
|
-
req.port.
|
173
|
+
req.port.must_equal 9393
|
93
174
|
|
94
|
-
req =
|
175
|
+
req = make_request \
|
95
176
|
Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org", "SERVER_PORT" => "9393")
|
96
|
-
req.port.
|
177
|
+
req.port.must_equal 80
|
97
178
|
|
98
|
-
req =
|
179
|
+
req = make_request \
|
99
180
|
Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost", "HTTP_X_FORWARDED_PROTO" => "https", "SERVER_PORT" => "80")
|
100
|
-
req.port.
|
181
|
+
req.port.must_equal 443
|
101
182
|
|
102
|
-
req =
|
183
|
+
req = make_request \
|
103
184
|
Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost", "HTTP_X_FORWARDED_PROTO" => "https,https", "SERVER_PORT" => "80")
|
104
|
-
req.port.
|
185
|
+
req.port.must_equal 443
|
105
186
|
end
|
106
187
|
|
107
|
-
|
108
|
-
req =
|
188
|
+
it "figure out the correct host with port" do
|
189
|
+
req = make_request \
|
109
190
|
Rack::MockRequest.env_for("/", "HTTP_HOST" => "www2.example.org")
|
110
|
-
req.host_with_port.
|
191
|
+
req.host_with_port.must_equal "www2.example.org"
|
111
192
|
|
112
|
-
req =
|
193
|
+
req = make_request \
|
113
194
|
Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81")
|
114
|
-
req.host_with_port.
|
195
|
+
req.host_with_port.must_equal "localhost:81"
|
115
196
|
|
116
|
-
req =
|
197
|
+
req = make_request \
|
117
198
|
Rack::MockRequest.env_for("/", "SERVER_NAME" => "example.org", "SERVER_PORT" => "9292")
|
118
|
-
req.host_with_port.
|
199
|
+
req.host_with_port.must_equal "example.org:9292"
|
119
200
|
|
120
|
-
req =
|
201
|
+
req = make_request \
|
121
202
|
Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org:9292")
|
122
|
-
req.host_with_port.
|
203
|
+
req.host_with_port.must_equal "example.org:9292"
|
123
204
|
|
124
|
-
req =
|
205
|
+
req = make_request \
|
125
206
|
Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org", "SERVER_PORT" => "9393")
|
126
|
-
req.host_with_port.
|
207
|
+
req.host_with_port.must_equal "example.org"
|
127
208
|
end
|
128
209
|
|
129
|
-
|
130
|
-
req =
|
131
|
-
req.query_string.
|
132
|
-
req.GET.
|
133
|
-
req.POST.
|
134
|
-
req.params.
|
210
|
+
it "parse the query string" do
|
211
|
+
req = make_request(Rack::MockRequest.env_for("/?foo=bar&quux=bla"))
|
212
|
+
req.query_string.must_equal "foo=bar&quux=bla"
|
213
|
+
req.GET.must_equal "foo" => "bar", "quux" => "bla"
|
214
|
+
req.POST.must_be :empty?
|
215
|
+
req.params.must_equal "foo" => "bar", "quux" => "bla"
|
135
216
|
end
|
136
217
|
|
137
|
-
|
218
|
+
it "not truncate query strings containing semi-colons #543 only in POST" do
|
138
219
|
mr = Rack::MockRequest.env_for("/",
|
139
220
|
"REQUEST_METHOD" => 'POST',
|
140
221
|
:input => "foo=bar&quux=b;la")
|
141
|
-
req =
|
142
|
-
req.query_string.
|
143
|
-
req.GET.
|
144
|
-
req.POST.
|
145
|
-
req.params.
|
222
|
+
req = make_request mr
|
223
|
+
req.query_string.must_equal ""
|
224
|
+
req.GET.must_be :empty?
|
225
|
+
req.POST.must_equal "foo" => "bar", "quux" => "b;la"
|
226
|
+
req.params.must_equal req.GET.merge(req.POST)
|
227
|
+
end
|
228
|
+
|
229
|
+
it "should use the query_parser for query parsing" do
|
230
|
+
c = Class.new(Rack::QueryParser::Params) do
|
231
|
+
def initialize(*)
|
232
|
+
super
|
233
|
+
@params = Hash.new{|h,k| h[k.to_s] if k.is_a?(Symbol)}
|
234
|
+
end
|
235
|
+
end
|
236
|
+
parser = Rack::QueryParser.new(c, 65536, 100)
|
237
|
+
c = Class.new(Rack::Request) do
|
238
|
+
define_method(:query_parser) do
|
239
|
+
parser
|
240
|
+
end
|
241
|
+
end
|
242
|
+
req = c.new(Rack::MockRequest.env_for("/?foo=bar&quux=bla"))
|
243
|
+
req.GET[:foo].must_equal "bar"
|
244
|
+
req.GET[:quux].must_equal "bla"
|
245
|
+
req.params[:foo].must_equal "bar"
|
246
|
+
req.params[:quux].must_equal "bla"
|
146
247
|
end
|
147
248
|
|
148
|
-
|
149
|
-
req =
|
150
|
-
req.query_string.
|
151
|
-
req.GET.
|
152
|
-
req.POST.
|
153
|
-
req.params.
|
249
|
+
it "use semi-colons as separators for query strings in GET" do
|
250
|
+
req = make_request(Rack::MockRequest.env_for("/?foo=bar&quux=b;la;wun=duh"))
|
251
|
+
req.query_string.must_equal "foo=bar&quux=b;la;wun=duh"
|
252
|
+
req.GET.must_equal "foo" => "bar", "quux" => "b", "la" => nil, "wun" => "duh"
|
253
|
+
req.POST.must_be :empty?
|
254
|
+
req.params.must_equal "foo" => "bar", "quux" => "b", "la" => nil, "wun" => "duh"
|
154
255
|
end
|
155
256
|
|
156
|
-
|
257
|
+
it "limit the keys from the GET query string" do
|
157
258
|
env = Rack::MockRequest.env_for("/?foo=bar")
|
158
259
|
|
159
260
|
old, Rack::Utils.key_space_limit = Rack::Utils.key_space_limit, 1
|
160
261
|
begin
|
161
|
-
req =
|
162
|
-
lambda { req.GET }.
|
262
|
+
req = make_request(env)
|
263
|
+
lambda { req.GET }.must_raise RangeError
|
163
264
|
ensure
|
164
265
|
Rack::Utils.key_space_limit = old
|
165
266
|
end
|
166
267
|
end
|
167
268
|
|
168
|
-
|
269
|
+
it "limit the key size per nested params hash" do
|
169
270
|
nested_query = Rack::MockRequest.env_for("/?foo%5Bbar%5D%5Bbaz%5D%5Bqux%5D=1")
|
170
271
|
plain_query = Rack::MockRequest.env_for("/?foo_bar__baz__qux_=1")
|
171
272
|
|
172
273
|
old, Rack::Utils.key_space_limit = Rack::Utils.key_space_limit, 3
|
173
274
|
begin
|
174
|
-
|
175
|
-
|
275
|
+
exp = {"foo"=>{"bar"=>{"baz"=>{"qux"=>"1"}}}}
|
276
|
+
make_request(nested_query).GET.must_equal exp
|
277
|
+
lambda { make_request(plain_query).GET }.must_raise RangeError
|
176
278
|
ensure
|
177
279
|
Rack::Utils.key_space_limit = old
|
178
280
|
end
|
179
281
|
end
|
180
282
|
|
181
|
-
|
283
|
+
it "not unify GET and POST when calling params" do
|
182
284
|
mr = Rack::MockRequest.env_for("/?foo=quux",
|
183
285
|
"REQUEST_METHOD" => 'POST',
|
184
286
|
:input => "foo=bar&quux=bla"
|
185
287
|
)
|
186
|
-
req =
|
288
|
+
req = make_request mr
|
187
289
|
|
188
290
|
req.params
|
189
291
|
|
190
|
-
req.GET.
|
191
|
-
req.POST.
|
192
|
-
req.params.
|
292
|
+
req.GET.must_equal "foo" => "quux"
|
293
|
+
req.POST.must_equal "foo" => "bar", "quux" => "bla"
|
294
|
+
req.params.must_equal req.GET.merge(req.POST)
|
193
295
|
end
|
194
296
|
|
195
|
-
|
297
|
+
it "use the query_parser's params_class for multipart params" do
|
298
|
+
c = Class.new(Rack::QueryParser::Params) do
|
299
|
+
def initialize(*)
|
300
|
+
super
|
301
|
+
@params = Hash.new{|h,k| h[k.to_s] if k.is_a?(Symbol)}
|
302
|
+
end
|
303
|
+
end
|
304
|
+
parser = Rack::QueryParser.new(c, 65536, 100)
|
305
|
+
c = Class.new(Rack::Request) do
|
306
|
+
define_method(:query_parser) do
|
307
|
+
parser
|
308
|
+
end
|
309
|
+
end
|
310
|
+
mr = Rack::MockRequest.env_for("/?foo=quux",
|
311
|
+
"REQUEST_METHOD" => 'POST',
|
312
|
+
:input => "foo=bar&quux=bla"
|
313
|
+
)
|
314
|
+
req = c.new mr
|
315
|
+
|
316
|
+
req.params
|
317
|
+
|
318
|
+
req.GET[:foo].must_equal "quux"
|
319
|
+
req.POST[:foo].must_equal "bar"
|
320
|
+
req.POST[:quux].must_equal "bla"
|
321
|
+
req.params[:foo].must_equal "bar"
|
322
|
+
req.params[:quux].must_equal "bla"
|
323
|
+
end
|
324
|
+
|
325
|
+
it "raise if input params has invalid %-encoding" do
|
196
326
|
mr = Rack::MockRequest.env_for("/?foo=quux",
|
197
327
|
"REQUEST_METHOD" => 'POST',
|
198
328
|
:input => "a%=1"
|
199
329
|
)
|
200
|
-
req =
|
330
|
+
req = make_request mr
|
201
331
|
|
202
|
-
lambda { req.POST }.
|
203
|
-
|
204
|
-
message.should.equal "invalid %-encoding (a%)"
|
332
|
+
lambda { req.POST }.must_raise(Rack::Utils::InvalidParameterError).
|
333
|
+
message.must_equal "invalid %-encoding (a%)"
|
205
334
|
end
|
206
335
|
|
207
|
-
|
208
|
-
req =
|
209
|
-
lambda { req.POST }.
|
336
|
+
it "raise if rack.input is missing" do
|
337
|
+
req = make_request({})
|
338
|
+
lambda { req.POST }.must_raise RuntimeError
|
210
339
|
end
|
211
340
|
|
212
|
-
|
213
|
-
req =
|
341
|
+
it "parse POST data when method is POST and no Content-Type given" do
|
342
|
+
req = make_request \
|
214
343
|
Rack::MockRequest.env_for("/?foo=quux",
|
215
344
|
"REQUEST_METHOD" => 'POST',
|
216
345
|
:input => "foo=bar&quux=bla")
|
217
|
-
req.content_type.
|
218
|
-
req.media_type.
|
219
|
-
req.query_string.
|
220
|
-
req.GET.
|
221
|
-
req.POST.
|
222
|
-
req.params.
|
346
|
+
req.content_type.must_be_nil
|
347
|
+
req.media_type.must_be_nil
|
348
|
+
req.query_string.must_equal "foo=quux"
|
349
|
+
req.GET.must_equal "foo" => "quux"
|
350
|
+
req.POST.must_equal "foo" => "bar", "quux" => "bla"
|
351
|
+
req.params.must_equal "foo" => "bar", "quux" => "bla"
|
223
352
|
end
|
224
353
|
|
225
|
-
|
354
|
+
it "limit the keys from the POST form data" do
|
226
355
|
env = Rack::MockRequest.env_for("",
|
227
356
|
"REQUEST_METHOD" => 'POST',
|
228
357
|
:input => "foo=bar&quux=bla")
|
229
358
|
|
230
359
|
old, Rack::Utils.key_space_limit = Rack::Utils.key_space_limit, 1
|
231
360
|
begin
|
232
|
-
req =
|
233
|
-
lambda { req.POST }.
|
361
|
+
req = make_request(env)
|
362
|
+
lambda { req.POST }.must_raise RangeError
|
234
363
|
ensure
|
235
364
|
Rack::Utils.key_space_limit = old
|
236
365
|
end
|
237
366
|
end
|
238
367
|
|
239
|
-
|
240
|
-
req =
|
368
|
+
it "parse POST data with explicit content type regardless of method" do
|
369
|
+
req = make_request \
|
241
370
|
Rack::MockRequest.env_for("/",
|
242
371
|
"CONTENT_TYPE" => 'application/x-www-form-urlencoded;foo=bar',
|
243
372
|
:input => "foo=bar&quux=bla")
|
244
|
-
req.content_type.
|
245
|
-
req.media_type.
|
246
|
-
req.media_type_params['foo'].
|
247
|
-
req.POST.
|
248
|
-
req.params.
|
373
|
+
req.content_type.must_equal 'application/x-www-form-urlencoded;foo=bar'
|
374
|
+
req.media_type.must_equal 'application/x-www-form-urlencoded'
|
375
|
+
req.media_type_params['foo'].must_equal 'bar'
|
376
|
+
req.POST.must_equal "foo" => "bar", "quux" => "bla"
|
377
|
+
req.params.must_equal "foo" => "bar", "quux" => "bla"
|
249
378
|
end
|
250
379
|
|
251
|
-
|
252
|
-
req =
|
380
|
+
it "not parse POST data when media type is not form-data" do
|
381
|
+
req = make_request \
|
253
382
|
Rack::MockRequest.env_for("/?foo=quux",
|
254
383
|
"REQUEST_METHOD" => 'POST',
|
255
384
|
"CONTENT_TYPE" => 'text/plain;charset=utf-8',
|
256
385
|
:input => "foo=bar&quux=bla")
|
257
|
-
req.content_type.
|
258
|
-
req.media_type.
|
259
|
-
req.media_type_params['charset'].
|
260
|
-
req.POST.
|
261
|
-
req.params.
|
262
|
-
req.body.read.
|
386
|
+
req.content_type.must_equal 'text/plain;charset=utf-8'
|
387
|
+
req.media_type.must_equal 'text/plain'
|
388
|
+
req.media_type_params['charset'].must_equal 'utf-8'
|
389
|
+
req.POST.must_be :empty?
|
390
|
+
req.params.must_equal "foo" => "quux"
|
391
|
+
req.body.read.must_equal "foo=bar&quux=bla"
|
263
392
|
end
|
264
393
|
|
265
|
-
|
266
|
-
req =
|
394
|
+
it "parse POST data on PUT when media type is form-data" do
|
395
|
+
req = make_request \
|
267
396
|
Rack::MockRequest.env_for("/?foo=quux",
|
268
397
|
"REQUEST_METHOD" => 'PUT',
|
269
398
|
"CONTENT_TYPE" => 'application/x-www-form-urlencoded',
|
270
399
|
:input => "foo=bar&quux=bla")
|
271
|
-
req.POST.
|
272
|
-
req.body.read.
|
400
|
+
req.POST.must_equal "foo" => "bar", "quux" => "bla"
|
401
|
+
req.body.read.must_equal "foo=bar&quux=bla"
|
273
402
|
end
|
274
403
|
|
275
|
-
|
404
|
+
it "rewind input after parsing POST data" do
|
276
405
|
input = StringIO.new("foo=bar&quux=bla")
|
277
|
-
req =
|
406
|
+
req = make_request \
|
278
407
|
Rack::MockRequest.env_for("/",
|
279
408
|
"CONTENT_TYPE" => 'application/x-www-form-urlencoded;foo=bar',
|
280
409
|
:input => input)
|
281
|
-
req.params.
|
282
|
-
input.read.
|
410
|
+
req.params.must_equal "foo" => "bar", "quux" => "bla"
|
411
|
+
input.read.must_equal "foo=bar&quux=bla"
|
412
|
+
end
|
413
|
+
|
414
|
+
it "safely accepts POST requests with empty body" do
|
415
|
+
mr = Rack::MockRequest.env_for("/",
|
416
|
+
"REQUEST_METHOD" => "POST",
|
417
|
+
"CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
|
418
|
+
"CONTENT_LENGTH" => '0',
|
419
|
+
:input => nil)
|
420
|
+
|
421
|
+
req = make_request mr
|
422
|
+
req.query_string.must_equal ""
|
423
|
+
req.GET.must_be :empty?
|
424
|
+
req.POST.must_be :empty?
|
425
|
+
req.params.must_equal({})
|
283
426
|
end
|
284
427
|
|
285
|
-
|
286
|
-
req =
|
428
|
+
it "clean up Safari's ajax POST body" do
|
429
|
+
req = make_request \
|
287
430
|
Rack::MockRequest.env_for("/",
|
288
431
|
'REQUEST_METHOD' => 'POST', :input => "foo=bar&quux=bla\0")
|
289
|
-
req.POST.
|
432
|
+
req.POST.must_equal "foo" => "bar", "quux" => "bla"
|
290
433
|
end
|
291
434
|
|
292
|
-
|
293
|
-
req =
|
435
|
+
it "get value by key from params with #[]" do
|
436
|
+
req = make_request \
|
294
437
|
Rack::MockRequest.env_for("?foo=quux")
|
295
|
-
req['foo'].
|
296
|
-
req[:foo].
|
438
|
+
req['foo'].must_equal 'quux'
|
439
|
+
req[:foo].must_equal 'quux'
|
297
440
|
end
|
298
441
|
|
299
|
-
|
300
|
-
req =
|
442
|
+
it "set value to key on params with #[]=" do
|
443
|
+
req = make_request \
|
301
444
|
Rack::MockRequest.env_for("?foo=duh")
|
302
|
-
req['foo'].
|
303
|
-
req[:foo].
|
304
|
-
req.params.
|
445
|
+
req['foo'].must_equal 'duh'
|
446
|
+
req[:foo].must_equal 'duh'
|
447
|
+
req.params.must_equal 'foo' => 'duh'
|
448
|
+
|
449
|
+
if req.delegate?
|
450
|
+
skip "delegate requests don't cache params, so mutations have no impact"
|
451
|
+
end
|
305
452
|
|
306
453
|
req['foo'] = 'bar'
|
307
|
-
req.params.
|
308
|
-
req['foo'].
|
309
|
-
req[:foo].
|
454
|
+
req.params.must_equal 'foo' => 'bar'
|
455
|
+
req['foo'].must_equal 'bar'
|
456
|
+
req[:foo].must_equal 'bar'
|
310
457
|
|
311
458
|
req[:foo] = 'jaz'
|
312
|
-
req.params.
|
313
|
-
req['foo'].
|
314
|
-
req[:foo].
|
459
|
+
req.params.must_equal 'foo' => 'jaz'
|
460
|
+
req['foo'].must_equal 'jaz'
|
461
|
+
req[:foo].must_equal 'jaz'
|
315
462
|
end
|
316
463
|
|
317
|
-
|
318
|
-
req =
|
464
|
+
it "return values for the keys in the order given from values_at" do
|
465
|
+
req = make_request \
|
319
466
|
Rack::MockRequest.env_for("?foo=baz&wun=der&bar=ful")
|
320
|
-
req.values_at('foo').
|
321
|
-
req.values_at('foo', 'wun').
|
322
|
-
req.values_at('bar', 'foo', 'wun').
|
467
|
+
req.values_at('foo').must_equal ['baz']
|
468
|
+
req.values_at('foo', 'wun').must_equal ['baz', 'der']
|
469
|
+
req.values_at('bar', 'foo', 'wun').must_equal ['ful', 'baz', 'der']
|
323
470
|
end
|
324
471
|
|
325
|
-
|
326
|
-
req =
|
472
|
+
it "extract referrer correctly" do
|
473
|
+
req = make_request \
|
327
474
|
Rack::MockRequest.env_for("/", "HTTP_REFERER" => "/some/path")
|
328
|
-
req.referer.
|
475
|
+
req.referer.must_equal "/some/path"
|
329
476
|
|
330
|
-
req =
|
477
|
+
req = make_request \
|
331
478
|
Rack::MockRequest.env_for("/")
|
332
|
-
req.referer.
|
479
|
+
req.referer.must_be_nil
|
333
480
|
end
|
334
481
|
|
335
|
-
|
336
|
-
req =
|
482
|
+
it "extract user agent correctly" do
|
483
|
+
req = make_request \
|
337
484
|
Rack::MockRequest.env_for("/", "HTTP_USER_AGENT" => "Mozilla/4.0 (compatible)")
|
338
|
-
req.user_agent.
|
485
|
+
req.user_agent.must_equal "Mozilla/4.0 (compatible)"
|
339
486
|
|
340
|
-
req =
|
487
|
+
req = make_request \
|
341
488
|
Rack::MockRequest.env_for("/")
|
342
|
-
req.user_agent.
|
489
|
+
req.user_agent.must_be_nil
|
343
490
|
end
|
344
491
|
|
345
|
-
|
346
|
-
req =
|
492
|
+
it "treat missing content type as nil" do
|
493
|
+
req = make_request \
|
347
494
|
Rack::MockRequest.env_for("/")
|
348
|
-
req.content_type.
|
495
|
+
req.content_type.must_be_nil
|
349
496
|
end
|
350
497
|
|
351
|
-
|
352
|
-
req =
|
498
|
+
it "treat empty content type as nil" do
|
499
|
+
req = make_request \
|
353
500
|
Rack::MockRequest.env_for("/", "CONTENT_TYPE" => "")
|
354
|
-
req.content_type.
|
501
|
+
req.content_type.must_be_nil
|
355
502
|
end
|
356
503
|
|
357
|
-
|
358
|
-
req =
|
504
|
+
it "return nil media type for empty content type" do
|
505
|
+
req = make_request \
|
359
506
|
Rack::MockRequest.env_for("/", "CONTENT_TYPE" => "")
|
360
|
-
req.media_type.
|
507
|
+
req.media_type.must_be_nil
|
361
508
|
end
|
362
509
|
|
363
|
-
|
364
|
-
req =
|
510
|
+
it "cache, but invalidates the cache" do
|
511
|
+
req = make_request \
|
365
512
|
Rack::MockRequest.env_for("/?foo=quux",
|
366
513
|
"CONTENT_TYPE" => "application/x-www-form-urlencoded",
|
367
514
|
:input => "foo=bar&quux=bla")
|
368
|
-
req.GET.
|
369
|
-
req.GET.
|
370
|
-
req.
|
371
|
-
req.GET.
|
372
|
-
req.GET.
|
515
|
+
req.GET.must_equal "foo" => "quux"
|
516
|
+
req.GET.must_equal "foo" => "quux"
|
517
|
+
req.set_header("QUERY_STRING", "bla=foo")
|
518
|
+
req.GET.must_equal "bla" => "foo"
|
519
|
+
req.GET.must_equal "bla" => "foo"
|
373
520
|
|
374
|
-
req.POST.
|
375
|
-
req.POST.
|
376
|
-
req.
|
377
|
-
req.POST.
|
378
|
-
req.POST.
|
521
|
+
req.POST.must_equal "foo" => "bar", "quux" => "bla"
|
522
|
+
req.POST.must_equal "foo" => "bar", "quux" => "bla"
|
523
|
+
req.set_header("rack.input", StringIO.new("foo=bla&quux=bar"))
|
524
|
+
req.POST.must_equal "foo" => "bla", "quux" => "bar"
|
525
|
+
req.POST.must_equal "foo" => "bla", "quux" => "bar"
|
379
526
|
end
|
380
527
|
|
381
|
-
|
382
|
-
req =
|
383
|
-
req.
|
528
|
+
it "figure out if called via XHR" do
|
529
|
+
req = make_request(Rack::MockRequest.env_for(""))
|
530
|
+
req.wont_be :xhr?
|
384
531
|
|
385
|
-
req =
|
532
|
+
req = make_request \
|
386
533
|
Rack::MockRequest.env_for("", "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest")
|
387
|
-
req.
|
534
|
+
req.must_be :xhr?
|
388
535
|
end
|
389
536
|
|
390
|
-
|
391
|
-
request =
|
392
|
-
request.scheme.
|
393
|
-
request.
|
537
|
+
it "ssl detection" do
|
538
|
+
request = make_request(Rack::MockRequest.env_for("/"))
|
539
|
+
request.scheme.must_equal "http"
|
540
|
+
request.wont_be :ssl?
|
394
541
|
|
395
|
-
request =
|
396
|
-
request.scheme.
|
397
|
-
request.
|
542
|
+
request = make_request(Rack::MockRequest.env_for("/", 'HTTPS' => 'on'))
|
543
|
+
request.scheme.must_equal "https"
|
544
|
+
request.must_be :ssl?
|
398
545
|
|
399
|
-
request =
|
400
|
-
request.scheme.
|
401
|
-
request.
|
546
|
+
request = make_request(Rack::MockRequest.env_for("/", 'rack.url_scheme' => 'https'))
|
547
|
+
request.scheme.must_equal "https"
|
548
|
+
request.must_be :ssl?
|
402
549
|
|
403
|
-
request =
|
404
|
-
request.scheme.
|
405
|
-
request.
|
550
|
+
request = make_request(Rack::MockRequest.env_for("/", 'HTTP_HOST' => 'www.example.org:8080'))
|
551
|
+
request.scheme.must_equal "http"
|
552
|
+
request.wont_be :ssl?
|
406
553
|
|
407
|
-
request =
|
408
|
-
request.scheme.
|
409
|
-
request.
|
554
|
+
request = make_request(Rack::MockRequest.env_for("/", 'HTTP_HOST' => 'www.example.org:8443', 'HTTPS' => 'on'))
|
555
|
+
request.scheme.must_equal "https"
|
556
|
+
request.must_be :ssl?
|
410
557
|
|
411
|
-
request =
|
412
|
-
request.scheme.
|
413
|
-
request.
|
558
|
+
request = make_request(Rack::MockRequest.env_for("/", 'HTTP_HOST' => 'www.example.org:8443', 'HTTP_X_FORWARDED_SSL' => 'on'))
|
559
|
+
request.scheme.must_equal "https"
|
560
|
+
request.must_be :ssl?
|
414
561
|
|
415
|
-
request =
|
416
|
-
request.scheme.
|
417
|
-
request.
|
562
|
+
request = make_request(Rack::MockRequest.env_for("/", 'HTTP_X_FORWARDED_SCHEME' => 'https'))
|
563
|
+
request.scheme.must_equal "https"
|
564
|
+
request.must_be :ssl?
|
418
565
|
|
419
|
-
request =
|
420
|
-
request.scheme.
|
421
|
-
request.
|
566
|
+
request = make_request(Rack::MockRequest.env_for("/", 'HTTP_X_FORWARDED_PROTO' => 'https'))
|
567
|
+
request.scheme.must_equal "https"
|
568
|
+
request.must_be :ssl?
|
422
569
|
|
423
|
-
request =
|
424
|
-
request.scheme.
|
425
|
-
request.
|
570
|
+
request = make_request(Rack::MockRequest.env_for("/", 'HTTP_X_FORWARDED_PROTO' => 'https, http, http'))
|
571
|
+
request.scheme.must_equal "https"
|
572
|
+
request.must_be :ssl?
|
426
573
|
end
|
427
574
|
|
428
|
-
|
429
|
-
request =
|
430
|
-
request.scheme.
|
575
|
+
it "prevents scheme abuse" do
|
576
|
+
request = make_request(Rack::MockRequest.env_for("/", 'HTTP_X_FORWARDED_SCHEME' => 'a."><script>alert(1)</script>'))
|
577
|
+
request.scheme.must_equal 'http'
|
431
578
|
end
|
432
579
|
|
433
|
-
|
434
|
-
req =
|
580
|
+
it "parse cookies" do
|
581
|
+
req = make_request \
|
435
582
|
Rack::MockRequest.env_for("", "HTTP_COOKIE" => "foo=bar;quux=h&m")
|
436
|
-
req.cookies.
|
437
|
-
req.cookies.
|
438
|
-
req.
|
439
|
-
req.cookies.
|
583
|
+
req.cookies.must_equal "foo" => "bar", "quux" => "h&m"
|
584
|
+
req.cookies.must_equal "foo" => "bar", "quux" => "h&m"
|
585
|
+
req.delete_header("HTTP_COOKIE")
|
586
|
+
req.cookies.must_equal({})
|
440
587
|
end
|
441
588
|
|
442
|
-
|
443
|
-
req =
|
589
|
+
it "always return the same hash object" do
|
590
|
+
req = make_request \
|
444
591
|
Rack::MockRequest.env_for("", "HTTP_COOKIE" => "foo=bar;quux=h&m")
|
445
592
|
hash = req.cookies
|
446
593
|
req.env.delete("HTTP_COOKIE")
|
447
|
-
req.cookies.
|
594
|
+
req.cookies.must_equal hash
|
448
595
|
req.env["HTTP_COOKIE"] = "zoo=m"
|
449
|
-
req.cookies.
|
596
|
+
req.cookies.must_equal hash
|
450
597
|
end
|
451
598
|
|
452
|
-
|
453
|
-
req =
|
454
|
-
req.cookies.
|
599
|
+
it "modify the cookies hash in place" do
|
600
|
+
req = make_request(Rack::MockRequest.env_for(""))
|
601
|
+
req.cookies.must_equal({})
|
455
602
|
req.cookies['foo'] = 'bar'
|
456
|
-
req.cookies.
|
603
|
+
req.cookies.must_equal 'foo' => 'bar'
|
457
604
|
end
|
458
605
|
|
459
|
-
|
606
|
+
it "not modify the params hash in place" do
|
460
607
|
e = Rack::MockRequest.env_for("")
|
461
|
-
req1 =
|
462
|
-
req1.
|
608
|
+
req1 = make_request(e)
|
609
|
+
if req1.delegate?
|
610
|
+
skip "delegate requests don't cache params, so mutations have no impact"
|
611
|
+
end
|
612
|
+
req1.params.must_equal({})
|
463
613
|
req1.params['foo'] = 'bar'
|
464
|
-
req1.params.
|
465
|
-
req2 =
|
466
|
-
req2.params.
|
614
|
+
req1.params.must_equal 'foo' => 'bar'
|
615
|
+
req2 = make_request(e)
|
616
|
+
req2.params.must_equal({})
|
467
617
|
end
|
468
618
|
|
469
|
-
|
619
|
+
it "modify params hash if param is in GET" do
|
470
620
|
e = Rack::MockRequest.env_for("?foo=duh")
|
471
|
-
req1 =
|
472
|
-
req1.params.
|
621
|
+
req1 = make_request(e)
|
622
|
+
req1.params.must_equal 'foo' => 'duh'
|
473
623
|
req1.update_param 'foo', 'bar'
|
474
|
-
req1.params.
|
475
|
-
req2 =
|
476
|
-
req2.params.
|
624
|
+
req1.params.must_equal 'foo' => 'bar'
|
625
|
+
req2 = make_request(e)
|
626
|
+
req2.params.must_equal 'foo' => 'bar'
|
477
627
|
end
|
478
628
|
|
479
|
-
|
629
|
+
it "modify params hash if param is in POST" do
|
480
630
|
e = Rack::MockRequest.env_for("", "REQUEST_METHOD" => 'POST', :input => 'foo=duh')
|
481
|
-
req1 =
|
482
|
-
req1.params.
|
631
|
+
req1 = make_request(e)
|
632
|
+
req1.params.must_equal 'foo' => 'duh'
|
483
633
|
req1.update_param 'foo', 'bar'
|
484
|
-
req1.params.
|
485
|
-
req2 =
|
486
|
-
req2.params.
|
634
|
+
req1.params.must_equal 'foo' => 'bar'
|
635
|
+
req2 = make_request(e)
|
636
|
+
req2.params.must_equal 'foo' => 'bar'
|
487
637
|
end
|
488
638
|
|
489
|
-
|
639
|
+
it "modify params hash, even if param didn't exist before" do
|
490
640
|
e = Rack::MockRequest.env_for("")
|
491
|
-
req1 =
|
492
|
-
req1.params.
|
641
|
+
req1 = make_request(e)
|
642
|
+
req1.params.must_equal({})
|
493
643
|
req1.update_param 'foo', 'bar'
|
494
|
-
req1.params.
|
495
|
-
req2 =
|
496
|
-
req2.params.
|
644
|
+
req1.params.must_equal 'foo' => 'bar'
|
645
|
+
req2 = make_request(e)
|
646
|
+
req2.params.must_equal 'foo' => 'bar'
|
497
647
|
end
|
498
648
|
|
499
|
-
|
649
|
+
it "modify params hash by changing only GET" do
|
500
650
|
e = Rack::MockRequest.env_for("?foo=duhget")
|
501
|
-
req =
|
502
|
-
req.GET.
|
503
|
-
req.POST.
|
651
|
+
req = make_request(e)
|
652
|
+
req.GET.must_equal 'foo' => 'duhget'
|
653
|
+
req.POST.must_equal({})
|
504
654
|
req.update_param 'foo', 'bar'
|
505
|
-
req.GET.
|
506
|
-
req.POST.
|
655
|
+
req.GET.must_equal 'foo' => 'bar'
|
656
|
+
req.POST.must_equal({})
|
507
657
|
end
|
508
658
|
|
509
|
-
|
659
|
+
it "modify params hash by changing only POST" do
|
510
660
|
e = Rack::MockRequest.env_for("", "REQUEST_METHOD" => 'POST', :input => "foo=duhpost")
|
511
|
-
req =
|
512
|
-
req.GET.
|
513
|
-
req.POST.
|
661
|
+
req = make_request(e)
|
662
|
+
req.GET.must_equal({})
|
663
|
+
req.POST.must_equal 'foo' => 'duhpost'
|
514
664
|
req.update_param 'foo', 'bar'
|
515
|
-
req.GET.
|
516
|
-
req.POST.
|
665
|
+
req.GET.must_equal({})
|
666
|
+
req.POST.must_equal 'foo' => 'bar'
|
517
667
|
end
|
518
668
|
|
519
|
-
|
669
|
+
it "modify params hash, even if param is defined in both POST and GET" do
|
520
670
|
e = Rack::MockRequest.env_for("?foo=duhget", "REQUEST_METHOD" => 'POST', :input => "foo=duhpost")
|
521
|
-
req1 =
|
522
|
-
req1.GET.
|
523
|
-
req1.POST.
|
524
|
-
req1.params.
|
671
|
+
req1 = make_request(e)
|
672
|
+
req1.GET.must_equal 'foo' => 'duhget'
|
673
|
+
req1.POST.must_equal 'foo' => 'duhpost'
|
674
|
+
req1.params.must_equal 'foo' => 'duhpost'
|
525
675
|
req1.update_param 'foo', 'bar'
|
526
|
-
req1.GET.
|
527
|
-
req1.POST.
|
528
|
-
req1.params.
|
529
|
-
req2 =
|
530
|
-
req2.GET.
|
531
|
-
req2.POST.
|
532
|
-
req2.params.
|
533
|
-
req2.params.
|
676
|
+
req1.GET.must_equal 'foo' => 'bar'
|
677
|
+
req1.POST.must_equal 'foo' => 'bar'
|
678
|
+
req1.params.must_equal 'foo' => 'bar'
|
679
|
+
req2 = make_request(e)
|
680
|
+
req2.GET.must_equal 'foo' => 'bar'
|
681
|
+
req2.POST.must_equal 'foo' => 'bar'
|
682
|
+
req2.params.must_equal 'foo' => 'bar'
|
683
|
+
req2.params.must_equal 'foo' => 'bar'
|
534
684
|
end
|
535
685
|
|
536
|
-
|
686
|
+
it "allow deleting from params hash if param is in GET" do
|
537
687
|
e = Rack::MockRequest.env_for("?foo=bar")
|
538
|
-
req1 =
|
539
|
-
req1.params.
|
540
|
-
req1.delete_param('foo').
|
541
|
-
req1.params.
|
542
|
-
req2 =
|
543
|
-
req2.params.
|
688
|
+
req1 = make_request(e)
|
689
|
+
req1.params.must_equal 'foo' => 'bar'
|
690
|
+
req1.delete_param('foo').must_equal 'bar'
|
691
|
+
req1.params.must_equal({})
|
692
|
+
req2 = make_request(e)
|
693
|
+
req2.params.must_equal({})
|
544
694
|
end
|
545
695
|
|
546
|
-
|
696
|
+
it "allow deleting from params hash if param is in POST" do
|
547
697
|
e = Rack::MockRequest.env_for("", "REQUEST_METHOD" => 'POST', :input => 'foo=bar')
|
548
|
-
req1 =
|
549
|
-
req1.params.
|
550
|
-
req1.delete_param('foo').
|
551
|
-
req1.params.
|
552
|
-
req2 =
|
553
|
-
req2.params.
|
698
|
+
req1 = make_request(e)
|
699
|
+
req1.params.must_equal 'foo' => 'bar'
|
700
|
+
req1.delete_param('foo').must_equal 'bar'
|
701
|
+
req1.params.must_equal({})
|
702
|
+
req2 = make_request(e)
|
703
|
+
req2.params.must_equal({})
|
554
704
|
end
|
555
705
|
|
556
|
-
|
557
|
-
req =
|
558
|
-
req.cookies["foo"].
|
706
|
+
it "pass through non-uri escaped cookies as-is" do
|
707
|
+
req = make_request Rack::MockRequest.env_for("", "HTTP_COOKIE" => "foo=%")
|
708
|
+
req.cookies["foo"].must_equal "%"
|
559
709
|
end
|
560
710
|
|
561
|
-
|
562
|
-
req =
|
711
|
+
it "parse cookies according to RFC 2109" do
|
712
|
+
req = make_request \
|
563
713
|
Rack::MockRequest.env_for('', 'HTTP_COOKIE' => 'foo=bar;foo=car')
|
564
|
-
req.cookies.
|
714
|
+
req.cookies.must_equal 'foo' => 'bar'
|
565
715
|
end
|
566
716
|
|
567
|
-
|
568
|
-
req =
|
717
|
+
it 'parse cookies with quotes' do
|
718
|
+
req = make_request Rack::MockRequest.env_for('', {
|
569
719
|
'HTTP_COOKIE' => '$Version="1"; Customer="WILE_E_COYOTE"; $Path="/acme"; Part_Number="Rocket_Launcher_0001"; $Path="/acme"'
|
570
720
|
})
|
571
|
-
req.cookies.
|
721
|
+
req.cookies.must_equal({
|
572
722
|
'$Version' => '"1"',
|
573
723
|
'Customer' => '"WILE_E_COYOTE"',
|
574
724
|
'$Path' => '"/acme"',
|
@@ -576,88 +726,88 @@ describe Rack::Request do
|
|
576
726
|
})
|
577
727
|
end
|
578
728
|
|
579
|
-
|
580
|
-
req =
|
581
|
-
req.script_name.
|
729
|
+
it "provide setters" do
|
730
|
+
req = make_request(e=Rack::MockRequest.env_for(""))
|
731
|
+
req.script_name.must_equal ""
|
582
732
|
req.script_name = "/foo"
|
583
|
-
req.script_name.
|
584
|
-
e["SCRIPT_NAME"].
|
733
|
+
req.script_name.must_equal "/foo"
|
734
|
+
e["SCRIPT_NAME"].must_equal "/foo"
|
585
735
|
|
586
|
-
req.path_info.
|
736
|
+
req.path_info.must_equal "/"
|
587
737
|
req.path_info = "/foo"
|
588
|
-
req.path_info.
|
589
|
-
e["PATH_INFO"].
|
590
|
-
end
|
591
|
-
|
592
|
-
|
593
|
-
req =
|
594
|
-
req.env.
|
595
|
-
end
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
end
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
end
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
end
|
642
|
-
|
643
|
-
|
644
|
-
req =
|
738
|
+
req.path_info.must_equal "/foo"
|
739
|
+
e["PATH_INFO"].must_equal "/foo"
|
740
|
+
end
|
741
|
+
|
742
|
+
it "provide the original env" do
|
743
|
+
req = make_request(e = Rack::MockRequest.env_for(""))
|
744
|
+
req.env.must_equal e
|
745
|
+
end
|
746
|
+
|
747
|
+
it "restore the base URL" do
|
748
|
+
make_request(Rack::MockRequest.env_for("")).base_url.
|
749
|
+
must_equal "http://example.org"
|
750
|
+
make_request(Rack::MockRequest.env_for("", "SCRIPT_NAME" => "/foo")).base_url.
|
751
|
+
must_equal "http://example.org"
|
752
|
+
end
|
753
|
+
|
754
|
+
it "restore the URL" do
|
755
|
+
make_request(Rack::MockRequest.env_for("")).url.
|
756
|
+
must_equal "http://example.org/"
|
757
|
+
make_request(Rack::MockRequest.env_for("", "SCRIPT_NAME" => "/foo")).url.
|
758
|
+
must_equal "http://example.org/foo/"
|
759
|
+
make_request(Rack::MockRequest.env_for("/foo")).url.
|
760
|
+
must_equal "http://example.org/foo"
|
761
|
+
make_request(Rack::MockRequest.env_for("?foo")).url.
|
762
|
+
must_equal "http://example.org/?foo"
|
763
|
+
make_request(Rack::MockRequest.env_for("http://example.org:8080/")).url.
|
764
|
+
must_equal "http://example.org:8080/"
|
765
|
+
make_request(Rack::MockRequest.env_for("https://example.org/")).url.
|
766
|
+
must_equal "https://example.org/"
|
767
|
+
make_request(Rack::MockRequest.env_for("coffee://example.org/")).url.
|
768
|
+
must_equal "coffee://example.org/"
|
769
|
+
make_request(Rack::MockRequest.env_for("coffee://example.org:443/")).url.
|
770
|
+
must_equal "coffee://example.org:443/"
|
771
|
+
make_request(Rack::MockRequest.env_for("https://example.com:8080/foo?foo")).url.
|
772
|
+
must_equal "https://example.com:8080/foo?foo"
|
773
|
+
end
|
774
|
+
|
775
|
+
it "restore the full path" do
|
776
|
+
make_request(Rack::MockRequest.env_for("")).fullpath.
|
777
|
+
must_equal "/"
|
778
|
+
make_request(Rack::MockRequest.env_for("", "SCRIPT_NAME" => "/foo")).fullpath.
|
779
|
+
must_equal "/foo/"
|
780
|
+
make_request(Rack::MockRequest.env_for("/foo")).fullpath.
|
781
|
+
must_equal "/foo"
|
782
|
+
make_request(Rack::MockRequest.env_for("?foo")).fullpath.
|
783
|
+
must_equal "/?foo"
|
784
|
+
make_request(Rack::MockRequest.env_for("http://example.org:8080/")).fullpath.
|
785
|
+
must_equal "/"
|
786
|
+
make_request(Rack::MockRequest.env_for("https://example.org/")).fullpath.
|
787
|
+
must_equal "/"
|
788
|
+
|
789
|
+
make_request(Rack::MockRequest.env_for("https://example.com:8080/foo?foo")).fullpath.
|
790
|
+
must_equal "/foo?foo"
|
791
|
+
end
|
792
|
+
|
793
|
+
it "handle multiple media type parameters" do
|
794
|
+
req = make_request \
|
645
795
|
Rack::MockRequest.env_for("/",
|
646
796
|
"CONTENT_TYPE" => 'text/plain; foo=BAR,baz=bizzle dizzle;BLING=bam;blong="boo";zump="zoo\"o";weird=lol"')
|
647
|
-
req.
|
648
|
-
req.media_type_params.
|
649
|
-
req.media_type_params['foo'].
|
650
|
-
req.media_type_params.
|
651
|
-
req.media_type_params['baz'].
|
652
|
-
req.media_type_params.
|
653
|
-
req.media_type_params.
|
654
|
-
req.media_type_params['bling'].
|
655
|
-
req.media_type_params['blong'].
|
656
|
-
req.media_type_params['zump'].
|
657
|
-
req.media_type_params['weird'].
|
658
|
-
end
|
659
|
-
|
660
|
-
|
797
|
+
req.wont_be :form_data?
|
798
|
+
req.media_type_params.must_include 'foo'
|
799
|
+
req.media_type_params['foo'].must_equal 'BAR'
|
800
|
+
req.media_type_params.must_include 'baz'
|
801
|
+
req.media_type_params['baz'].must_equal 'bizzle dizzle'
|
802
|
+
req.media_type_params.wont_include 'BLING'
|
803
|
+
req.media_type_params.must_include 'bling'
|
804
|
+
req.media_type_params['bling'].must_equal 'bam'
|
805
|
+
req.media_type_params['blong'].must_equal 'boo'
|
806
|
+
req.media_type_params['zump'].must_equal 'zoo\"o'
|
807
|
+
req.media_type_params['weird'].must_equal 'lol"'
|
808
|
+
end
|
809
|
+
|
810
|
+
it "parse with junk before boundary" do
|
661
811
|
# Adapted from RFC 1867.
|
662
812
|
input = <<EOF
|
663
813
|
blah blah\r
|
@@ -674,31 +824,31 @@ Content-Transfer-Encoding: base64\r
|
|
674
824
|
/9j/4AAQSkZJRgABAQAAAQABAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcg\r
|
675
825
|
--AaB03x--\r
|
676
826
|
EOF
|
677
|
-
req =
|
827
|
+
req = make_request Rack::MockRequest.env_for("/",
|
678
828
|
"CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
|
679
829
|
"CONTENT_LENGTH" => input.size,
|
680
830
|
:input => input)
|
681
831
|
|
682
|
-
req.POST.
|
683
|
-
req.POST.
|
832
|
+
req.POST.must_include "fileupload"
|
833
|
+
req.POST.must_include "reply"
|
684
834
|
|
685
|
-
req.
|
686
|
-
req.content_length.
|
687
|
-
req.media_type.
|
688
|
-
req.media_type_params.
|
689
|
-
req.media_type_params['boundary'].
|
835
|
+
req.must_be :form_data?
|
836
|
+
req.content_length.must_equal input.size
|
837
|
+
req.media_type.must_equal 'multipart/form-data'
|
838
|
+
req.media_type_params.must_include 'boundary'
|
839
|
+
req.media_type_params['boundary'].must_equal 'AaB03x'
|
690
840
|
|
691
|
-
req.POST["reply"].
|
841
|
+
req.POST["reply"].must_equal "yes"
|
692
842
|
|
693
843
|
f = req.POST["fileupload"]
|
694
|
-
f.
|
695
|
-
f[:type].
|
696
|
-
f[:filename].
|
697
|
-
f.
|
698
|
-
f[:tempfile].size.
|
844
|
+
f.must_be_kind_of Hash
|
845
|
+
f[:type].must_equal "image/jpeg"
|
846
|
+
f[:filename].must_equal "dj.jpg"
|
847
|
+
f.must_include :tempfile
|
848
|
+
f[:tempfile].size.must_equal 76
|
699
849
|
end
|
700
850
|
|
701
|
-
|
851
|
+
it "not infinite loop with a malformed HTTP request" do
|
702
852
|
# Adapted from RFC 1867.
|
703
853
|
input = <<EOF
|
704
854
|
--AaB03x
|
@@ -713,16 +863,16 @@ Content-Transfer-Encoding: base64
|
|
713
863
|
/9j/4AAQSkZJRgABAQAAAQABAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcg
|
714
864
|
--AaB03x--
|
715
865
|
EOF
|
716
|
-
req =
|
866
|
+
req = make_request Rack::MockRequest.env_for("/",
|
717
867
|
"CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
|
718
868
|
"CONTENT_LENGTH" => input.size,
|
719
869
|
:input => input)
|
720
870
|
|
721
|
-
lambda{req.POST}.
|
871
|
+
lambda{req.POST}.must_raise EOFError
|
722
872
|
end
|
723
873
|
|
724
874
|
|
725
|
-
|
875
|
+
it "parse multipart form data" do
|
726
876
|
# Adapted from RFC 1867.
|
727
877
|
input = <<EOF
|
728
878
|
--AaB03x\r
|
@@ -737,47 +887,89 @@ Content-Transfer-Encoding: base64\r
|
|
737
887
|
/9j/4AAQSkZJRgABAQAAAQABAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcg\r
|
738
888
|
--AaB03x--\r
|
739
889
|
EOF
|
740
|
-
req =
|
890
|
+
req = make_request Rack::MockRequest.env_for("/",
|
741
891
|
"CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
|
742
892
|
"CONTENT_LENGTH" => input.size,
|
743
893
|
:input => input)
|
744
894
|
|
745
|
-
req.POST.
|
746
|
-
req.POST.
|
895
|
+
req.POST.must_include "fileupload"
|
896
|
+
req.POST.must_include "reply"
|
747
897
|
|
748
|
-
req.
|
749
|
-
req.content_length.
|
750
|
-
req.media_type.
|
751
|
-
req.media_type_params.
|
752
|
-
req.media_type_params['boundary'].
|
898
|
+
req.must_be :form_data?
|
899
|
+
req.content_length.must_equal input.size
|
900
|
+
req.media_type.must_equal 'multipart/form-data'
|
901
|
+
req.media_type_params.must_include 'boundary'
|
902
|
+
req.media_type_params['boundary'].must_equal 'AaB03x'
|
753
903
|
|
754
|
-
req.POST["reply"].
|
904
|
+
req.POST["reply"].must_equal "yes"
|
755
905
|
|
756
906
|
f = req.POST["fileupload"]
|
757
|
-
f.
|
758
|
-
f[:type].
|
759
|
-
f[:filename].
|
760
|
-
f.
|
761
|
-
f[:tempfile].size.
|
907
|
+
f.must_be_kind_of Hash
|
908
|
+
f[:type].must_equal "image/jpeg"
|
909
|
+
f[:filename].must_equal "dj.jpg"
|
910
|
+
f.must_include :tempfile
|
911
|
+
f[:tempfile].size.must_equal 76
|
912
|
+
end
|
913
|
+
|
914
|
+
it "MultipartPartLimitError when request has too many multipart file parts if limit set" do
|
915
|
+
begin
|
916
|
+
data = 10000.times.map { "--AaB03x\r\nContent-Type: text/plain\r\nContent-Disposition: attachment; name=#{SecureRandom.hex(10)}; filename=#{SecureRandom.hex(10)}\r\n\r\ncontents\r\n" }.join("\r\n")
|
917
|
+
data += "--AaB03x--\r"
|
918
|
+
|
919
|
+
options = {
|
920
|
+
"CONTENT_TYPE" => "multipart/form-data; boundary=AaB03x",
|
921
|
+
"CONTENT_LENGTH" => data.length.to_s,
|
922
|
+
:input => StringIO.new(data)
|
923
|
+
}
|
924
|
+
|
925
|
+
request = make_request Rack::MockRequest.env_for("/", options)
|
926
|
+
lambda { request.POST }.must_raise Rack::Multipart::MultipartPartLimitError
|
927
|
+
end
|
928
|
+
end
|
929
|
+
|
930
|
+
it "MultipartPartLimitError when request has too many multipart total parts if limit set" do
|
931
|
+
begin
|
932
|
+
data = 10000.times.map { "--AaB03x\r\ncontent-type: text/plain\r\ncontent-disposition: attachment; name=#{SecureRandom.hex(10)}\r\n\r\ncontents\r\n" }.join("\r\n")
|
933
|
+
data += "--AaB03x--\r"
|
934
|
+
|
935
|
+
options = {
|
936
|
+
"CONTENT_TYPE" => "multipart/form-data; boundary=AaB03x",
|
937
|
+
"CONTENT_LENGTH" => data.length.to_s,
|
938
|
+
:input => StringIO.new(data)
|
939
|
+
}
|
940
|
+
|
941
|
+
request = make_request Rack::MockRequest.env_for("/", options)
|
942
|
+
lambda { request.POST }.must_raise Rack::Multipart::MultipartTotalPartLimitError
|
943
|
+
end
|
762
944
|
end
|
763
945
|
|
764
|
-
|
946
|
+
it 'closes tempfiles it created in the case of too many created' do
|
765
947
|
begin
|
766
948
|
data = 10000.times.map { "--AaB03x\r\nContent-Type: text/plain\r\nContent-Disposition: attachment; name=#{SecureRandom.hex(10)}; filename=#{SecureRandom.hex(10)}\r\n\r\ncontents\r\n" }.join("\r\n")
|
767
949
|
data += "--AaB03x--\r"
|
768
950
|
|
951
|
+
files = []
|
769
952
|
options = {
|
770
953
|
"CONTENT_TYPE" => "multipart/form-data; boundary=AaB03x",
|
771
954
|
"CONTENT_LENGTH" => data.length.to_s,
|
955
|
+
Rack::RACK_MULTIPART_TEMPFILE_FACTORY => lambda { |filename, content_type|
|
956
|
+
file = Tempfile.new(["RackMultipart", ::File.extname(filename)])
|
957
|
+
files << file
|
958
|
+
file
|
959
|
+
},
|
772
960
|
:input => StringIO.new(data)
|
773
961
|
}
|
774
962
|
|
775
|
-
request =
|
776
|
-
|
963
|
+
request = make_request Rack::MockRequest.env_for("/", options)
|
964
|
+
assert_raises(Rack::Multipart::MultipartPartLimitError) do
|
965
|
+
request.POST
|
966
|
+
end
|
967
|
+
refute_predicate files, :empty?
|
968
|
+
files.each { |f| assert_predicate f, :closed? }
|
777
969
|
end
|
778
970
|
end
|
779
971
|
|
780
|
-
|
972
|
+
it "parse big multipart form data" do
|
781
973
|
input = <<EOF
|
782
974
|
--AaB03x\r
|
783
975
|
content-disposition: form-data; name="huge"; filename="huge"\r
|
@@ -789,17 +981,17 @@ content-disposition: form-data; name="mean"; filename="mean"\r
|
|
789
981
|
--AaB03xha\r
|
790
982
|
--AaB03x--\r
|
791
983
|
EOF
|
792
|
-
req =
|
984
|
+
req = make_request Rack::MockRequest.env_for("/",
|
793
985
|
"CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
|
794
986
|
"CONTENT_LENGTH" => input.size,
|
795
987
|
:input => input)
|
796
988
|
|
797
|
-
req.POST["huge"][:tempfile].size.
|
798
|
-
req.POST["mean"][:tempfile].size.
|
799
|
-
req.POST["mean"][:tempfile].read.
|
989
|
+
req.POST["huge"][:tempfile].size.must_equal 32768
|
990
|
+
req.POST["mean"][:tempfile].size.must_equal 10
|
991
|
+
req.POST["mean"][:tempfile].read.must_equal "--AaB03xha"
|
800
992
|
end
|
801
993
|
|
802
|
-
|
994
|
+
it "record tempfiles from multipart form data in env[rack.tempfiles]" do
|
803
995
|
input = <<EOF
|
804
996
|
--AaB03x\r
|
805
997
|
content-disposition: form-data; name="fileupload"; filename="foo.jpg"\r
|
@@ -819,22 +1011,22 @@ EOF
|
|
819
1011
|
"CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
|
820
1012
|
"CONTENT_LENGTH" => input.size,
|
821
1013
|
:input => input)
|
822
|
-
req =
|
1014
|
+
req = make_request(env)
|
823
1015
|
req.params
|
824
|
-
env['rack.tempfiles'].size.
|
1016
|
+
env['rack.tempfiles'].size.must_equal 2
|
825
1017
|
end
|
826
1018
|
|
827
|
-
|
1019
|
+
it "detect invalid multipart form data" do
|
828
1020
|
input = <<EOF
|
829
1021
|
--AaB03x\r
|
830
1022
|
content-disposition: form-data; name="huge"; filename="huge"\r
|
831
1023
|
EOF
|
832
|
-
req =
|
1024
|
+
req = make_request Rack::MockRequest.env_for("/",
|
833
1025
|
"CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
|
834
1026
|
"CONTENT_LENGTH" => input.size,
|
835
1027
|
:input => input)
|
836
1028
|
|
837
|
-
lambda { req.POST }.
|
1029
|
+
lambda { req.POST }.must_raise EOFError
|
838
1030
|
|
839
1031
|
input = <<EOF
|
840
1032
|
--AaB03x\r
|
@@ -842,12 +1034,12 @@ content-disposition: form-data; name="huge"; filename="huge"\r
|
|
842
1034
|
\r
|
843
1035
|
foo\r
|
844
1036
|
EOF
|
845
|
-
req =
|
1037
|
+
req = make_request Rack::MockRequest.env_for("/",
|
846
1038
|
"CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
|
847
1039
|
"CONTENT_LENGTH" => input.size,
|
848
1040
|
:input => input)
|
849
1041
|
|
850
|
-
lambda { req.POST }.
|
1042
|
+
lambda { req.POST }.must_raise EOFError
|
851
1043
|
|
852
1044
|
input = <<EOF
|
853
1045
|
--AaB03x\r
|
@@ -855,29 +1047,29 @@ content-disposition: form-data; name="huge"; filename="huge"\r
|
|
855
1047
|
\r
|
856
1048
|
foo\r
|
857
1049
|
EOF
|
858
|
-
req =
|
1050
|
+
req = make_request Rack::MockRequest.env_for("/",
|
859
1051
|
"CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
|
860
1052
|
"CONTENT_LENGTH" => input.size,
|
861
1053
|
:input => input)
|
862
1054
|
|
863
|
-
lambda { req.POST }.
|
1055
|
+
lambda { req.POST }.must_raise EOFError
|
864
1056
|
end
|
865
1057
|
|
866
|
-
|
1058
|
+
it "consistently raise EOFError on bad multipart form data" do
|
867
1059
|
input = <<EOF
|
868
1060
|
--AaB03x\r
|
869
1061
|
content-disposition: form-data; name="huge"; filename="huge"\r
|
870
1062
|
EOF
|
871
|
-
req =
|
1063
|
+
req = make_request Rack::MockRequest.env_for("/",
|
872
1064
|
"CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
|
873
1065
|
"CONTENT_LENGTH" => input.size,
|
874
1066
|
:input => input)
|
875
1067
|
|
876
|
-
lambda { req.POST }.
|
877
|
-
lambda { req.POST }.
|
1068
|
+
lambda { req.POST }.must_raise EOFError
|
1069
|
+
lambda { req.POST }.must_raise EOFError
|
878
1070
|
end
|
879
1071
|
|
880
|
-
|
1072
|
+
it "correctly parse the part name from Content-Id header" do
|
881
1073
|
input = <<EOF
|
882
1074
|
--AaB03x\r
|
883
1075
|
Content-Type: text/xml; charset=utf-8\r
|
@@ -887,20 +1079,15 @@ Content-Transfer-Encoding: 7bit\r
|
|
887
1079
|
foo\r
|
888
1080
|
--AaB03x--\r
|
889
1081
|
EOF
|
890
|
-
req =
|
1082
|
+
req = make_request Rack::MockRequest.env_for("/",
|
891
1083
|
"CONTENT_TYPE" => "multipart/related, boundary=AaB03x",
|
892
1084
|
"CONTENT_LENGTH" => input.size,
|
893
1085
|
:input => input)
|
894
1086
|
|
895
|
-
req.params.keys.
|
1087
|
+
req.params.keys.must_equal ["<soap-start>"]
|
896
1088
|
end
|
897
1089
|
|
898
|
-
|
899
|
-
if /regexp/.respond_to?(:kcode) # < 1.9
|
900
|
-
begin
|
901
|
-
original_kcode = $KCODE
|
902
|
-
$KCODE='UTF8'
|
903
|
-
|
1090
|
+
it "not try to interpret binary as utf8" do
|
904
1091
|
input = <<EOF
|
905
1092
|
--AaB03x\r
|
906
1093
|
content-disposition: form-data; name="fileupload"; filename="junk.a"\r
|
@@ -910,77 +1097,33 @@ content-type: application/octet-stream\r
|
|
910
1097
|
--AaB03x--\r
|
911
1098
|
EOF
|
912
1099
|
|
913
|
-
req =
|
1100
|
+
req = make_request Rack::MockRequest.env_for("/",
|
914
1101
|
"CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
|
915
1102
|
"CONTENT_LENGTH" => input.size,
|
916
1103
|
:input => input)
|
917
1104
|
|
918
|
-
|
919
|
-
req.POST["fileupload"][:tempfile].size.should.equal 4
|
920
|
-
ensure
|
921
|
-
$KCODE = original_kcode
|
922
|
-
end
|
923
|
-
else # >= 1.9
|
924
|
-
input = <<EOF
|
925
|
-
--AaB03x\r
|
926
|
-
content-disposition: form-data; name="fileupload"; filename="junk.a"\r
|
927
|
-
content-type: application/octet-stream\r
|
928
|
-
\r
|
929
|
-
#{[0x36,0xCF,0x0A,0xF8].pack('c*')}\r
|
930
|
-
--AaB03x--\r
|
931
|
-
EOF
|
932
|
-
|
933
|
-
req = Rack::Request.new Rack::MockRequest.env_for("/",
|
934
|
-
"CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
|
935
|
-
"CONTENT_LENGTH" => input.size,
|
936
|
-
:input => input)
|
937
|
-
|
938
|
-
lambda{req.POST}.should.not.raise(EOFError)
|
939
|
-
req.POST["fileupload"][:tempfile].size.should.equal 4
|
940
|
-
end
|
1105
|
+
req.POST["fileupload"][:tempfile].size.must_equal 4
|
941
1106
|
end
|
942
1107
|
|
943
|
-
|
944
|
-
input = <<EOF
|
945
|
-
--AaB03x\r
|
946
|
-
content-disposition: form-data; name="huge"; filename="huge"\r
|
947
|
-
\r
|
948
|
-
foo\r
|
949
|
-
--AaB03x--
|
950
|
-
EOF
|
951
|
-
|
952
|
-
rack_input = Tempfile.new("rackspec")
|
953
|
-
rack_input.write(input)
|
954
|
-
rack_input.rewind
|
955
|
-
|
956
|
-
req = Rack::Request.new Rack::MockRequest.env_for("/",
|
957
|
-
"CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
|
958
|
-
"CONTENT_LENGTH" => input.size,
|
959
|
-
:input => rack_input)
|
960
|
-
|
961
|
-
lambda{ req.POST }.should.not.raise
|
962
|
-
lambda{ req.POST }.should.not.raise("input re-processed!")
|
963
|
-
end
|
964
|
-
|
965
|
-
should "use form_hash when form_input is a Tempfile" do
|
1108
|
+
it "use form_hash when form_input is a Tempfile" do
|
966
1109
|
input = "{foo: 'bar'}"
|
967
1110
|
|
968
1111
|
rack_input = Tempfile.new("rackspec")
|
969
1112
|
rack_input.write(input)
|
970
1113
|
rack_input.rewind
|
971
1114
|
|
972
|
-
req =
|
1115
|
+
req = make_request Rack::MockRequest.env_for("/",
|
973
1116
|
"rack.request.form_hash" => {'foo' => 'bar'},
|
974
1117
|
"rack.request.form_input" => rack_input,
|
975
1118
|
:input => rack_input)
|
976
1119
|
|
977
|
-
req.POST.
|
1120
|
+
req.POST.must_equal req.env['rack.request.form_hash']
|
978
1121
|
end
|
979
1122
|
|
980
|
-
|
1123
|
+
it "conform to the Rack spec" do
|
981
1124
|
app = lambda { |env|
|
982
|
-
content =
|
983
|
-
size = content.
|
1125
|
+
content = make_request(env).POST["file"].inspect
|
1126
|
+
size = content.bytesize
|
984
1127
|
[200, {"Content-Type" => "text/html", "Content-Length" => size.to_s}, [content]]
|
985
1128
|
}
|
986
1129
|
|
@@ -997,149 +1140,151 @@ Content-Transfer-Encoding: base64\r
|
|
997
1140
|
/9j/4AAQSkZJRgABAQAAAQABAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcg\r
|
998
1141
|
--AaB03x--\r
|
999
1142
|
EOF
|
1000
|
-
input.force_encoding(
|
1143
|
+
input.force_encoding(Encoding::ASCII_8BIT)
|
1001
1144
|
res = Rack::MockRequest.new(Rack::Lint.new(app)).get "/",
|
1002
1145
|
"CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
|
1003
1146
|
"CONTENT_LENGTH" => input.size.to_s, "rack.input" => StringIO.new(input)
|
1004
1147
|
|
1005
|
-
res.
|
1148
|
+
res.must_be :ok?
|
1006
1149
|
end
|
1007
1150
|
|
1008
|
-
|
1151
|
+
it "parse Accept-Encoding correctly" do
|
1009
1152
|
parser = lambda do |x|
|
1010
|
-
|
1153
|
+
make_request(Rack::MockRequest.env_for("", "HTTP_ACCEPT_ENCODING" => x)).accept_encoding
|
1011
1154
|
end
|
1012
1155
|
|
1013
|
-
parser.call(nil).
|
1156
|
+
parser.call(nil).must_equal []
|
1014
1157
|
|
1015
|
-
parser.call("compress, gzip").
|
1016
|
-
parser.call("").
|
1017
|
-
parser.call("*").
|
1018
|
-
parser.call("compress;q=0.5, gzip;q=1.0").
|
1019
|
-
parser.call("gzip;q=1.0, identity; q=0.5, *;q=0").
|
1158
|
+
parser.call("compress, gzip").must_equal [["compress", 1.0], ["gzip", 1.0]]
|
1159
|
+
parser.call("").must_equal []
|
1160
|
+
parser.call("*").must_equal [["*", 1.0]]
|
1161
|
+
parser.call("compress;q=0.5, gzip;q=1.0").must_equal [["compress", 0.5], ["gzip", 1.0]]
|
1162
|
+
parser.call("gzip;q=1.0, identity; q=0.5, *;q=0").must_equal [["gzip", 1.0], ["identity", 0.5], ["*", 0] ]
|
1020
1163
|
|
1021
|
-
parser.call("gzip ; q=0.9").
|
1022
|
-
parser.call("gzip ; deflate").
|
1164
|
+
parser.call("gzip ; q=0.9").must_equal [["gzip", 0.9]]
|
1165
|
+
parser.call("gzip ; deflate").must_equal [["gzip", 1.0]]
|
1023
1166
|
end
|
1024
1167
|
|
1025
|
-
|
1168
|
+
it "parse Accept-Language correctly" do
|
1026
1169
|
parser = lambda do |x|
|
1027
|
-
|
1170
|
+
make_request(Rack::MockRequest.env_for("", "HTTP_ACCEPT_LANGUAGE" => x)).accept_language
|
1028
1171
|
end
|
1029
1172
|
|
1030
|
-
parser.call(nil).
|
1173
|
+
parser.call(nil).must_equal []
|
1031
1174
|
|
1032
|
-
parser.call("fr, en").
|
1033
|
-
parser.call("").
|
1034
|
-
parser.call("*").
|
1035
|
-
parser.call("fr;q=0.5, en;q=1.0").
|
1036
|
-
parser.call("fr;q=1.0, en; q=0.5, *;q=0").
|
1175
|
+
parser.call("fr, en").must_equal [["fr", 1.0], ["en", 1.0]]
|
1176
|
+
parser.call("").must_equal []
|
1177
|
+
parser.call("*").must_equal [["*", 1.0]]
|
1178
|
+
parser.call("fr;q=0.5, en;q=1.0").must_equal [["fr", 0.5], ["en", 1.0]]
|
1179
|
+
parser.call("fr;q=1.0, en; q=0.5, *;q=0").must_equal [["fr", 1.0], ["en", 0.5], ["*", 0] ]
|
1037
1180
|
|
1038
|
-
parser.call("fr ; q=0.9").
|
1039
|
-
parser.call("fr").
|
1181
|
+
parser.call("fr ; q=0.9").must_equal [["fr", 0.9]]
|
1182
|
+
parser.call("fr").must_equal [["fr", 1.0]]
|
1040
1183
|
end
|
1041
1184
|
|
1042
|
-
ip_app
|
1043
|
-
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
1185
|
+
def ip_app
|
1186
|
+
lambda { |env|
|
1187
|
+
request = make_request(env)
|
1188
|
+
response = Rack::Response.new
|
1189
|
+
response.write request.ip
|
1190
|
+
response.finish
|
1191
|
+
}
|
1192
|
+
end
|
1048
1193
|
|
1049
|
-
|
1194
|
+
it 'provide ip information' do
|
1050
1195
|
mock = Rack::MockRequest.new(Rack::Lint.new(ip_app))
|
1051
1196
|
|
1052
1197
|
res = mock.get '/', 'REMOTE_ADDR' => '1.2.3.4'
|
1053
|
-
res.body.
|
1198
|
+
res.body.must_equal '1.2.3.4'
|
1054
1199
|
|
1055
1200
|
res = mock.get '/', 'REMOTE_ADDR' => 'fe80::202:b3ff:fe1e:8329'
|
1056
|
-
res.body.
|
1201
|
+
res.body.must_equal 'fe80::202:b3ff:fe1e:8329'
|
1057
1202
|
|
1058
1203
|
res = mock.get '/', 'REMOTE_ADDR' => '1.2.3.4,3.4.5.6'
|
1059
|
-
res.body.
|
1204
|
+
res.body.must_equal '1.2.3.4'
|
1060
1205
|
end
|
1061
1206
|
|
1062
|
-
|
1207
|
+
it 'deals with proxies' do
|
1063
1208
|
mock = Rack::MockRequest.new(Rack::Lint.new(ip_app))
|
1064
1209
|
|
1065
1210
|
res = mock.get '/',
|
1066
1211
|
'REMOTE_ADDR' => '1.2.3.4',
|
1067
1212
|
'HTTP_X_FORWARDED_FOR' => '3.4.5.6'
|
1068
|
-
res.body.
|
1213
|
+
res.body.must_equal '1.2.3.4'
|
1069
1214
|
|
1070
1215
|
res = mock.get '/',
|
1071
1216
|
'REMOTE_ADDR' => '1.2.3.4',
|
1072
1217
|
'HTTP_X_FORWARDED_FOR' => 'unknown'
|
1073
|
-
res.body.
|
1218
|
+
res.body.must_equal '1.2.3.4'
|
1074
1219
|
|
1075
1220
|
res = mock.get '/',
|
1076
1221
|
'REMOTE_ADDR' => '127.0.0.1',
|
1077
1222
|
'HTTP_X_FORWARDED_FOR' => '3.4.5.6'
|
1078
|
-
res.body.
|
1223
|
+
res.body.must_equal '3.4.5.6'
|
1079
1224
|
|
1080
1225
|
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => 'unknown,3.4.5.6'
|
1081
|
-
res.body.
|
1226
|
+
res.body.must_equal '3.4.5.6'
|
1082
1227
|
|
1083
1228
|
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '192.168.0.1,3.4.5.6'
|
1084
|
-
res.body.
|
1229
|
+
res.body.must_equal '3.4.5.6'
|
1085
1230
|
|
1086
1231
|
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '10.0.0.1,3.4.5.6'
|
1087
|
-
res.body.
|
1232
|
+
res.body.must_equal '3.4.5.6'
|
1088
1233
|
|
1089
1234
|
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '10.0.0.1, 10.0.0.1, 3.4.5.6'
|
1090
|
-
res.body.
|
1235
|
+
res.body.must_equal '3.4.5.6'
|
1091
1236
|
|
1092
1237
|
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '127.0.0.1, 3.4.5.6'
|
1093
|
-
res.body.
|
1238
|
+
res.body.must_equal '3.4.5.6'
|
1094
1239
|
|
1095
1240
|
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => 'unknown,192.168.0.1'
|
1096
|
-
res.body.
|
1241
|
+
res.body.must_equal 'unknown'
|
1097
1242
|
|
1098
1243
|
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => 'other,unknown,192.168.0.1'
|
1099
|
-
res.body.
|
1244
|
+
res.body.must_equal 'unknown'
|
1100
1245
|
|
1101
1246
|
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => 'unknown,localhost,192.168.0.1'
|
1102
|
-
res.body.
|
1247
|
+
res.body.must_equal 'unknown'
|
1103
1248
|
|
1104
1249
|
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '9.9.9.9, 3.4.5.6, 10.0.0.1, 172.31.4.4'
|
1105
|
-
res.body.
|
1250
|
+
res.body.must_equal '3.4.5.6'
|
1106
1251
|
|
1107
1252
|
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '::1,2620:0:1c00:0:812c:9583:754b:ca11'
|
1108
|
-
res.body.
|
1253
|
+
res.body.must_equal '2620:0:1c00:0:812c:9583:754b:ca11'
|
1109
1254
|
|
1110
1255
|
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '2620:0:1c00:0:812c:9583:754b:ca11,::1'
|
1111
|
-
res.body.
|
1256
|
+
res.body.must_equal '2620:0:1c00:0:812c:9583:754b:ca11'
|
1112
1257
|
|
1113
1258
|
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => 'fd5b:982e:9130:247f:0000:0000:0000:0000,2620:0:1c00:0:812c:9583:754b:ca11'
|
1114
|
-
res.body.
|
1259
|
+
res.body.must_equal '2620:0:1c00:0:812c:9583:754b:ca11'
|
1115
1260
|
|
1116
1261
|
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '2620:0:1c00:0:812c:9583:754b:ca11,fd5b:982e:9130:247f:0000:0000:0000:0000'
|
1117
|
-
res.body.
|
1262
|
+
res.body.must_equal '2620:0:1c00:0:812c:9583:754b:ca11'
|
1118
1263
|
|
1119
1264
|
res = mock.get '/',
|
1120
1265
|
'HTTP_X_FORWARDED_FOR' => '1.1.1.1, 127.0.0.1',
|
1121
1266
|
'HTTP_CLIENT_IP' => '1.1.1.1'
|
1122
|
-
res.body.
|
1267
|
+
res.body.must_equal '1.1.1.1'
|
1123
1268
|
|
1124
1269
|
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '8.8.8.8, 9.9.9.9'
|
1125
|
-
res.body.
|
1270
|
+
res.body.must_equal '9.9.9.9'
|
1126
1271
|
|
1127
1272
|
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '8.8.8.8, fe80::202:b3ff:fe1e:8329'
|
1128
|
-
res.body.
|
1273
|
+
res.body.must_equal 'fe80::202:b3ff:fe1e:8329'
|
1129
1274
|
|
1130
1275
|
# Unix Sockets
|
1131
1276
|
res = mock.get '/',
|
1132
1277
|
'REMOTE_ADDR' => 'unix',
|
1133
1278
|
'HTTP_X_FORWARDED_FOR' => '3.4.5.6'
|
1134
|
-
res.body.
|
1279
|
+
res.body.must_equal '3.4.5.6'
|
1135
1280
|
|
1136
1281
|
res = mock.get '/',
|
1137
1282
|
'REMOTE_ADDR' => 'unix:/tmp/foo',
|
1138
1283
|
'HTTP_X_FORWARDED_FOR' => '3.4.5.6'
|
1139
|
-
res.body.
|
1284
|
+
res.body.must_equal '3.4.5.6'
|
1140
1285
|
end
|
1141
1286
|
|
1142
|
-
|
1287
|
+
it "not allow IP spoofing via Client-IP and X-Forwarded-For headers" do
|
1143
1288
|
mock = Rack::MockRequest.new(Rack::Lint.new(ip_app))
|
1144
1289
|
|
1145
1290
|
# IP Spoofing attempt:
|
@@ -1154,31 +1299,45 @@ EOF
|
|
1154
1299
|
res = mock.get '/',
|
1155
1300
|
'HTTP_X_FORWARDED_FOR' => '6.6.6.6, 2.2.2.3, 192.168.0.7',
|
1156
1301
|
'HTTP_CLIENT_IP' => '6.6.6.6'
|
1157
|
-
res.body.
|
1158
|
-
end
|
1159
|
-
|
1160
|
-
|
1161
|
-
|
1162
|
-
|
1163
|
-
|
1164
|
-
|
1165
|
-
|
1166
|
-
|
1167
|
-
|
1168
|
-
|
1169
|
-
|
1170
|
-
req.
|
1171
|
-
req.trusted_proxy?('
|
1172
|
-
req.trusted_proxy?('
|
1173
|
-
req.trusted_proxy?('
|
1174
|
-
|
1175
|
-
req.trusted_proxy?(
|
1176
|
-
req.trusted_proxy?(
|
1177
|
-
req.trusted_proxy?(
|
1178
|
-
req.trusted_proxy?(
|
1179
|
-
req.trusted_proxy?(
|
1180
|
-
req.trusted_proxy?(
|
1181
|
-
req.trusted_proxy?(
|
1302
|
+
res.body.must_equal '2.2.2.3'
|
1303
|
+
end
|
1304
|
+
|
1305
|
+
it "preserves ip for trusted proxy chain" do
|
1306
|
+
mock = Rack::MockRequest.new(Rack::Lint.new(ip_app))
|
1307
|
+
res = mock.get '/',
|
1308
|
+
'HTTP_X_FORWARDED_FOR' => '192.168.0.11, 192.168.0.7',
|
1309
|
+
'HTTP_CLIENT_IP' => '127.0.0.1'
|
1310
|
+
res.body.must_equal '192.168.0.11'
|
1311
|
+
|
1312
|
+
end
|
1313
|
+
|
1314
|
+
it "regards local addresses as proxies" do
|
1315
|
+
req = make_request(Rack::MockRequest.env_for("/"))
|
1316
|
+
req.trusted_proxy?('127.0.0.1').must_equal 0
|
1317
|
+
req.trusted_proxy?('10.0.0.1').must_equal 0
|
1318
|
+
req.trusted_proxy?('172.16.0.1').must_equal 0
|
1319
|
+
req.trusted_proxy?('172.20.0.1').must_equal 0
|
1320
|
+
req.trusted_proxy?('172.30.0.1').must_equal 0
|
1321
|
+
req.trusted_proxy?('172.31.0.1').must_equal 0
|
1322
|
+
req.trusted_proxy?('192.168.0.1').must_equal 0
|
1323
|
+
req.trusted_proxy?('::1').must_equal 0
|
1324
|
+
req.trusted_proxy?('fd00::').must_equal 0
|
1325
|
+
req.trusted_proxy?('localhost').must_equal 0
|
1326
|
+
req.trusted_proxy?('unix').must_equal 0
|
1327
|
+
req.trusted_proxy?('unix:/tmp/sock').must_equal 0
|
1328
|
+
|
1329
|
+
req.trusted_proxy?("unix.example.org").must_be_nil
|
1330
|
+
req.trusted_proxy?("example.org\n127.0.0.1").must_be_nil
|
1331
|
+
req.trusted_proxy?("127.0.0.1\nexample.org").must_be_nil
|
1332
|
+
req.trusted_proxy?("11.0.0.1").must_be_nil
|
1333
|
+
req.trusted_proxy?("172.15.0.1").must_be_nil
|
1334
|
+
req.trusted_proxy?("172.32.0.1").must_be_nil
|
1335
|
+
req.trusted_proxy?("2001:470:1f0b:18f8::1").must_be_nil
|
1336
|
+
end
|
1337
|
+
|
1338
|
+
it "sets the default session to an empty hash" do
|
1339
|
+
req = make_request(Rack::MockRequest.env_for("http://example.com:8080/"))
|
1340
|
+
assert_equal Hash.new, req.session
|
1182
1341
|
end
|
1183
1342
|
|
1184
1343
|
class MyRequest < Rack::Request
|
@@ -1187,46 +1346,78 @@ EOF
|
|
1187
1346
|
end
|
1188
1347
|
end
|
1189
1348
|
|
1190
|
-
|
1349
|
+
it "allow subclass request to be instantiated after parent request" do
|
1191
1350
|
env = Rack::MockRequest.env_for("/?foo=bar")
|
1192
1351
|
|
1193
|
-
req1 =
|
1194
|
-
req1.GET.
|
1195
|
-
req1.params.
|
1352
|
+
req1 = make_request(env)
|
1353
|
+
req1.GET.must_equal "foo" => "bar"
|
1354
|
+
req1.params.must_equal "foo" => "bar"
|
1196
1355
|
|
1197
1356
|
req2 = MyRequest.new(env)
|
1198
|
-
req2.GET.
|
1199
|
-
req2.params.
|
1357
|
+
req2.GET.must_equal "foo" => "bar"
|
1358
|
+
req2.params.must_equal :foo => "bar"
|
1200
1359
|
end
|
1201
1360
|
|
1202
|
-
|
1361
|
+
it "allow parent request to be instantiated after subclass request" do
|
1203
1362
|
env = Rack::MockRequest.env_for("/?foo=bar")
|
1204
1363
|
|
1205
1364
|
req1 = MyRequest.new(env)
|
1206
|
-
req1.GET.
|
1207
|
-
req1.params.
|
1365
|
+
req1.GET.must_equal "foo" => "bar"
|
1366
|
+
req1.params.must_equal :foo => "bar"
|
1208
1367
|
|
1209
|
-
req2 =
|
1210
|
-
req2.GET.
|
1211
|
-
req2.params.
|
1368
|
+
req2 = make_request(env)
|
1369
|
+
req2.GET.must_equal "foo" => "bar"
|
1370
|
+
req2.params.must_equal "foo" => "bar"
|
1212
1371
|
end
|
1213
1372
|
|
1214
|
-
|
1373
|
+
it "raise TypeError every time if request parameters are broken" do
|
1215
1374
|
broken_query = Rack::MockRequest.env_for("/?foo%5B%5D=0&foo%5Bbar%5D=1")
|
1216
|
-
req =
|
1217
|
-
lambda{req.GET}.
|
1218
|
-
lambda{req.params}.
|
1375
|
+
req = make_request(broken_query)
|
1376
|
+
lambda{req.GET}.must_raise TypeError
|
1377
|
+
lambda{req.params}.must_raise TypeError
|
1219
1378
|
end
|
1220
1379
|
|
1221
1380
|
(0x20...0x7E).collect { |a|
|
1222
1381
|
b = a.chr
|
1223
1382
|
c = CGI.escape(b)
|
1224
|
-
|
1383
|
+
it "not strip '#{a}' => '#{c}' => '#{b}' escaped character from parameters when accessed as string" do
|
1225
1384
|
url = "/?foo=#{c}bar#{c}"
|
1226
1385
|
env = Rack::MockRequest.env_for(url)
|
1227
|
-
req2 =
|
1228
|
-
req2.GET.
|
1229
|
-
req2.params.
|
1386
|
+
req2 = make_request(env)
|
1387
|
+
req2.GET.must_equal "foo" => "#{b}bar#{b}"
|
1388
|
+
req2.params.must_equal "foo" => "#{b}bar#{b}"
|
1230
1389
|
end
|
1231
1390
|
}
|
1391
|
+
|
1392
|
+
class NonDelegate < Rack::Request
|
1393
|
+
def delegate?; false; end
|
1394
|
+
end
|
1395
|
+
|
1396
|
+
def make_request(env)
|
1397
|
+
NonDelegate.new env
|
1398
|
+
end
|
1399
|
+
|
1400
|
+
class TestProxyRequest < RackRequestTest
|
1401
|
+
class DelegateRequest
|
1402
|
+
include Rack::Request::Helpers
|
1403
|
+
extend Forwardable
|
1404
|
+
|
1405
|
+
def_delegators :@req, :has_header?, :get_header, :fetch_header,
|
1406
|
+
:each_header, :set_header, :add_header, :delete_header
|
1407
|
+
|
1408
|
+
def_delegators :@req, :[], :[]=, :values_at
|
1409
|
+
|
1410
|
+
def initialize(req)
|
1411
|
+
@req = req
|
1412
|
+
end
|
1413
|
+
|
1414
|
+
def delegate?; true; end
|
1415
|
+
|
1416
|
+
def env; @req.env.dup; end
|
1417
|
+
end
|
1418
|
+
|
1419
|
+
def make_request(env)
|
1420
|
+
DelegateRequest.new super(env)
|
1421
|
+
end
|
1422
|
+
end
|
1232
1423
|
end
|