rack 1.6.13 → 2.0.1
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 +5 -5
- data/COPYING +1 -1
- data/HISTORY.md +138 -8
- data/README.rdoc +17 -25
- data/Rakefile +6 -14
- data/SPEC +8 -9
- 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} +3 -3
- data/lib/rack/{conditionalget.rb → conditional_get.rb} +0 -0
- data/lib/rack/content_length.rb +2 -2
- data/lib/rack/deflater.rb +4 -4
- data/lib/rack/directory.rb +66 -54
- data/lib/rack/etag.rb +4 -3
- data/lib/rack/events.rb +154 -0
- data/lib/rack/file.rb +63 -39
- 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 +22 -24
- data/lib/rack/handler.rb +3 -25
- data/lib/rack/head.rb +15 -17
- data/lib/rack/lint.rb +38 -38
- data/lib/rack/lobster.rb +1 -1
- data/lib/rack/lock.rb +6 -10
- data/lib/rack/logger.rb +2 -2
- data/lib/rack/media_type.rb +38 -0
- data/lib/rack/{methodoverride.rb → method_override.rb} +4 -11
- data/lib/rack/mime.rb +18 -5
- data/lib/rack/mock.rb +35 -53
- data/lib/rack/multipart/generator.rb +5 -5
- data/lib/rack/multipart/parser.rb +272 -158
- data/lib/rack/multipart/uploaded_file.rb +1 -2
- data/lib/rack/multipart.rb +35 -6
- 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 +383 -307
- data/lib/rack/response.rb +129 -56
- 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 +31 -25
- data/lib/rack/session/abstract/id.rb +95 -135
- data/lib/rack/session/cookie.rb +26 -28
- data/lib/rack/session/memcache.rb +8 -14
- data/lib/rack/session/pool.rb +14 -21
- 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 +135 -210
- data/lib/rack.rb +70 -21
- data/rack.gemspec +7 -5
- 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_null_byte → filename_with_single_quote} +1 -1
- 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 +36 -34
- data/test/{spec_commonlogger.rb → spec_common_logger.rb} +23 -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 +66 -40
- 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 +107 -77
- data/test/spec_handler.rb +19 -34
- data/test/spec_head.rb +15 -14
- data/test/spec_lint.rb +162 -197
- data/test/spec_lobster.rb +24 -23
- data/test/spec_lock.rb +69 -39
- data/test/spec_logger.rb +4 -3
- data/test/spec_media_type.rb +42 -0
- data/test/spec_method_override.rb +83 -0
- data/test/spec_mime.rb +19 -19
- data/test/spec_mock.rb +196 -151
- data/test/spec_multipart.rb +317 -201
- data/test/{spec_nulllogger.rb → spec_null_logger.rb} +5 -4
- data/test/spec_recursive.rb +17 -14
- data/test/spec_request.rb +768 -607
- data/test/spec_response.rb +214 -111
- 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 +28 -0
- data/test/spec_session_cookie.rb +97 -65
- data/test/spec_session_memcache.rb +63 -101
- data/test/spec_session_pool.rb +48 -84
- data/test/spec_show_exceptions.rb +80 -0
- 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 +91 -67
- 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 +103 -69
- 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_methodoverride.rb +0 -111
- data/test/spec_mongrel.rb +0 -182
- data/test/spec_session_persisted_secure_secure_session_hash.rb +0 -73
- data/test/spec_showexceptions.rb +0 -98
data/test/spec_request.rb
CHANGED
@@ -1,574 +1,719 @@
|
|
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
|
34
|
+
|
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
|
39
|
+
|
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
|
47
|
+
|
48
|
+
assert yielded
|
49
|
+
assert_equal "bar", req.get_header("FOO")
|
50
|
+
end
|
10
51
|
|
11
|
-
|
12
|
-
req.
|
13
|
-
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
|
61
|
+
|
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")
|
66
|
+
end
|
14
67
|
|
15
|
-
|
16
|
-
req.
|
17
|
-
req.should.not.be.put
|
18
|
-
req.should.not.be.delete
|
19
|
-
req.should.not.be.head
|
20
|
-
req.should.not.be.patch
|
68
|
+
it 'can add to multivalued headers in the env' do
|
69
|
+
req = make_request(Rack::MockRequest.env_for('http://example.com:8080/'))
|
21
70
|
|
22
|
-
req.
|
23
|
-
req.
|
24
|
-
req.query_string.should.equal ""
|
71
|
+
assert_equal '1', req.add_header('FOO', '1')
|
72
|
+
assert_equal '1', req.get_header('FOO')
|
25
73
|
|
26
|
-
req.
|
27
|
-
req.
|
74
|
+
assert_equal '1,2', req.add_header('FOO', '2')
|
75
|
+
assert_equal '1,2', req.get_header('FOO')
|
28
76
|
|
29
|
-
req.
|
30
|
-
req.
|
77
|
+
assert_equal '1,2', req.add_header('FOO', nil)
|
78
|
+
assert_equal '1,2', req.get_header('FOO')
|
31
79
|
end
|
32
80
|
|
33
|
-
|
34
|
-
req = Rack::
|
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
|
284
|
+
mr = Rack::MockRequest.env_for("/?foo=quux",
|
285
|
+
"REQUEST_METHOD" => 'POST',
|
286
|
+
:input => "foo=bar&quux=bla"
|
287
|
+
)
|
288
|
+
req = make_request mr
|
289
|
+
|
290
|
+
req.params
|
291
|
+
|
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)
|
295
|
+
end
|
296
|
+
|
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
|
182
310
|
mr = Rack::MockRequest.env_for("/?foo=quux",
|
183
311
|
"REQUEST_METHOD" => 'POST',
|
184
312
|
:input => "foo=bar&quux=bla"
|
185
313
|
)
|
186
|
-
req =
|
314
|
+
req = c.new mr
|
187
315
|
|
188
316
|
req.params
|
189
317
|
|
190
|
-
req.GET.
|
191
|
-
req.POST.
|
192
|
-
req.
|
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"
|
193
323
|
end
|
194
324
|
|
195
|
-
|
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"
|
283
412
|
end
|
284
413
|
|
285
|
-
|
286
|
-
|
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({})
|
426
|
+
end
|
427
|
+
|
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_equal 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_equal 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_equal 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_equal 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_equal 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.
|
394
|
-
|
395
|
-
request = Rack::Request.new(Rack::MockRequest.env_for("/", 'HTTPS' => 'on'))
|
396
|
-
request.scheme.should.equal "https"
|
397
|
-
request.should.be.ssl?
|
537
|
+
it "ssl detection" do
|
538
|
+
request = make_request(Rack::MockRequest.env_for("/"))
|
539
|
+
request.scheme.must_equal "http"
|
540
|
+
request.wont_be :ssl?
|
398
541
|
|
399
|
-
request =
|
400
|
-
request.scheme.
|
401
|
-
request.
|
542
|
+
request = make_request(Rack::MockRequest.env_for("/", 'HTTPS' => 'on'))
|
543
|
+
request.scheme.must_equal "https"
|
544
|
+
request.must_be :ssl?
|
402
545
|
|
403
|
-
request =
|
404
|
-
request.scheme.
|
405
|
-
request.
|
546
|
+
request = make_request(Rack::MockRequest.env_for("/", 'rack.url_scheme' => 'https'))
|
547
|
+
request.scheme.must_equal "https"
|
548
|
+
request.must_be :ssl?
|
406
549
|
|
407
|
-
request =
|
408
|
-
request.scheme.
|
409
|
-
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?
|
410
553
|
|
411
|
-
request =
|
412
|
-
request.scheme.
|
413
|
-
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?
|
414
557
|
|
415
|
-
request =
|
416
|
-
request.scheme.
|
417
|
-
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?
|
418
561
|
|
419
|
-
request =
|
420
|
-
request.scheme.
|
421
|
-
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?
|
422
565
|
|
423
|
-
request =
|
424
|
-
request.scheme.
|
425
|
-
request.
|
426
|
-
end
|
566
|
+
request = make_request(Rack::MockRequest.env_for("/", 'HTTP_X_FORWARDED_PROTO' => 'https'))
|
567
|
+
request.scheme.must_equal "https"
|
568
|
+
request.must_be :ssl?
|
427
569
|
|
428
|
-
|
429
|
-
request
|
430
|
-
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?
|
431
573
|
end
|
432
574
|
|
433
|
-
|
434
|
-
req =
|
575
|
+
it "parse cookies" do
|
576
|
+
req = make_request \
|
435
577
|
Rack::MockRequest.env_for("", "HTTP_COOKIE" => "foo=bar;quux=h&m")
|
436
|
-
req.cookies.
|
437
|
-
req.cookies.
|
438
|
-
req.
|
439
|
-
req.cookies.
|
578
|
+
req.cookies.must_equal "foo" => "bar", "quux" => "h&m"
|
579
|
+
req.cookies.must_equal "foo" => "bar", "quux" => "h&m"
|
580
|
+
req.delete_header("HTTP_COOKIE")
|
581
|
+
req.cookies.must_equal({})
|
440
582
|
end
|
441
583
|
|
442
|
-
|
443
|
-
req =
|
584
|
+
it "always return the same hash object" do
|
585
|
+
req = make_request \
|
444
586
|
Rack::MockRequest.env_for("", "HTTP_COOKIE" => "foo=bar;quux=h&m")
|
445
587
|
hash = req.cookies
|
446
588
|
req.env.delete("HTTP_COOKIE")
|
447
|
-
req.cookies.
|
589
|
+
req.cookies.must_equal hash
|
448
590
|
req.env["HTTP_COOKIE"] = "zoo=m"
|
449
|
-
req.cookies.
|
591
|
+
req.cookies.must_equal hash
|
450
592
|
end
|
451
593
|
|
452
|
-
|
453
|
-
req =
|
454
|
-
req.cookies.
|
594
|
+
it "modify the cookies hash in place" do
|
595
|
+
req = make_request(Rack::MockRequest.env_for(""))
|
596
|
+
req.cookies.must_equal({})
|
455
597
|
req.cookies['foo'] = 'bar'
|
456
|
-
req.cookies.
|
598
|
+
req.cookies.must_equal 'foo' => 'bar'
|
457
599
|
end
|
458
600
|
|
459
|
-
|
601
|
+
it "not modify the params hash in place" do
|
460
602
|
e = Rack::MockRequest.env_for("")
|
461
|
-
req1 =
|
462
|
-
req1.
|
603
|
+
req1 = make_request(e)
|
604
|
+
if req1.delegate?
|
605
|
+
skip "delegate requests don't cache params, so mutations have no impact"
|
606
|
+
end
|
607
|
+
req1.params.must_equal({})
|
463
608
|
req1.params['foo'] = 'bar'
|
464
|
-
req1.params.
|
465
|
-
req2 =
|
466
|
-
req2.params.
|
609
|
+
req1.params.must_equal 'foo' => 'bar'
|
610
|
+
req2 = make_request(e)
|
611
|
+
req2.params.must_equal({})
|
467
612
|
end
|
468
613
|
|
469
|
-
|
614
|
+
it "modify params hash if param is in GET" do
|
470
615
|
e = Rack::MockRequest.env_for("?foo=duh")
|
471
|
-
req1 =
|
472
|
-
req1.params.
|
616
|
+
req1 = make_request(e)
|
617
|
+
req1.params.must_equal 'foo' => 'duh'
|
473
618
|
req1.update_param 'foo', 'bar'
|
474
|
-
req1.params.
|
475
|
-
req2 =
|
476
|
-
req2.params.
|
619
|
+
req1.params.must_equal 'foo' => 'bar'
|
620
|
+
req2 = make_request(e)
|
621
|
+
req2.params.must_equal 'foo' => 'bar'
|
477
622
|
end
|
478
623
|
|
479
|
-
|
624
|
+
it "modify params hash if param is in POST" do
|
480
625
|
e = Rack::MockRequest.env_for("", "REQUEST_METHOD" => 'POST', :input => 'foo=duh')
|
481
|
-
req1 =
|
482
|
-
req1.params.
|
626
|
+
req1 = make_request(e)
|
627
|
+
req1.params.must_equal 'foo' => 'duh'
|
483
628
|
req1.update_param 'foo', 'bar'
|
484
|
-
req1.params.
|
485
|
-
req2 =
|
486
|
-
req2.params.
|
629
|
+
req1.params.must_equal 'foo' => 'bar'
|
630
|
+
req2 = make_request(e)
|
631
|
+
req2.params.must_equal 'foo' => 'bar'
|
487
632
|
end
|
488
633
|
|
489
|
-
|
634
|
+
it "modify params hash, even if param didn't exist before" do
|
490
635
|
e = Rack::MockRequest.env_for("")
|
491
|
-
req1 =
|
492
|
-
req1.params.
|
636
|
+
req1 = make_request(e)
|
637
|
+
req1.params.must_equal({})
|
493
638
|
req1.update_param 'foo', 'bar'
|
494
|
-
req1.params.
|
495
|
-
req2 =
|
496
|
-
req2.params.
|
639
|
+
req1.params.must_equal 'foo' => 'bar'
|
640
|
+
req2 = make_request(e)
|
641
|
+
req2.params.must_equal 'foo' => 'bar'
|
497
642
|
end
|
498
643
|
|
499
|
-
|
644
|
+
it "modify params hash by changing only GET" do
|
500
645
|
e = Rack::MockRequest.env_for("?foo=duhget")
|
501
|
-
req =
|
502
|
-
req.GET.
|
503
|
-
req.POST.
|
646
|
+
req = make_request(e)
|
647
|
+
req.GET.must_equal 'foo' => 'duhget'
|
648
|
+
req.POST.must_equal({})
|
504
649
|
req.update_param 'foo', 'bar'
|
505
|
-
req.GET.
|
506
|
-
req.POST.
|
650
|
+
req.GET.must_equal 'foo' => 'bar'
|
651
|
+
req.POST.must_equal({})
|
507
652
|
end
|
508
653
|
|
509
|
-
|
654
|
+
it "modify params hash by changing only POST" do
|
510
655
|
e = Rack::MockRequest.env_for("", "REQUEST_METHOD" => 'POST', :input => "foo=duhpost")
|
511
|
-
req =
|
512
|
-
req.GET.
|
513
|
-
req.POST.
|
656
|
+
req = make_request(e)
|
657
|
+
req.GET.must_equal({})
|
658
|
+
req.POST.must_equal 'foo' => 'duhpost'
|
514
659
|
req.update_param 'foo', 'bar'
|
515
|
-
req.GET.
|
516
|
-
req.POST.
|
660
|
+
req.GET.must_equal({})
|
661
|
+
req.POST.must_equal 'foo' => 'bar'
|
517
662
|
end
|
518
663
|
|
519
|
-
|
664
|
+
it "modify params hash, even if param is defined in both POST and GET" do
|
520
665
|
e = Rack::MockRequest.env_for("?foo=duhget", "REQUEST_METHOD" => 'POST', :input => "foo=duhpost")
|
521
|
-
req1 =
|
522
|
-
req1.GET.
|
523
|
-
req1.POST.
|
524
|
-
req1.params.
|
666
|
+
req1 = make_request(e)
|
667
|
+
req1.GET.must_equal 'foo' => 'duhget'
|
668
|
+
req1.POST.must_equal 'foo' => 'duhpost'
|
669
|
+
req1.params.must_equal 'foo' => 'duhpost'
|
525
670
|
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.
|
671
|
+
req1.GET.must_equal 'foo' => 'bar'
|
672
|
+
req1.POST.must_equal 'foo' => 'bar'
|
673
|
+
req1.params.must_equal 'foo' => 'bar'
|
674
|
+
req2 = make_request(e)
|
675
|
+
req2.GET.must_equal 'foo' => 'bar'
|
676
|
+
req2.POST.must_equal 'foo' => 'bar'
|
677
|
+
req2.params.must_equal 'foo' => 'bar'
|
678
|
+
req2.params.must_equal 'foo' => 'bar'
|
534
679
|
end
|
535
680
|
|
536
|
-
|
681
|
+
it "allow deleting from params hash if param is in GET" do
|
537
682
|
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.
|
683
|
+
req1 = make_request(e)
|
684
|
+
req1.params.must_equal 'foo' => 'bar'
|
685
|
+
req1.delete_param('foo').must_equal 'bar'
|
686
|
+
req1.params.must_equal({})
|
687
|
+
req2 = make_request(e)
|
688
|
+
req2.params.must_equal({})
|
544
689
|
end
|
545
690
|
|
546
|
-
|
691
|
+
it "allow deleting from params hash if param is in POST" do
|
547
692
|
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.
|
693
|
+
req1 = make_request(e)
|
694
|
+
req1.params.must_equal 'foo' => 'bar'
|
695
|
+
req1.delete_param('foo').must_equal 'bar'
|
696
|
+
req1.params.must_equal({})
|
697
|
+
req2 = make_request(e)
|
698
|
+
req2.params.must_equal({})
|
554
699
|
end
|
555
700
|
|
556
|
-
|
557
|
-
req =
|
558
|
-
req.cookies["foo"].
|
701
|
+
it "pass through non-uri escaped cookies as-is" do
|
702
|
+
req = make_request Rack::MockRequest.env_for("", "HTTP_COOKIE" => "foo=%")
|
703
|
+
req.cookies["foo"].must_equal "%"
|
559
704
|
end
|
560
705
|
|
561
|
-
|
562
|
-
req =
|
706
|
+
it "parse cookies according to RFC 2109" do
|
707
|
+
req = make_request \
|
563
708
|
Rack::MockRequest.env_for('', 'HTTP_COOKIE' => 'foo=bar;foo=car')
|
564
|
-
req.cookies.
|
709
|
+
req.cookies.must_equal 'foo' => 'bar'
|
565
710
|
end
|
566
711
|
|
567
|
-
|
568
|
-
req =
|
712
|
+
it 'parse cookies with quotes' do
|
713
|
+
req = make_request Rack::MockRequest.env_for('', {
|
569
714
|
'HTTP_COOKIE' => '$Version="1"; Customer="WILE_E_COYOTE"; $Path="/acme"; Part_Number="Rocket_Launcher_0001"; $Path="/acme"'
|
570
715
|
})
|
571
|
-
req.cookies.
|
716
|
+
req.cookies.must_equal({
|
572
717
|
'$Version' => '"1"',
|
573
718
|
'Customer' => '"WILE_E_COYOTE"',
|
574
719
|
'$Path' => '"/acme"',
|
@@ -576,88 +721,88 @@ describe Rack::Request do
|
|
576
721
|
})
|
577
722
|
end
|
578
723
|
|
579
|
-
|
580
|
-
req =
|
581
|
-
req.script_name.
|
724
|
+
it "provide setters" do
|
725
|
+
req = make_request(e=Rack::MockRequest.env_for(""))
|
726
|
+
req.script_name.must_equal ""
|
582
727
|
req.script_name = "/foo"
|
583
|
-
req.script_name.
|
584
|
-
e["SCRIPT_NAME"].
|
728
|
+
req.script_name.must_equal "/foo"
|
729
|
+
e["SCRIPT_NAME"].must_equal "/foo"
|
585
730
|
|
586
|
-
req.path_info.
|
731
|
+
req.path_info.must_equal "/"
|
587
732
|
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 =
|
733
|
+
req.path_info.must_equal "/foo"
|
734
|
+
e["PATH_INFO"].must_equal "/foo"
|
735
|
+
end
|
736
|
+
|
737
|
+
it "provide the original env" do
|
738
|
+
req = make_request(e = Rack::MockRequest.env_for(""))
|
739
|
+
req.env.must_equal e
|
740
|
+
end
|
741
|
+
|
742
|
+
it "restore the base URL" do
|
743
|
+
make_request(Rack::MockRequest.env_for("")).base_url.
|
744
|
+
must_equal "http://example.org"
|
745
|
+
make_request(Rack::MockRequest.env_for("", "SCRIPT_NAME" => "/foo")).base_url.
|
746
|
+
must_equal "http://example.org"
|
747
|
+
end
|
748
|
+
|
749
|
+
it "restore the URL" do
|
750
|
+
make_request(Rack::MockRequest.env_for("")).url.
|
751
|
+
must_equal "http://example.org/"
|
752
|
+
make_request(Rack::MockRequest.env_for("", "SCRIPT_NAME" => "/foo")).url.
|
753
|
+
must_equal "http://example.org/foo/"
|
754
|
+
make_request(Rack::MockRequest.env_for("/foo")).url.
|
755
|
+
must_equal "http://example.org/foo"
|
756
|
+
make_request(Rack::MockRequest.env_for("?foo")).url.
|
757
|
+
must_equal "http://example.org/?foo"
|
758
|
+
make_request(Rack::MockRequest.env_for("http://example.org:8080/")).url.
|
759
|
+
must_equal "http://example.org:8080/"
|
760
|
+
make_request(Rack::MockRequest.env_for("https://example.org/")).url.
|
761
|
+
must_equal "https://example.org/"
|
762
|
+
make_request(Rack::MockRequest.env_for("coffee://example.org/")).url.
|
763
|
+
must_equal "coffee://example.org/"
|
764
|
+
make_request(Rack::MockRequest.env_for("coffee://example.org:443/")).url.
|
765
|
+
must_equal "coffee://example.org:443/"
|
766
|
+
make_request(Rack::MockRequest.env_for("https://example.com:8080/foo?foo")).url.
|
767
|
+
must_equal "https://example.com:8080/foo?foo"
|
768
|
+
end
|
769
|
+
|
770
|
+
it "restore the full path" do
|
771
|
+
make_request(Rack::MockRequest.env_for("")).fullpath.
|
772
|
+
must_equal "/"
|
773
|
+
make_request(Rack::MockRequest.env_for("", "SCRIPT_NAME" => "/foo")).fullpath.
|
774
|
+
must_equal "/foo/"
|
775
|
+
make_request(Rack::MockRequest.env_for("/foo")).fullpath.
|
776
|
+
must_equal "/foo"
|
777
|
+
make_request(Rack::MockRequest.env_for("?foo")).fullpath.
|
778
|
+
must_equal "/?foo"
|
779
|
+
make_request(Rack::MockRequest.env_for("http://example.org:8080/")).fullpath.
|
780
|
+
must_equal "/"
|
781
|
+
make_request(Rack::MockRequest.env_for("https://example.org/")).fullpath.
|
782
|
+
must_equal "/"
|
783
|
+
|
784
|
+
make_request(Rack::MockRequest.env_for("https://example.com:8080/foo?foo")).fullpath.
|
785
|
+
must_equal "/foo?foo"
|
786
|
+
end
|
787
|
+
|
788
|
+
it "handle multiple media type parameters" do
|
789
|
+
req = make_request \
|
645
790
|
Rack::MockRequest.env_for("/",
|
646
791
|
"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
|
-
|
792
|
+
req.wont_be :form_data?
|
793
|
+
req.media_type_params.must_include 'foo'
|
794
|
+
req.media_type_params['foo'].must_equal 'BAR'
|
795
|
+
req.media_type_params.must_include 'baz'
|
796
|
+
req.media_type_params['baz'].must_equal 'bizzle dizzle'
|
797
|
+
req.media_type_params.wont_include 'BLING'
|
798
|
+
req.media_type_params.must_include 'bling'
|
799
|
+
req.media_type_params['bling'].must_equal 'bam'
|
800
|
+
req.media_type_params['blong'].must_equal 'boo'
|
801
|
+
req.media_type_params['zump'].must_equal 'zoo\"o'
|
802
|
+
req.media_type_params['weird'].must_equal 'lol"'
|
803
|
+
end
|
804
|
+
|
805
|
+
it "parse with junk before boundary" do
|
661
806
|
# Adapted from RFC 1867.
|
662
807
|
input = <<EOF
|
663
808
|
blah blah\r
|
@@ -674,31 +819,31 @@ Content-Transfer-Encoding: base64\r
|
|
674
819
|
/9j/4AAQSkZJRgABAQAAAQABAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcg\r
|
675
820
|
--AaB03x--\r
|
676
821
|
EOF
|
677
|
-
req =
|
822
|
+
req = make_request Rack::MockRequest.env_for("/",
|
678
823
|
"CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
|
679
824
|
"CONTENT_LENGTH" => input.size,
|
680
825
|
:input => input)
|
681
826
|
|
682
|
-
req.POST.
|
683
|
-
req.POST.
|
827
|
+
req.POST.must_include "fileupload"
|
828
|
+
req.POST.must_include "reply"
|
684
829
|
|
685
|
-
req.
|
686
|
-
req.content_length.
|
687
|
-
req.media_type.
|
688
|
-
req.media_type_params.
|
689
|
-
req.media_type_params['boundary'].
|
830
|
+
req.must_be :form_data?
|
831
|
+
req.content_length.must_equal input.size
|
832
|
+
req.media_type.must_equal 'multipart/form-data'
|
833
|
+
req.media_type_params.must_include 'boundary'
|
834
|
+
req.media_type_params['boundary'].must_equal 'AaB03x'
|
690
835
|
|
691
|
-
req.POST["reply"].
|
836
|
+
req.POST["reply"].must_equal "yes"
|
692
837
|
|
693
838
|
f = req.POST["fileupload"]
|
694
|
-
f.
|
695
|
-
f[:type].
|
696
|
-
f[:filename].
|
697
|
-
f.
|
698
|
-
f[:tempfile].size.
|
839
|
+
f.must_be_kind_of Hash
|
840
|
+
f[:type].must_equal "image/jpeg"
|
841
|
+
f[:filename].must_equal "dj.jpg"
|
842
|
+
f.must_include :tempfile
|
843
|
+
f[:tempfile].size.must_equal 76
|
699
844
|
end
|
700
845
|
|
701
|
-
|
846
|
+
it "not infinite loop with a malformed HTTP request" do
|
702
847
|
# Adapted from RFC 1867.
|
703
848
|
input = <<EOF
|
704
849
|
--AaB03x
|
@@ -713,16 +858,16 @@ Content-Transfer-Encoding: base64
|
|
713
858
|
/9j/4AAQSkZJRgABAQAAAQABAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcg
|
714
859
|
--AaB03x--
|
715
860
|
EOF
|
716
|
-
req =
|
861
|
+
req = make_request Rack::MockRequest.env_for("/",
|
717
862
|
"CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
|
718
863
|
"CONTENT_LENGTH" => input.size,
|
719
864
|
:input => input)
|
720
865
|
|
721
|
-
lambda{req.POST}.
|
866
|
+
lambda{req.POST}.must_raise EOFError
|
722
867
|
end
|
723
868
|
|
724
869
|
|
725
|
-
|
870
|
+
it "parse multipart form data" do
|
726
871
|
# Adapted from RFC 1867.
|
727
872
|
input = <<EOF
|
728
873
|
--AaB03x\r
|
@@ -737,47 +882,73 @@ Content-Transfer-Encoding: base64\r
|
|
737
882
|
/9j/4AAQSkZJRgABAQAAAQABAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcg\r
|
738
883
|
--AaB03x--\r
|
739
884
|
EOF
|
740
|
-
req =
|
885
|
+
req = make_request Rack::MockRequest.env_for("/",
|
741
886
|
"CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
|
742
887
|
"CONTENT_LENGTH" => input.size,
|
743
888
|
:input => input)
|
744
889
|
|
745
|
-
req.POST.
|
746
|
-
req.POST.
|
890
|
+
req.POST.must_include "fileupload"
|
891
|
+
req.POST.must_include "reply"
|
747
892
|
|
748
|
-
req.
|
749
|
-
req.content_length.
|
750
|
-
req.media_type.
|
751
|
-
req.media_type_params.
|
752
|
-
req.media_type_params['boundary'].
|
893
|
+
req.must_be :form_data?
|
894
|
+
req.content_length.must_equal input.size
|
895
|
+
req.media_type.must_equal 'multipart/form-data'
|
896
|
+
req.media_type_params.must_include 'boundary'
|
897
|
+
req.media_type_params['boundary'].must_equal 'AaB03x'
|
753
898
|
|
754
|
-
req.POST["reply"].
|
899
|
+
req.POST["reply"].must_equal "yes"
|
755
900
|
|
756
901
|
f = req.POST["fileupload"]
|
757
|
-
f.
|
758
|
-
f[:type].
|
759
|
-
f[:filename].
|
760
|
-
f.
|
761
|
-
f[:tempfile].size.
|
902
|
+
f.must_be_kind_of Hash
|
903
|
+
f[:type].must_equal "image/jpeg"
|
904
|
+
f[:filename].must_equal "dj.jpg"
|
905
|
+
f.must_include :tempfile
|
906
|
+
f[:tempfile].size.must_equal 76
|
907
|
+
end
|
908
|
+
|
909
|
+
it "MultipartPartLimitError when request has too many multipart parts if limit set" do
|
910
|
+
begin
|
911
|
+
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")
|
912
|
+
data += "--AaB03x--\r"
|
913
|
+
|
914
|
+
options = {
|
915
|
+
"CONTENT_TYPE" => "multipart/form-data; boundary=AaB03x",
|
916
|
+
"CONTENT_LENGTH" => data.length.to_s,
|
917
|
+
:input => StringIO.new(data)
|
918
|
+
}
|
919
|
+
|
920
|
+
request = make_request Rack::MockRequest.env_for("/", options)
|
921
|
+
lambda { request.POST }.must_raise Rack::Multipart::MultipartPartLimitError
|
922
|
+
end
|
762
923
|
end
|
763
924
|
|
764
|
-
|
925
|
+
it 'closes tempfiles it created in the case of too many created' do
|
765
926
|
begin
|
766
927
|
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
928
|
data += "--AaB03x--\r"
|
768
929
|
|
930
|
+
files = []
|
769
931
|
options = {
|
770
932
|
"CONTENT_TYPE" => "multipart/form-data; boundary=AaB03x",
|
771
933
|
"CONTENT_LENGTH" => data.length.to_s,
|
934
|
+
Rack::RACK_MULTIPART_TEMPFILE_FACTORY => lambda { |filename, content_type|
|
935
|
+
file = Tempfile.new(["RackMultipart", ::File.extname(filename)])
|
936
|
+
files << file
|
937
|
+
file
|
938
|
+
},
|
772
939
|
:input => StringIO.new(data)
|
773
940
|
}
|
774
941
|
|
775
|
-
request =
|
776
|
-
|
942
|
+
request = make_request Rack::MockRequest.env_for("/", options)
|
943
|
+
assert_raises(Rack::Multipart::MultipartPartLimitError) do
|
944
|
+
request.POST
|
945
|
+
end
|
946
|
+
refute_predicate files, :empty?
|
947
|
+
files.each { |f| assert_predicate f, :closed? }
|
777
948
|
end
|
778
949
|
end
|
779
950
|
|
780
|
-
|
951
|
+
it "parse big multipart form data" do
|
781
952
|
input = <<EOF
|
782
953
|
--AaB03x\r
|
783
954
|
content-disposition: form-data; name="huge"; filename="huge"\r
|
@@ -789,17 +960,17 @@ content-disposition: form-data; name="mean"; filename="mean"\r
|
|
789
960
|
--AaB03xha\r
|
790
961
|
--AaB03x--\r
|
791
962
|
EOF
|
792
|
-
req =
|
963
|
+
req = make_request Rack::MockRequest.env_for("/",
|
793
964
|
"CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
|
794
965
|
"CONTENT_LENGTH" => input.size,
|
795
966
|
:input => input)
|
796
967
|
|
797
|
-
req.POST["huge"][:tempfile].size.
|
798
|
-
req.POST["mean"][:tempfile].size.
|
799
|
-
req.POST["mean"][:tempfile].read.
|
968
|
+
req.POST["huge"][:tempfile].size.must_equal 32768
|
969
|
+
req.POST["mean"][:tempfile].size.must_equal 10
|
970
|
+
req.POST["mean"][:tempfile].read.must_equal "--AaB03xha"
|
800
971
|
end
|
801
972
|
|
802
|
-
|
973
|
+
it "record tempfiles from multipart form data in env[rack.tempfiles]" do
|
803
974
|
input = <<EOF
|
804
975
|
--AaB03x\r
|
805
976
|
content-disposition: form-data; name="fileupload"; filename="foo.jpg"\r
|
@@ -819,22 +990,22 @@ EOF
|
|
819
990
|
"CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
|
820
991
|
"CONTENT_LENGTH" => input.size,
|
821
992
|
:input => input)
|
822
|
-
req =
|
993
|
+
req = make_request(env)
|
823
994
|
req.params
|
824
|
-
env['rack.tempfiles'].size.
|
995
|
+
env['rack.tempfiles'].size.must_equal 2
|
825
996
|
end
|
826
997
|
|
827
|
-
|
998
|
+
it "detect invalid multipart form data" do
|
828
999
|
input = <<EOF
|
829
1000
|
--AaB03x\r
|
830
1001
|
content-disposition: form-data; name="huge"; filename="huge"\r
|
831
1002
|
EOF
|
832
|
-
req =
|
1003
|
+
req = make_request Rack::MockRequest.env_for("/",
|
833
1004
|
"CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
|
834
1005
|
"CONTENT_LENGTH" => input.size,
|
835
1006
|
:input => input)
|
836
1007
|
|
837
|
-
lambda { req.POST }.
|
1008
|
+
lambda { req.POST }.must_raise EOFError
|
838
1009
|
|
839
1010
|
input = <<EOF
|
840
1011
|
--AaB03x\r
|
@@ -842,12 +1013,12 @@ content-disposition: form-data; name="huge"; filename="huge"\r
|
|
842
1013
|
\r
|
843
1014
|
foo\r
|
844
1015
|
EOF
|
845
|
-
req =
|
1016
|
+
req = make_request Rack::MockRequest.env_for("/",
|
846
1017
|
"CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
|
847
1018
|
"CONTENT_LENGTH" => input.size,
|
848
1019
|
:input => input)
|
849
1020
|
|
850
|
-
lambda { req.POST }.
|
1021
|
+
lambda { req.POST }.must_raise EOFError
|
851
1022
|
|
852
1023
|
input = <<EOF
|
853
1024
|
--AaB03x\r
|
@@ -855,29 +1026,29 @@ content-disposition: form-data; name="huge"; filename="huge"\r
|
|
855
1026
|
\r
|
856
1027
|
foo\r
|
857
1028
|
EOF
|
858
|
-
req =
|
1029
|
+
req = make_request Rack::MockRequest.env_for("/",
|
859
1030
|
"CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
|
860
1031
|
"CONTENT_LENGTH" => input.size,
|
861
1032
|
:input => input)
|
862
1033
|
|
863
|
-
lambda { req.POST }.
|
1034
|
+
lambda { req.POST }.must_raise EOFError
|
864
1035
|
end
|
865
1036
|
|
866
|
-
|
1037
|
+
it "consistently raise EOFError on bad multipart form data" do
|
867
1038
|
input = <<EOF
|
868
1039
|
--AaB03x\r
|
869
1040
|
content-disposition: form-data; name="huge"; filename="huge"\r
|
870
1041
|
EOF
|
871
|
-
req =
|
1042
|
+
req = make_request Rack::MockRequest.env_for("/",
|
872
1043
|
"CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
|
873
1044
|
"CONTENT_LENGTH" => input.size,
|
874
1045
|
:input => input)
|
875
1046
|
|
876
|
-
lambda { req.POST }.
|
877
|
-
lambda { req.POST }.
|
1047
|
+
lambda { req.POST }.must_raise EOFError
|
1048
|
+
lambda { req.POST }.must_raise EOFError
|
878
1049
|
end
|
879
1050
|
|
880
|
-
|
1051
|
+
it "correctly parse the part name from Content-Id header" do
|
881
1052
|
input = <<EOF
|
882
1053
|
--AaB03x\r
|
883
1054
|
Content-Type: text/xml; charset=utf-8\r
|
@@ -887,20 +1058,15 @@ Content-Transfer-Encoding: 7bit\r
|
|
887
1058
|
foo\r
|
888
1059
|
--AaB03x--\r
|
889
1060
|
EOF
|
890
|
-
req =
|
1061
|
+
req = make_request Rack::MockRequest.env_for("/",
|
891
1062
|
"CONTENT_TYPE" => "multipart/related, boundary=AaB03x",
|
892
1063
|
"CONTENT_LENGTH" => input.size,
|
893
1064
|
:input => input)
|
894
1065
|
|
895
|
-
req.params.keys.
|
1066
|
+
req.params.keys.must_equal ["<soap-start>"]
|
896
1067
|
end
|
897
1068
|
|
898
|
-
|
899
|
-
if /regexp/.respond_to?(:kcode) # < 1.9
|
900
|
-
begin
|
901
|
-
original_kcode = $KCODE
|
902
|
-
$KCODE='UTF8'
|
903
|
-
|
1069
|
+
it "not try to interpret binary as utf8" do
|
904
1070
|
input = <<EOF
|
905
1071
|
--AaB03x\r
|
906
1072
|
content-disposition: form-data; name="fileupload"; filename="junk.a"\r
|
@@ -910,77 +1076,33 @@ content-type: application/octet-stream\r
|
|
910
1076
|
--AaB03x--\r
|
911
1077
|
EOF
|
912
1078
|
|
913
|
-
req =
|
1079
|
+
req = make_request Rack::MockRequest.env_for("/",
|
914
1080
|
"CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
|
915
1081
|
"CONTENT_LENGTH" => input.size,
|
916
1082
|
:input => input)
|
917
1083
|
|
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
|
1084
|
+
req.POST["fileupload"][:tempfile].size.must_equal 4
|
941
1085
|
end
|
942
1086
|
|
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
|
1087
|
+
it "use form_hash when form_input is a Tempfile" do
|
966
1088
|
input = "{foo: 'bar'}"
|
967
1089
|
|
968
1090
|
rack_input = Tempfile.new("rackspec")
|
969
1091
|
rack_input.write(input)
|
970
1092
|
rack_input.rewind
|
971
1093
|
|
972
|
-
req =
|
1094
|
+
req = make_request Rack::MockRequest.env_for("/",
|
973
1095
|
"rack.request.form_hash" => {'foo' => 'bar'},
|
974
1096
|
"rack.request.form_input" => rack_input,
|
975
1097
|
:input => rack_input)
|
976
1098
|
|
977
|
-
req.POST.
|
1099
|
+
req.POST.must_equal req.env['rack.request.form_hash']
|
978
1100
|
end
|
979
1101
|
|
980
|
-
|
1102
|
+
it "conform to the Rack spec" do
|
981
1103
|
app = lambda { |env|
|
982
|
-
content =
|
983
|
-
size = content.
|
1104
|
+
content = make_request(env).POST["file"].inspect
|
1105
|
+
size = content.bytesize
|
984
1106
|
[200, {"Content-Type" => "text/html", "Content-Length" => size.to_s}, [content]]
|
985
1107
|
}
|
986
1108
|
|
@@ -997,149 +1119,151 @@ Content-Transfer-Encoding: base64\r
|
|
997
1119
|
/9j/4AAQSkZJRgABAQAAAQABAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcg\r
|
998
1120
|
--AaB03x--\r
|
999
1121
|
EOF
|
1000
|
-
input.force_encoding(
|
1122
|
+
input.force_encoding(Encoding::ASCII_8BIT)
|
1001
1123
|
res = Rack::MockRequest.new(Rack::Lint.new(app)).get "/",
|
1002
1124
|
"CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
|
1003
1125
|
"CONTENT_LENGTH" => input.size.to_s, "rack.input" => StringIO.new(input)
|
1004
1126
|
|
1005
|
-
res.
|
1127
|
+
res.must_be :ok?
|
1006
1128
|
end
|
1007
1129
|
|
1008
|
-
|
1130
|
+
it "parse Accept-Encoding correctly" do
|
1009
1131
|
parser = lambda do |x|
|
1010
|
-
|
1132
|
+
make_request(Rack::MockRequest.env_for("", "HTTP_ACCEPT_ENCODING" => x)).accept_encoding
|
1011
1133
|
end
|
1012
1134
|
|
1013
|
-
parser.call(nil).
|
1135
|
+
parser.call(nil).must_equal []
|
1014
1136
|
|
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").
|
1137
|
+
parser.call("compress, gzip").must_equal [["compress", 1.0], ["gzip", 1.0]]
|
1138
|
+
parser.call("").must_equal []
|
1139
|
+
parser.call("*").must_equal [["*", 1.0]]
|
1140
|
+
parser.call("compress;q=0.5, gzip;q=1.0").must_equal [["compress", 0.5], ["gzip", 1.0]]
|
1141
|
+
parser.call("gzip;q=1.0, identity; q=0.5, *;q=0").must_equal [["gzip", 1.0], ["identity", 0.5], ["*", 0] ]
|
1020
1142
|
|
1021
|
-
parser.call("gzip ; q=0.9").
|
1022
|
-
parser.call("gzip ; deflate").
|
1143
|
+
parser.call("gzip ; q=0.9").must_equal [["gzip", 0.9]]
|
1144
|
+
parser.call("gzip ; deflate").must_equal [["gzip", 1.0]]
|
1023
1145
|
end
|
1024
1146
|
|
1025
|
-
|
1147
|
+
it "parse Accept-Language correctly" do
|
1026
1148
|
parser = lambda do |x|
|
1027
|
-
|
1149
|
+
make_request(Rack::MockRequest.env_for("", "HTTP_ACCEPT_LANGUAGE" => x)).accept_language
|
1028
1150
|
end
|
1029
1151
|
|
1030
|
-
parser.call(nil).
|
1152
|
+
parser.call(nil).must_equal []
|
1031
1153
|
|
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").
|
1154
|
+
parser.call("fr, en").must_equal [["fr", 1.0], ["en", 1.0]]
|
1155
|
+
parser.call("").must_equal []
|
1156
|
+
parser.call("*").must_equal [["*", 1.0]]
|
1157
|
+
parser.call("fr;q=0.5, en;q=1.0").must_equal [["fr", 0.5], ["en", 1.0]]
|
1158
|
+
parser.call("fr;q=1.0, en; q=0.5, *;q=0").must_equal [["fr", 1.0], ["en", 0.5], ["*", 0] ]
|
1037
1159
|
|
1038
|
-
parser.call("fr ; q=0.9").
|
1039
|
-
parser.call("fr").
|
1160
|
+
parser.call("fr ; q=0.9").must_equal [["fr", 0.9]]
|
1161
|
+
parser.call("fr").must_equal [["fr", 1.0]]
|
1040
1162
|
end
|
1041
1163
|
|
1042
|
-
ip_app
|
1043
|
-
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
1164
|
+
def ip_app
|
1165
|
+
lambda { |env|
|
1166
|
+
request = make_request(env)
|
1167
|
+
response = Rack::Response.new
|
1168
|
+
response.write request.ip
|
1169
|
+
response.finish
|
1170
|
+
}
|
1171
|
+
end
|
1048
1172
|
|
1049
|
-
|
1173
|
+
it 'provide ip information' do
|
1050
1174
|
mock = Rack::MockRequest.new(Rack::Lint.new(ip_app))
|
1051
1175
|
|
1052
1176
|
res = mock.get '/', 'REMOTE_ADDR' => '1.2.3.4'
|
1053
|
-
res.body.
|
1177
|
+
res.body.must_equal '1.2.3.4'
|
1054
1178
|
|
1055
1179
|
res = mock.get '/', 'REMOTE_ADDR' => 'fe80::202:b3ff:fe1e:8329'
|
1056
|
-
res.body.
|
1180
|
+
res.body.must_equal 'fe80::202:b3ff:fe1e:8329'
|
1057
1181
|
|
1058
1182
|
res = mock.get '/', 'REMOTE_ADDR' => '1.2.3.4,3.4.5.6'
|
1059
|
-
res.body.
|
1183
|
+
res.body.must_equal '1.2.3.4'
|
1060
1184
|
end
|
1061
1185
|
|
1062
|
-
|
1186
|
+
it 'deals with proxies' do
|
1063
1187
|
mock = Rack::MockRequest.new(Rack::Lint.new(ip_app))
|
1064
1188
|
|
1065
1189
|
res = mock.get '/',
|
1066
1190
|
'REMOTE_ADDR' => '1.2.3.4',
|
1067
1191
|
'HTTP_X_FORWARDED_FOR' => '3.4.5.6'
|
1068
|
-
res.body.
|
1192
|
+
res.body.must_equal '1.2.3.4'
|
1069
1193
|
|
1070
1194
|
res = mock.get '/',
|
1071
1195
|
'REMOTE_ADDR' => '1.2.3.4',
|
1072
1196
|
'HTTP_X_FORWARDED_FOR' => 'unknown'
|
1073
|
-
res.body.
|
1197
|
+
res.body.must_equal '1.2.3.4'
|
1074
1198
|
|
1075
1199
|
res = mock.get '/',
|
1076
1200
|
'REMOTE_ADDR' => '127.0.0.1',
|
1077
1201
|
'HTTP_X_FORWARDED_FOR' => '3.4.5.6'
|
1078
|
-
res.body.
|
1202
|
+
res.body.must_equal '3.4.5.6'
|
1079
1203
|
|
1080
1204
|
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => 'unknown,3.4.5.6'
|
1081
|
-
res.body.
|
1205
|
+
res.body.must_equal '3.4.5.6'
|
1082
1206
|
|
1083
1207
|
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '192.168.0.1,3.4.5.6'
|
1084
|
-
res.body.
|
1208
|
+
res.body.must_equal '3.4.5.6'
|
1085
1209
|
|
1086
1210
|
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '10.0.0.1,3.4.5.6'
|
1087
|
-
res.body.
|
1211
|
+
res.body.must_equal '3.4.5.6'
|
1088
1212
|
|
1089
1213
|
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '10.0.0.1, 10.0.0.1, 3.4.5.6'
|
1090
|
-
res.body.
|
1214
|
+
res.body.must_equal '3.4.5.6'
|
1091
1215
|
|
1092
1216
|
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '127.0.0.1, 3.4.5.6'
|
1093
|
-
res.body.
|
1217
|
+
res.body.must_equal '3.4.5.6'
|
1094
1218
|
|
1095
1219
|
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => 'unknown,192.168.0.1'
|
1096
|
-
res.body.
|
1220
|
+
res.body.must_equal 'unknown'
|
1097
1221
|
|
1098
1222
|
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => 'other,unknown,192.168.0.1'
|
1099
|
-
res.body.
|
1223
|
+
res.body.must_equal 'unknown'
|
1100
1224
|
|
1101
1225
|
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => 'unknown,localhost,192.168.0.1'
|
1102
|
-
res.body.
|
1226
|
+
res.body.must_equal 'unknown'
|
1103
1227
|
|
1104
1228
|
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.
|
1229
|
+
res.body.must_equal '3.4.5.6'
|
1106
1230
|
|
1107
1231
|
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '::1,2620:0:1c00:0:812c:9583:754b:ca11'
|
1108
|
-
res.body.
|
1232
|
+
res.body.must_equal '2620:0:1c00:0:812c:9583:754b:ca11'
|
1109
1233
|
|
1110
1234
|
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '2620:0:1c00:0:812c:9583:754b:ca11,::1'
|
1111
|
-
res.body.
|
1235
|
+
res.body.must_equal '2620:0:1c00:0:812c:9583:754b:ca11'
|
1112
1236
|
|
1113
1237
|
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.
|
1238
|
+
res.body.must_equal '2620:0:1c00:0:812c:9583:754b:ca11'
|
1115
1239
|
|
1116
1240
|
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.
|
1241
|
+
res.body.must_equal '2620:0:1c00:0:812c:9583:754b:ca11'
|
1118
1242
|
|
1119
1243
|
res = mock.get '/',
|
1120
1244
|
'HTTP_X_FORWARDED_FOR' => '1.1.1.1, 127.0.0.1',
|
1121
1245
|
'HTTP_CLIENT_IP' => '1.1.1.1'
|
1122
|
-
res.body.
|
1246
|
+
res.body.must_equal '1.1.1.1'
|
1123
1247
|
|
1124
1248
|
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '8.8.8.8, 9.9.9.9'
|
1125
|
-
res.body.
|
1249
|
+
res.body.must_equal '9.9.9.9'
|
1126
1250
|
|
1127
1251
|
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '8.8.8.8, fe80::202:b3ff:fe1e:8329'
|
1128
|
-
res.body.
|
1252
|
+
res.body.must_equal 'fe80::202:b3ff:fe1e:8329'
|
1129
1253
|
|
1130
1254
|
# Unix Sockets
|
1131
1255
|
res = mock.get '/',
|
1132
1256
|
'REMOTE_ADDR' => 'unix',
|
1133
1257
|
'HTTP_X_FORWARDED_FOR' => '3.4.5.6'
|
1134
|
-
res.body.
|
1258
|
+
res.body.must_equal '3.4.5.6'
|
1135
1259
|
|
1136
1260
|
res = mock.get '/',
|
1137
1261
|
'REMOTE_ADDR' => 'unix:/tmp/foo',
|
1138
1262
|
'HTTP_X_FORWARDED_FOR' => '3.4.5.6'
|
1139
|
-
res.body.
|
1263
|
+
res.body.must_equal '3.4.5.6'
|
1140
1264
|
end
|
1141
1265
|
|
1142
|
-
|
1266
|
+
it "not allow IP spoofing via Client-IP and X-Forwarded-For headers" do
|
1143
1267
|
mock = Rack::MockRequest.new(Rack::Lint.new(ip_app))
|
1144
1268
|
|
1145
1269
|
# IP Spoofing attempt:
|
@@ -1154,31 +1278,36 @@ EOF
|
|
1154
1278
|
res = mock.get '/',
|
1155
1279
|
'HTTP_X_FORWARDED_FOR' => '6.6.6.6, 2.2.2.3, 192.168.0.7',
|
1156
1280
|
'HTTP_CLIENT_IP' => '6.6.6.6'
|
1157
|
-
res.body.
|
1158
|
-
end
|
1159
|
-
|
1160
|
-
|
1161
|
-
req =
|
1162
|
-
req.trusted_proxy?('127.0.0.1').
|
1163
|
-
req.trusted_proxy?('10.0.0.1').
|
1164
|
-
req.trusted_proxy?('172.16.0.1').
|
1165
|
-
req.trusted_proxy?('172.20.0.1').
|
1166
|
-
req.trusted_proxy?('172.30.0.1').
|
1167
|
-
req.trusted_proxy?('172.31.0.1').
|
1168
|
-
req.trusted_proxy?('192.168.0.1').
|
1169
|
-
req.trusted_proxy?('::1').
|
1170
|
-
req.trusted_proxy?('fd00::').
|
1171
|
-
req.trusted_proxy?('localhost').
|
1172
|
-
req.trusted_proxy?('unix').
|
1173
|
-
req.trusted_proxy?('unix:/tmp/sock').
|
1174
|
-
|
1175
|
-
req.trusted_proxy?("unix.example.org").
|
1176
|
-
req.trusted_proxy?("example.org\n127.0.0.1").
|
1177
|
-
req.trusted_proxy?("127.0.0.1\nexample.org").
|
1178
|
-
req.trusted_proxy?("11.0.0.1").
|
1179
|
-
req.trusted_proxy?("172.15.0.1").
|
1180
|
-
req.trusted_proxy?("172.32.0.1").
|
1181
|
-
req.trusted_proxy?("2001:470:1f0b:18f8::1").
|
1281
|
+
res.body.must_equal '2.2.2.3'
|
1282
|
+
end
|
1283
|
+
|
1284
|
+
it "regard local addresses as proxies" do
|
1285
|
+
req = make_request(Rack::MockRequest.env_for("/"))
|
1286
|
+
req.trusted_proxy?('127.0.0.1').must_equal 0
|
1287
|
+
req.trusted_proxy?('10.0.0.1').must_equal 0
|
1288
|
+
req.trusted_proxy?('172.16.0.1').must_equal 0
|
1289
|
+
req.trusted_proxy?('172.20.0.1').must_equal 0
|
1290
|
+
req.trusted_proxy?('172.30.0.1').must_equal 0
|
1291
|
+
req.trusted_proxy?('172.31.0.1').must_equal 0
|
1292
|
+
req.trusted_proxy?('192.168.0.1').must_equal 0
|
1293
|
+
req.trusted_proxy?('::1').must_equal 0
|
1294
|
+
req.trusted_proxy?('fd00::').must_equal 0
|
1295
|
+
req.trusted_proxy?('localhost').must_equal 0
|
1296
|
+
req.trusted_proxy?('unix').must_equal 0
|
1297
|
+
req.trusted_proxy?('unix:/tmp/sock').must_equal 0
|
1298
|
+
|
1299
|
+
req.trusted_proxy?("unix.example.org").must_equal nil
|
1300
|
+
req.trusted_proxy?("example.org\n127.0.0.1").must_equal nil
|
1301
|
+
req.trusted_proxy?("127.0.0.1\nexample.org").must_equal nil
|
1302
|
+
req.trusted_proxy?("11.0.0.1").must_equal nil
|
1303
|
+
req.trusted_proxy?("172.15.0.1").must_equal nil
|
1304
|
+
req.trusted_proxy?("172.32.0.1").must_equal nil
|
1305
|
+
req.trusted_proxy?("2001:470:1f0b:18f8::1").must_equal nil
|
1306
|
+
end
|
1307
|
+
|
1308
|
+
it "sets the default session to an empty hash" do
|
1309
|
+
req = make_request(Rack::MockRequest.env_for("http://example.com:8080/"))
|
1310
|
+
assert_equal Hash.new, req.session
|
1182
1311
|
end
|
1183
1312
|
|
1184
1313
|
class MyRequest < Rack::Request
|
@@ -1187,46 +1316,78 @@ EOF
|
|
1187
1316
|
end
|
1188
1317
|
end
|
1189
1318
|
|
1190
|
-
|
1319
|
+
it "allow subclass request to be instantiated after parent request" do
|
1191
1320
|
env = Rack::MockRequest.env_for("/?foo=bar")
|
1192
1321
|
|
1193
|
-
req1 =
|
1194
|
-
req1.GET.
|
1195
|
-
req1.params.
|
1322
|
+
req1 = make_request(env)
|
1323
|
+
req1.GET.must_equal "foo" => "bar"
|
1324
|
+
req1.params.must_equal "foo" => "bar"
|
1196
1325
|
|
1197
1326
|
req2 = MyRequest.new(env)
|
1198
|
-
req2.GET.
|
1199
|
-
req2.params.
|
1327
|
+
req2.GET.must_equal "foo" => "bar"
|
1328
|
+
req2.params.must_equal :foo => "bar"
|
1200
1329
|
end
|
1201
1330
|
|
1202
|
-
|
1331
|
+
it "allow parent request to be instantiated after subclass request" do
|
1203
1332
|
env = Rack::MockRequest.env_for("/?foo=bar")
|
1204
1333
|
|
1205
1334
|
req1 = MyRequest.new(env)
|
1206
|
-
req1.GET.
|
1207
|
-
req1.params.
|
1335
|
+
req1.GET.must_equal "foo" => "bar"
|
1336
|
+
req1.params.must_equal :foo => "bar"
|
1208
1337
|
|
1209
|
-
req2 =
|
1210
|
-
req2.GET.
|
1211
|
-
req2.params.
|
1338
|
+
req2 = make_request(env)
|
1339
|
+
req2.GET.must_equal "foo" => "bar"
|
1340
|
+
req2.params.must_equal "foo" => "bar"
|
1212
1341
|
end
|
1213
1342
|
|
1214
|
-
|
1343
|
+
it "raise TypeError every time if request parameters are broken" do
|
1215
1344
|
broken_query = Rack::MockRequest.env_for("/?foo%5B%5D=0&foo%5Bbar%5D=1")
|
1216
|
-
req =
|
1217
|
-
lambda{req.GET}.
|
1218
|
-
lambda{req.params}.
|
1345
|
+
req = make_request(broken_query)
|
1346
|
+
lambda{req.GET}.must_raise TypeError
|
1347
|
+
lambda{req.params}.must_raise TypeError
|
1219
1348
|
end
|
1220
1349
|
|
1221
1350
|
(0x20...0x7E).collect { |a|
|
1222
1351
|
b = a.chr
|
1223
1352
|
c = CGI.escape(b)
|
1224
|
-
|
1353
|
+
it "not strip '#{a}' => '#{c}' => '#{b}' escaped character from parameters when accessed as string" do
|
1225
1354
|
url = "/?foo=#{c}bar#{c}"
|
1226
1355
|
env = Rack::MockRequest.env_for(url)
|
1227
|
-
req2 =
|
1228
|
-
req2.GET.
|
1229
|
-
req2.params.
|
1356
|
+
req2 = make_request(env)
|
1357
|
+
req2.GET.must_equal "foo" => "#{b}bar#{b}"
|
1358
|
+
req2.params.must_equal "foo" => "#{b}bar#{b}"
|
1230
1359
|
end
|
1231
1360
|
}
|
1361
|
+
|
1362
|
+
class NonDelegate < Rack::Request
|
1363
|
+
def delegate?; false; end
|
1364
|
+
end
|
1365
|
+
|
1366
|
+
def make_request(env)
|
1367
|
+
NonDelegate.new env
|
1368
|
+
end
|
1369
|
+
|
1370
|
+
class TestProxyRequest < RackRequestTest
|
1371
|
+
class DelegateRequest
|
1372
|
+
include Rack::Request::Helpers
|
1373
|
+
extend Forwardable
|
1374
|
+
|
1375
|
+
def_delegators :@req, :has_header?, :get_header, :fetch_header,
|
1376
|
+
:each_header, :set_header, :add_header, :delete_header
|
1377
|
+
|
1378
|
+
def_delegators :@req, :[], :[]=, :values_at
|
1379
|
+
|
1380
|
+
def initialize(req)
|
1381
|
+
@req = req
|
1382
|
+
end
|
1383
|
+
|
1384
|
+
def delegate?; true; end
|
1385
|
+
|
1386
|
+
def env; @req.env.dup; end
|
1387
|
+
end
|
1388
|
+
|
1389
|
+
def make_request(env)
|
1390
|
+
DelegateRequest.new super(env)
|
1391
|
+
end
|
1392
|
+
end
|
1232
1393
|
end
|