rack 2.0.9.4 → 2.1.0

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.

Files changed (188) hide show
  1. checksums.yaml +4 -4
  2. data/{HISTORY.md → CHANGELOG.md} +214 -164
  3. data/{COPYING → MIT-LICENSE} +4 -2
  4. data/README.rdoc +79 -133
  5. data/Rakefile +25 -18
  6. data/SPEC +9 -9
  7. data/bin/rackup +1 -0
  8. data/example/lobster.ru +2 -0
  9. data/example/protectedlobster.rb +3 -1
  10. data/example/protectedlobster.ru +2 -0
  11. data/lib/rack/auth/abstract/handler.rb +3 -1
  12. data/lib/rack/auth/abstract/request.rb +2 -0
  13. data/lib/rack/auth/basic.rb +4 -1
  14. data/lib/rack/auth/digest/md5.rb +9 -7
  15. data/lib/rack/auth/digest/nonce.rb +6 -3
  16. data/lib/rack/auth/digest/params.rb +4 -2
  17. data/lib/rack/auth/digest/request.rb +2 -0
  18. data/lib/rack/body_proxy.rb +3 -6
  19. data/lib/rack/builder.rb +38 -15
  20. data/lib/rack/cascade.rb +6 -5
  21. data/lib/rack/chunked.rb +29 -6
  22. data/lib/rack/common_logger.rb +9 -11
  23. data/lib/rack/conditional_get.rb +3 -1
  24. data/lib/rack/config.rb +2 -0
  25. data/lib/rack/content_length.rb +3 -1
  26. data/lib/rack/content_type.rb +3 -1
  27. data/lib/rack/core_ext/regexp.rb +14 -0
  28. data/lib/rack/deflater.rb +28 -17
  29. data/lib/rack/directory.rb +17 -14
  30. data/lib/rack/etag.rb +3 -1
  31. data/lib/rack/events.rb +5 -3
  32. data/lib/rack/file.rb +5 -173
  33. data/lib/rack/files.rb +178 -0
  34. data/lib/rack/handler/cgi.rb +3 -1
  35. data/lib/rack/handler/fastcgi.rb +4 -2
  36. data/lib/rack/handler/lsws.rb +3 -1
  37. data/lib/rack/handler/scgi.rb +9 -6
  38. data/lib/rack/handler/thin.rb +3 -1
  39. data/lib/rack/handler/webrick.rb +4 -2
  40. data/lib/rack/handler.rb +7 -2
  41. data/lib/rack/head.rb +2 -0
  42. data/lib/rack/lint.rb +15 -12
  43. data/lib/rack/lobster.rb +7 -5
  44. data/lib/rack/lock.rb +2 -0
  45. data/lib/rack/logger.rb +2 -0
  46. data/lib/rack/media_type.rb +10 -5
  47. data/lib/rack/method_override.rb +4 -2
  48. data/lib/rack/mime.rb +9 -1
  49. data/lib/rack/mock.rb +74 -15
  50. data/lib/rack/multipart/generator.rb +6 -7
  51. data/lib/rack/multipart/parser.rb +55 -62
  52. data/lib/rack/multipart/uploaded_file.rb +2 -0
  53. data/lib/rack/multipart.rb +6 -3
  54. data/lib/rack/null_logger.rb +2 -0
  55. data/lib/rack/query_parser.rb +51 -25
  56. data/lib/rack/recursive.rb +7 -5
  57. data/lib/rack/reloader.rb +10 -4
  58. data/lib/rack/request.rb +79 -26
  59. data/lib/rack/response.rb +71 -31
  60. data/lib/rack/rewindable_input.rb +4 -2
  61. data/lib/rack/runtime.rb +4 -2
  62. data/lib/rack/sendfile.rb +15 -8
  63. data/lib/rack/server.rb +88 -16
  64. data/lib/rack/session/abstract/id.rb +40 -22
  65. data/lib/rack/session/cookie.rb +10 -9
  66. data/lib/rack/session/memcache.rb +4 -93
  67. data/lib/rack/session/pool.rb +4 -2
  68. data/lib/rack/show_exceptions.rb +15 -9
  69. data/lib/rack/show_status.rb +4 -2
  70. data/lib/rack/static.rb +15 -10
  71. data/lib/rack/tempfile_reaper.rb +2 -0
  72. data/lib/rack/urlmap.rb +11 -2
  73. data/lib/rack/utils.rb +64 -93
  74. data/lib/rack.rb +63 -60
  75. data/rack.gemspec +17 -7
  76. metadata +33 -175
  77. data/test/builder/an_underscore_app.rb +0 -5
  78. data/test/builder/anything.rb +0 -5
  79. data/test/builder/comment.ru +0 -4
  80. data/test/builder/end.ru +0 -5
  81. data/test/builder/line.ru +0 -1
  82. data/test/builder/options.ru +0 -2
  83. data/test/cgi/assets/folder/test.js +0 -1
  84. data/test/cgi/assets/fonts/font.eot +0 -1
  85. data/test/cgi/assets/images/image.png +0 -1
  86. data/test/cgi/assets/index.html +0 -1
  87. data/test/cgi/assets/javascripts/app.js +0 -1
  88. data/test/cgi/assets/stylesheets/app.css +0 -1
  89. data/test/cgi/lighttpd.conf +0 -26
  90. data/test/cgi/rackup_stub.rb +0 -6
  91. data/test/cgi/sample_rackup.ru +0 -5
  92. data/test/cgi/test +0 -9
  93. data/test/cgi/test+directory/test+file +0 -1
  94. data/test/cgi/test.fcgi +0 -9
  95. data/test/cgi/test.gz +0 -0
  96. data/test/cgi/test.ru +0 -5
  97. data/test/gemloader.rb +0 -10
  98. data/test/helper.rb +0 -34
  99. data/test/multipart/bad_robots +0 -259
  100. data/test/multipart/binary +0 -0
  101. data/test/multipart/content_type_and_no_filename +0 -6
  102. data/test/multipart/empty +0 -10
  103. data/test/multipart/fail_16384_nofile +0 -814
  104. data/test/multipart/file1.txt +0 -1
  105. data/test/multipart/filename_and_modification_param +0 -7
  106. data/test/multipart/filename_and_no_name +0 -6
  107. data/test/multipart/filename_with_encoded_words +0 -7
  108. data/test/multipart/filename_with_escaped_quotes +0 -6
  109. data/test/multipart/filename_with_escaped_quotes_and_modification_param +0 -7
  110. data/test/multipart/filename_with_null_byte +0 -7
  111. data/test/multipart/filename_with_percent_escaped_quotes +0 -6
  112. data/test/multipart/filename_with_single_quote +0 -7
  113. data/test/multipart/filename_with_unescaped_percentages +0 -6
  114. data/test/multipart/filename_with_unescaped_percentages2 +0 -6
  115. data/test/multipart/filename_with_unescaped_percentages3 +0 -6
  116. data/test/multipart/filename_with_unescaped_quotes +0 -6
  117. data/test/multipart/ie +0 -6
  118. data/test/multipart/invalid_character +0 -6
  119. data/test/multipart/mixed_files +0 -21
  120. data/test/multipart/nested +0 -10
  121. data/test/multipart/none +0 -9
  122. data/test/multipart/quoted +0 -15
  123. data/test/multipart/rack-logo.png +0 -0
  124. data/test/multipart/semicolon +0 -6
  125. data/test/multipart/text +0 -15
  126. data/test/multipart/three_files_three_fields +0 -31
  127. data/test/multipart/unity3d_wwwform +0 -11
  128. data/test/multipart/webkit +0 -32
  129. data/test/rackup/config.ru +0 -31
  130. data/test/registering_handler/rack/handler/registering_myself.rb +0 -8
  131. data/test/spec_auth_basic.rb +0 -89
  132. data/test/spec_auth_digest.rb +0 -260
  133. data/test/spec_body_proxy.rb +0 -85
  134. data/test/spec_builder.rb +0 -233
  135. data/test/spec_cascade.rb +0 -63
  136. data/test/spec_cgi.rb +0 -84
  137. data/test/spec_chunked.rb +0 -103
  138. data/test/spec_common_logger.rb +0 -107
  139. data/test/spec_conditional_get.rb +0 -103
  140. data/test/spec_config.rb +0 -23
  141. data/test/spec_content_length.rb +0 -86
  142. data/test/spec_content_type.rb +0 -46
  143. data/test/spec_deflater.rb +0 -375
  144. data/test/spec_directory.rb +0 -148
  145. data/test/spec_etag.rb +0 -108
  146. data/test/spec_events.rb +0 -133
  147. data/test/spec_fastcgi.rb +0 -85
  148. data/test/spec_file.rb +0 -264
  149. data/test/spec_handler.rb +0 -57
  150. data/test/spec_head.rb +0 -46
  151. data/test/spec_lint.rb +0 -520
  152. data/test/spec_lobster.rb +0 -59
  153. data/test/spec_lock.rb +0 -204
  154. data/test/spec_logger.rb +0 -24
  155. data/test/spec_media_type.rb +0 -42
  156. data/test/spec_method_override.rb +0 -110
  157. data/test/spec_mime.rb +0 -51
  158. data/test/spec_mock.rb +0 -359
  159. data/test/spec_multipart.rb +0 -721
  160. data/test/spec_null_logger.rb +0 -21
  161. data/test/spec_recursive.rb +0 -75
  162. data/test/spec_request.rb +0 -1423
  163. data/test/spec_response.rb +0 -528
  164. data/test/spec_rewindable_input.rb +0 -128
  165. data/test/spec_runtime.rb +0 -50
  166. data/test/spec_sendfile.rb +0 -125
  167. data/test/spec_server.rb +0 -193
  168. data/test/spec_session_abstract_id.rb +0 -31
  169. data/test/spec_session_abstract_session_hash.rb +0 -45
  170. data/test/spec_session_cookie.rb +0 -442
  171. data/test/spec_session_memcache.rb +0 -357
  172. data/test/spec_session_persisted_secure_secure_session_hash.rb +0 -73
  173. data/test/spec_session_pool.rb +0 -247
  174. data/test/spec_show_exceptions.rb +0 -93
  175. data/test/spec_show_status.rb +0 -104
  176. data/test/spec_static.rb +0 -184
  177. data/test/spec_tempfile_reaper.rb +0 -64
  178. data/test/spec_thin.rb +0 -96
  179. data/test/spec_urlmap.rb +0 -237
  180. data/test/spec_utils.rb +0 -742
  181. data/test/spec_version.rb +0 -11
  182. data/test/spec_webrick.rb +0 -206
  183. data/test/static/another/index.html +0 -1
  184. data/test/static/foo.html +0 -1
  185. data/test/static/index.html +0 -1
  186. data/test/testrequest.rb +0 -78
  187. data/test/unregistered_handler/rack/handler/unregistered.rb +0 -7
  188. data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +0 -7
data/test/spec_request.rb DELETED
@@ -1,1423 +0,0 @@
1
- require 'minitest/autorun'
2
- require 'stringio'
3
- require 'cgi'
4
- require 'rack/request'
5
- require 'rack/mock'
6
- require 'rack/multipart'
7
- require 'securerandom'
8
-
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
51
-
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
67
-
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 \
116
- Rack::MockRequest.env_for("/", "HTTP_HOST" => "www2.example.org")
117
- req.host.must_equal "www2.example.org"
118
-
119
- req = make_request \
120
- Rack::MockRequest.env_for("/", "SERVER_NAME" => "example.org", "SERVER_PORT" => "9292")
121
- req.host.must_equal "example.org"
122
-
123
- req = make_request \
124
- Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org:9292")
125
- req.host.must_equal "example.org"
126
-
127
- env = Rack::MockRequest.env_for("/", "SERVER_ADDR" => "192.168.1.1", "SERVER_PORT" => "9292")
128
- env.delete("SERVER_NAME")
129
- req = make_request(env)
130
- req.host.must_equal "192.168.1.1"
131
-
132
- env = Rack::MockRequest.env_for("/")
133
- env.delete("SERVER_NAME")
134
- req = make_request(env)
135
- req.host.must_equal ""
136
- end
137
-
138
- it "figure out the correct port" do
139
- req = make_request \
140
- Rack::MockRequest.env_for("/", "HTTP_HOST" => "www2.example.org")
141
- req.port.must_equal 80
142
-
143
- req = make_request \
144
- Rack::MockRequest.env_for("/", "HTTP_HOST" => "www2.example.org:81")
145
- req.port.must_equal 81
146
-
147
- req = make_request \
148
- Rack::MockRequest.env_for("/", "SERVER_NAME" => "example.org", "SERVER_PORT" => "9292")
149
- req.port.must_equal 9292
150
-
151
- req = make_request \
152
- Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org:9292")
153
- req.port.must_equal 9292
154
-
155
- req = make_request \
156
- Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org")
157
- req.port.must_equal 80
158
-
159
- req = make_request \
160
- Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org", "HTTP_X_FORWARDED_SSL" => "on")
161
- req.port.must_equal 443
162
-
163
- req = make_request \
164
- Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org", "HTTP_X_FORWARDED_PROTO" => "https")
165
- req.port.must_equal 443
166
-
167
- req = make_request \
168
- Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org", "HTTP_X_FORWARDED_PORT" => "9393")
169
- req.port.must_equal 9393
170
-
171
- req = make_request \
172
- Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org:9393", "SERVER_PORT" => "80")
173
- req.port.must_equal 9393
174
-
175
- req = make_request \
176
- Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org", "SERVER_PORT" => "9393")
177
- req.port.must_equal 80
178
-
179
- req = make_request \
180
- Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost", "HTTP_X_FORWARDED_PROTO" => "https", "SERVER_PORT" => "80")
181
- req.port.must_equal 443
182
-
183
- req = make_request \
184
- Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost", "HTTP_X_FORWARDED_PROTO" => "https,https", "SERVER_PORT" => "80")
185
- req.port.must_equal 443
186
- end
187
-
188
- it "figure out the correct host with port" do
189
- req = make_request \
190
- Rack::MockRequest.env_for("/", "HTTP_HOST" => "www2.example.org")
191
- req.host_with_port.must_equal "www2.example.org"
192
-
193
- req = make_request \
194
- Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81")
195
- req.host_with_port.must_equal "localhost:81"
196
-
197
- req = make_request \
198
- Rack::MockRequest.env_for("/", "SERVER_NAME" => "example.org", "SERVER_PORT" => "9292")
199
- req.host_with_port.must_equal "example.org:9292"
200
-
201
- req = make_request \
202
- Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org:9292")
203
- req.host_with_port.must_equal "example.org:9292"
204
-
205
- req = make_request \
206
- Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org", "SERVER_PORT" => "9393")
207
- req.host_with_port.must_equal "example.org"
208
- end
209
-
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"
216
- end
217
-
218
- it "not truncate query strings containing semi-colons #543 only in POST" do
219
- mr = Rack::MockRequest.env_for("/",
220
- "REQUEST_METHOD" => 'POST',
221
- :input => "foo=bar&quux=b;la")
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"
247
- end
248
-
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"
255
- end
256
-
257
- it "limit the keys from the GET query string" do
258
- env = Rack::MockRequest.env_for("/?foo=bar")
259
-
260
- old, Rack::Utils.key_space_limit = Rack::Utils.key_space_limit, 1
261
- begin
262
- req = make_request(env)
263
- lambda { req.GET }.must_raise RangeError
264
- ensure
265
- Rack::Utils.key_space_limit = old
266
- end
267
- end
268
-
269
- it "limit the key size per nested params hash" do
270
- nested_query = Rack::MockRequest.env_for("/?foo%5Bbar%5D%5Bbaz%5D%5Bqux%5D=1")
271
- plain_query = Rack::MockRequest.env_for("/?foo_bar__baz__qux_=1")
272
-
273
- old, Rack::Utils.key_space_limit = Rack::Utils.key_space_limit, 3
274
- begin
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
278
- ensure
279
- Rack::Utils.key_space_limit = old
280
- end
281
- end
282
-
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
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
326
- mr = Rack::MockRequest.env_for("/?foo=quux",
327
- "REQUEST_METHOD" => 'POST',
328
- :input => "a%=1"
329
- )
330
- req = make_request mr
331
-
332
- lambda { req.POST }.must_raise(Rack::Utils::InvalidParameterError).
333
- message.must_equal "invalid %-encoding (a%)"
334
- end
335
-
336
- it "raise if rack.input is missing" do
337
- req = make_request({})
338
- lambda { req.POST }.must_raise RuntimeError
339
- end
340
-
341
- it "parse POST data when method is POST and no Content-Type given" do
342
- req = make_request \
343
- Rack::MockRequest.env_for("/?foo=quux",
344
- "REQUEST_METHOD" => 'POST',
345
- :input => "foo=bar&quux=bla")
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"
352
- end
353
-
354
- it "limit the keys from the POST form data" do
355
- env = Rack::MockRequest.env_for("",
356
- "REQUEST_METHOD" => 'POST',
357
- :input => "foo=bar&quux=bla")
358
-
359
- old, Rack::Utils.key_space_limit = Rack::Utils.key_space_limit, 1
360
- begin
361
- req = make_request(env)
362
- lambda { req.POST }.must_raise RangeError
363
- ensure
364
- Rack::Utils.key_space_limit = old
365
- end
366
- end
367
-
368
- it "parse POST data with explicit content type regardless of method" do
369
- req = make_request \
370
- Rack::MockRequest.env_for("/",
371
- "CONTENT_TYPE" => 'application/x-www-form-urlencoded;foo=bar',
372
- :input => "foo=bar&quux=bla")
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"
378
- end
379
-
380
- it "not parse POST data when media type is not form-data" do
381
- req = make_request \
382
- Rack::MockRequest.env_for("/?foo=quux",
383
- "REQUEST_METHOD" => 'POST',
384
- "CONTENT_TYPE" => 'text/plain;charset=utf-8',
385
- :input => "foo=bar&quux=bla")
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"
392
- end
393
-
394
- it "parse POST data on PUT when media type is form-data" do
395
- req = make_request \
396
- Rack::MockRequest.env_for("/?foo=quux",
397
- "REQUEST_METHOD" => 'PUT',
398
- "CONTENT_TYPE" => 'application/x-www-form-urlencoded',
399
- :input => "foo=bar&quux=bla")
400
- req.POST.must_equal "foo" => "bar", "quux" => "bla"
401
- req.body.read.must_equal "foo=bar&quux=bla"
402
- end
403
-
404
- it "rewind input after parsing POST data" do
405
- input = StringIO.new("foo=bar&quux=bla")
406
- req = make_request \
407
- Rack::MockRequest.env_for("/",
408
- "CONTENT_TYPE" => 'application/x-www-form-urlencoded;foo=bar',
409
- :input => input)
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({})
426
- end
427
-
428
- it "clean up Safari's ajax POST body" do
429
- req = make_request \
430
- Rack::MockRequest.env_for("/",
431
- 'REQUEST_METHOD' => 'POST', :input => "foo=bar&quux=bla\0")
432
- req.POST.must_equal "foo" => "bar", "quux" => "bla"
433
- end
434
-
435
- it "get value by key from params with #[]" do
436
- req = make_request \
437
- Rack::MockRequest.env_for("?foo=quux")
438
- req['foo'].must_equal 'quux'
439
- req[:foo].must_equal 'quux'
440
- end
441
-
442
- it "set value to key on params with #[]=" do
443
- req = make_request \
444
- Rack::MockRequest.env_for("?foo=duh")
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
452
-
453
- req['foo'] = 'bar'
454
- req.params.must_equal 'foo' => 'bar'
455
- req['foo'].must_equal 'bar'
456
- req[:foo].must_equal 'bar'
457
-
458
- req[:foo] = 'jaz'
459
- req.params.must_equal 'foo' => 'jaz'
460
- req['foo'].must_equal 'jaz'
461
- req[:foo].must_equal 'jaz'
462
- end
463
-
464
- it "return values for the keys in the order given from values_at" do
465
- req = make_request \
466
- Rack::MockRequest.env_for("?foo=baz&wun=der&bar=ful")
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']
470
- end
471
-
472
- it "extract referrer correctly" do
473
- req = make_request \
474
- Rack::MockRequest.env_for("/", "HTTP_REFERER" => "/some/path")
475
- req.referer.must_equal "/some/path"
476
-
477
- req = make_request \
478
- Rack::MockRequest.env_for("/")
479
- req.referer.must_be_nil
480
- end
481
-
482
- it "extract user agent correctly" do
483
- req = make_request \
484
- Rack::MockRequest.env_for("/", "HTTP_USER_AGENT" => "Mozilla/4.0 (compatible)")
485
- req.user_agent.must_equal "Mozilla/4.0 (compatible)"
486
-
487
- req = make_request \
488
- Rack::MockRequest.env_for("/")
489
- req.user_agent.must_be_nil
490
- end
491
-
492
- it "treat missing content type as nil" do
493
- req = make_request \
494
- Rack::MockRequest.env_for("/")
495
- req.content_type.must_be_nil
496
- end
497
-
498
- it "treat empty content type as nil" do
499
- req = make_request \
500
- Rack::MockRequest.env_for("/", "CONTENT_TYPE" => "")
501
- req.content_type.must_be_nil
502
- end
503
-
504
- it "return nil media type for empty content type" do
505
- req = make_request \
506
- Rack::MockRequest.env_for("/", "CONTENT_TYPE" => "")
507
- req.media_type.must_be_nil
508
- end
509
-
510
- it "cache, but invalidates the cache" do
511
- req = make_request \
512
- Rack::MockRequest.env_for("/?foo=quux",
513
- "CONTENT_TYPE" => "application/x-www-form-urlencoded",
514
- :input => "foo=bar&quux=bla")
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"
520
-
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"
526
- end
527
-
528
- it "figure out if called via XHR" do
529
- req = make_request(Rack::MockRequest.env_for(""))
530
- req.wont_be :xhr?
531
-
532
- req = make_request \
533
- Rack::MockRequest.env_for("", "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest")
534
- req.must_be :xhr?
535
- end
536
-
537
- it "ssl detection" do
538
- request = make_request(Rack::MockRequest.env_for("/"))
539
- request.scheme.must_equal "http"
540
- request.wont_be :ssl?
541
-
542
- request = make_request(Rack::MockRequest.env_for("/", 'HTTPS' => 'on'))
543
- request.scheme.must_equal "https"
544
- request.must_be :ssl?
545
-
546
- request = make_request(Rack::MockRequest.env_for("/", 'rack.url_scheme' => 'https'))
547
- request.scheme.must_equal "https"
548
- request.must_be :ssl?
549
-
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?
553
-
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?
557
-
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?
561
-
562
- request = make_request(Rack::MockRequest.env_for("/", 'HTTP_X_FORWARDED_SCHEME' => 'https'))
563
- request.scheme.must_equal "https"
564
- request.must_be :ssl?
565
-
566
- request = make_request(Rack::MockRequest.env_for("/", 'HTTP_X_FORWARDED_PROTO' => 'https'))
567
- request.scheme.must_equal "https"
568
- request.must_be :ssl?
569
-
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?
573
- end
574
-
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'
578
- end
579
-
580
- it "parse cookies" do
581
- req = make_request \
582
- Rack::MockRequest.env_for("", "HTTP_COOKIE" => "foo=bar;quux=h&m")
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({})
587
- end
588
-
589
- it "always return the same hash object" do
590
- req = make_request \
591
- Rack::MockRequest.env_for("", "HTTP_COOKIE" => "foo=bar;quux=h&m")
592
- hash = req.cookies
593
- req.env.delete("HTTP_COOKIE")
594
- req.cookies.must_equal hash
595
- req.env["HTTP_COOKIE"] = "zoo=m"
596
- req.cookies.must_equal hash
597
- end
598
-
599
- it "modify the cookies hash in place" do
600
- req = make_request(Rack::MockRequest.env_for(""))
601
- req.cookies.must_equal({})
602
- req.cookies['foo'] = 'bar'
603
- req.cookies.must_equal 'foo' => 'bar'
604
- end
605
-
606
- it "not modify the params hash in place" do
607
- e = Rack::MockRequest.env_for("")
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({})
613
- req1.params['foo'] = 'bar'
614
- req1.params.must_equal 'foo' => 'bar'
615
- req2 = make_request(e)
616
- req2.params.must_equal({})
617
- end
618
-
619
- it "modify params hash if param is in GET" do
620
- e = Rack::MockRequest.env_for("?foo=duh")
621
- req1 = make_request(e)
622
- req1.params.must_equal 'foo' => 'duh'
623
- req1.update_param 'foo', 'bar'
624
- req1.params.must_equal 'foo' => 'bar'
625
- req2 = make_request(e)
626
- req2.params.must_equal 'foo' => 'bar'
627
- end
628
-
629
- it "modify params hash if param is in POST" do
630
- e = Rack::MockRequest.env_for("", "REQUEST_METHOD" => 'POST', :input => 'foo=duh')
631
- req1 = make_request(e)
632
- req1.params.must_equal 'foo' => 'duh'
633
- req1.update_param 'foo', 'bar'
634
- req1.params.must_equal 'foo' => 'bar'
635
- req2 = make_request(e)
636
- req2.params.must_equal 'foo' => 'bar'
637
- end
638
-
639
- it "modify params hash, even if param didn't exist before" do
640
- e = Rack::MockRequest.env_for("")
641
- req1 = make_request(e)
642
- req1.params.must_equal({})
643
- req1.update_param 'foo', 'bar'
644
- req1.params.must_equal 'foo' => 'bar'
645
- req2 = make_request(e)
646
- req2.params.must_equal 'foo' => 'bar'
647
- end
648
-
649
- it "modify params hash by changing only GET" do
650
- e = Rack::MockRequest.env_for("?foo=duhget")
651
- req = make_request(e)
652
- req.GET.must_equal 'foo' => 'duhget'
653
- req.POST.must_equal({})
654
- req.update_param 'foo', 'bar'
655
- req.GET.must_equal 'foo' => 'bar'
656
- req.POST.must_equal({})
657
- end
658
-
659
- it "modify params hash by changing only POST" do
660
- e = Rack::MockRequest.env_for("", "REQUEST_METHOD" => 'POST', :input => "foo=duhpost")
661
- req = make_request(e)
662
- req.GET.must_equal({})
663
- req.POST.must_equal 'foo' => 'duhpost'
664
- req.update_param 'foo', 'bar'
665
- req.GET.must_equal({})
666
- req.POST.must_equal 'foo' => 'bar'
667
- end
668
-
669
- it "modify params hash, even if param is defined in both POST and GET" do
670
- e = Rack::MockRequest.env_for("?foo=duhget", "REQUEST_METHOD" => 'POST', :input => "foo=duhpost")
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'
675
- req1.update_param 'foo', 'bar'
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'
684
- end
685
-
686
- it "allow deleting from params hash if param is in GET" do
687
- e = Rack::MockRequest.env_for("?foo=bar")
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({})
694
- end
695
-
696
- it "allow deleting from params hash if param is in POST" do
697
- e = Rack::MockRequest.env_for("", "REQUEST_METHOD" => 'POST', :input => 'foo=bar')
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({})
704
- end
705
-
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 "%"
709
- end
710
-
711
- it "parse cookies according to RFC 2109" do
712
- req = make_request \
713
- Rack::MockRequest.env_for('', 'HTTP_COOKIE' => 'foo=bar;foo=car')
714
- req.cookies.must_equal 'foo' => 'bar'
715
- end
716
-
717
- it 'parse cookies with quotes' do
718
- req = make_request Rack::MockRequest.env_for('', {
719
- 'HTTP_COOKIE' => '$Version="1"; Customer="WILE_E_COYOTE"; $Path="/acme"; Part_Number="Rocket_Launcher_0001"; $Path="/acme"'
720
- })
721
- req.cookies.must_equal({
722
- '$Version' => '"1"',
723
- 'Customer' => '"WILE_E_COYOTE"',
724
- '$Path' => '"/acme"',
725
- 'Part_Number' => '"Rocket_Launcher_0001"',
726
- })
727
- end
728
-
729
- it "provide setters" do
730
- req = make_request(e=Rack::MockRequest.env_for(""))
731
- req.script_name.must_equal ""
732
- req.script_name = "/foo"
733
- req.script_name.must_equal "/foo"
734
- e["SCRIPT_NAME"].must_equal "/foo"
735
-
736
- req.path_info.must_equal "/"
737
- req.path_info = "/foo"
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 \
795
- Rack::MockRequest.env_for("/",
796
- "CONTENT_TYPE" => 'text/plain; foo=BAR,baz=bizzle dizzle;BLING=bam;blong="boo";zump="zoo\"o";weird=lol"')
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
811
- # Adapted from RFC 1867.
812
- input = <<EOF
813
- blah blah\r
814
- \r
815
- --AaB03x\r
816
- content-disposition: form-data; name="reply"\r
817
- \r
818
- yes\r
819
- --AaB03x\r
820
- content-disposition: form-data; name="fileupload"; filename="dj.jpg"\r
821
- Content-Type: image/jpeg\r
822
- Content-Transfer-Encoding: base64\r
823
- \r
824
- /9j/4AAQSkZJRgABAQAAAQABAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcg\r
825
- --AaB03x--\r
826
- EOF
827
- req = make_request Rack::MockRequest.env_for("/",
828
- "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
829
- "CONTENT_LENGTH" => input.size,
830
- :input => input)
831
-
832
- req.POST.must_include "fileupload"
833
- req.POST.must_include "reply"
834
-
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'
840
-
841
- req.POST["reply"].must_equal "yes"
842
-
843
- f = req.POST["fileupload"]
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
849
- end
850
-
851
- it "not infinite loop with a malformed HTTP request" do
852
- # Adapted from RFC 1867.
853
- input = <<EOF
854
- --AaB03x
855
- content-disposition: form-data; name="reply"
856
-
857
- yes
858
- --AaB03x
859
- content-disposition: form-data; name="fileupload"; filename="dj.jpg"
860
- Content-Type: image/jpeg
861
- Content-Transfer-Encoding: base64
862
-
863
- /9j/4AAQSkZJRgABAQAAAQABAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcg
864
- --AaB03x--
865
- EOF
866
- req = make_request Rack::MockRequest.env_for("/",
867
- "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
868
- "CONTENT_LENGTH" => input.size,
869
- :input => input)
870
-
871
- lambda{req.POST}.must_raise EOFError
872
- end
873
-
874
-
875
- it "parse multipart form data" do
876
- # Adapted from RFC 1867.
877
- input = <<EOF
878
- --AaB03x\r
879
- content-disposition: form-data; name="reply"\r
880
- \r
881
- yes\r
882
- --AaB03x\r
883
- content-disposition: form-data; name="fileupload"; filename="dj.jpg"\r
884
- Content-Type: image/jpeg\r
885
- Content-Transfer-Encoding: base64\r
886
- \r
887
- /9j/4AAQSkZJRgABAQAAAQABAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcg\r
888
- --AaB03x--\r
889
- EOF
890
- req = make_request Rack::MockRequest.env_for("/",
891
- "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
892
- "CONTENT_LENGTH" => input.size,
893
- :input => input)
894
-
895
- req.POST.must_include "fileupload"
896
- req.POST.must_include "reply"
897
-
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'
903
-
904
- req.POST["reply"].must_equal "yes"
905
-
906
- f = req.POST["fileupload"]
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
944
- end
945
-
946
- it 'closes tempfiles it created in the case of too many created' do
947
- begin
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")
949
- data += "--AaB03x--\r"
950
-
951
- files = []
952
- options = {
953
- "CONTENT_TYPE" => "multipart/form-data; boundary=AaB03x",
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
- },
960
- :input => StringIO.new(data)
961
- }
962
-
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? }
969
- end
970
- end
971
-
972
- it "parse big multipart form data" do
973
- input = <<EOF
974
- --AaB03x\r
975
- content-disposition: form-data; name="huge"; filename="huge"\r
976
- \r
977
- #{"x"*32768}\r
978
- --AaB03x\r
979
- content-disposition: form-data; name="mean"; filename="mean"\r
980
- \r
981
- --AaB03xha\r
982
- --AaB03x--\r
983
- EOF
984
- req = make_request Rack::MockRequest.env_for("/",
985
- "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
986
- "CONTENT_LENGTH" => input.size,
987
- :input => input)
988
-
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"
992
- end
993
-
994
- it "record tempfiles from multipart form data in env[rack.tempfiles]" do
995
- input = <<EOF
996
- --AaB03x\r
997
- content-disposition: form-data; name="fileupload"; filename="foo.jpg"\r
998
- Content-Type: image/jpeg\r
999
- Content-Transfer-Encoding: base64\r
1000
- \r
1001
- /9j/4AAQSkZJRgABAQAAAQABAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcg\r
1002
- --AaB03x\r
1003
- content-disposition: form-data; name="fileupload"; filename="bar.jpg"\r
1004
- Content-Type: image/jpeg\r
1005
- Content-Transfer-Encoding: base64\r
1006
- \r
1007
- /9j/4AAQSkZJRgABAQAAAQABAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcg\r
1008
- --AaB03x--\r
1009
- EOF
1010
- env = Rack::MockRequest.env_for("/",
1011
- "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
1012
- "CONTENT_LENGTH" => input.size,
1013
- :input => input)
1014
- req = make_request(env)
1015
- req.params
1016
- env['rack.tempfiles'].size.must_equal 2
1017
- end
1018
-
1019
- it "detect invalid multipart form data" do
1020
- input = <<EOF
1021
- --AaB03x\r
1022
- content-disposition: form-data; name="huge"; filename="huge"\r
1023
- EOF
1024
- req = make_request Rack::MockRequest.env_for("/",
1025
- "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
1026
- "CONTENT_LENGTH" => input.size,
1027
- :input => input)
1028
-
1029
- lambda { req.POST }.must_raise EOFError
1030
-
1031
- input = <<EOF
1032
- --AaB03x\r
1033
- content-disposition: form-data; name="huge"; filename="huge"\r
1034
- \r
1035
- foo\r
1036
- EOF
1037
- req = make_request Rack::MockRequest.env_for("/",
1038
- "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
1039
- "CONTENT_LENGTH" => input.size,
1040
- :input => input)
1041
-
1042
- lambda { req.POST }.must_raise EOFError
1043
-
1044
- input = <<EOF
1045
- --AaB03x\r
1046
- content-disposition: form-data; name="huge"; filename="huge"\r
1047
- \r
1048
- foo\r
1049
- EOF
1050
- req = make_request Rack::MockRequest.env_for("/",
1051
- "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
1052
- "CONTENT_LENGTH" => input.size,
1053
- :input => input)
1054
-
1055
- lambda { req.POST }.must_raise EOFError
1056
- end
1057
-
1058
- it "consistently raise EOFError on bad multipart form data" do
1059
- input = <<EOF
1060
- --AaB03x\r
1061
- content-disposition: form-data; name="huge"; filename="huge"\r
1062
- EOF
1063
- req = make_request Rack::MockRequest.env_for("/",
1064
- "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
1065
- "CONTENT_LENGTH" => input.size,
1066
- :input => input)
1067
-
1068
- lambda { req.POST }.must_raise EOFError
1069
- lambda { req.POST }.must_raise EOFError
1070
- end
1071
-
1072
- it "correctly parse the part name from Content-Id header" do
1073
- input = <<EOF
1074
- --AaB03x\r
1075
- Content-Type: text/xml; charset=utf-8\r
1076
- Content-Id: <soap-start>\r
1077
- Content-Transfer-Encoding: 7bit\r
1078
- \r
1079
- foo\r
1080
- --AaB03x--\r
1081
- EOF
1082
- req = make_request Rack::MockRequest.env_for("/",
1083
- "CONTENT_TYPE" => "multipart/related, boundary=AaB03x",
1084
- "CONTENT_LENGTH" => input.size,
1085
- :input => input)
1086
-
1087
- req.params.keys.must_equal ["<soap-start>"]
1088
- end
1089
-
1090
- it "not try to interpret binary as utf8" do
1091
- input = <<EOF
1092
- --AaB03x\r
1093
- content-disposition: form-data; name="fileupload"; filename="junk.a"\r
1094
- content-type: application/octet-stream\r
1095
- \r
1096
- #{[0x36,0xCF,0x0A,0xF8].pack('c*')}\r
1097
- --AaB03x--\r
1098
- EOF
1099
-
1100
- req = make_request Rack::MockRequest.env_for("/",
1101
- "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
1102
- "CONTENT_LENGTH" => input.size,
1103
- :input => input)
1104
-
1105
- req.POST["fileupload"][:tempfile].size.must_equal 4
1106
- end
1107
-
1108
- it "use form_hash when form_input is a Tempfile" do
1109
- input = "{foo: 'bar'}"
1110
-
1111
- rack_input = Tempfile.new("rackspec")
1112
- rack_input.write(input)
1113
- rack_input.rewind
1114
-
1115
- req = make_request Rack::MockRequest.env_for("/",
1116
- "rack.request.form_hash" => {'foo' => 'bar'},
1117
- "rack.request.form_input" => rack_input,
1118
- :input => rack_input)
1119
-
1120
- req.POST.must_equal req.env['rack.request.form_hash']
1121
- end
1122
-
1123
- it "conform to the Rack spec" do
1124
- app = lambda { |env|
1125
- content = make_request(env).POST["file"].inspect
1126
- size = content.bytesize
1127
- [200, {"Content-Type" => "text/html", "Content-Length" => size.to_s}, [content]]
1128
- }
1129
-
1130
- input = <<EOF
1131
- --AaB03x\r
1132
- content-disposition: form-data; name="reply"\r
1133
- \r
1134
- yes\r
1135
- --AaB03x\r
1136
- content-disposition: form-data; name="fileupload"; filename="dj.jpg"\r
1137
- Content-Type: image/jpeg\r
1138
- Content-Transfer-Encoding: base64\r
1139
- \r
1140
- /9j/4AAQSkZJRgABAQAAAQABAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcg\r
1141
- --AaB03x--\r
1142
- EOF
1143
- input.force_encoding(Encoding::ASCII_8BIT)
1144
- res = Rack::MockRequest.new(Rack::Lint.new(app)).get "/",
1145
- "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
1146
- "CONTENT_LENGTH" => input.size.to_s, "rack.input" => StringIO.new(input)
1147
-
1148
- res.must_be :ok?
1149
- end
1150
-
1151
- it "parse Accept-Encoding correctly" do
1152
- parser = lambda do |x|
1153
- make_request(Rack::MockRequest.env_for("", "HTTP_ACCEPT_ENCODING" => x)).accept_encoding
1154
- end
1155
-
1156
- parser.call(nil).must_equal []
1157
-
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] ]
1163
-
1164
- parser.call("gzip ; q=0.9").must_equal [["gzip", 0.9]]
1165
- parser.call("gzip ; deflate").must_equal [["gzip", 1.0]]
1166
- end
1167
-
1168
- it "parse Accept-Language correctly" do
1169
- parser = lambda do |x|
1170
- make_request(Rack::MockRequest.env_for("", "HTTP_ACCEPT_LANGUAGE" => x)).accept_language
1171
- end
1172
-
1173
- parser.call(nil).must_equal []
1174
-
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] ]
1180
-
1181
- parser.call("fr ; q=0.9").must_equal [["fr", 0.9]]
1182
- parser.call("fr").must_equal [["fr", 1.0]]
1183
- end
1184
-
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
1193
-
1194
- it 'provide ip information' do
1195
- mock = Rack::MockRequest.new(Rack::Lint.new(ip_app))
1196
-
1197
- res = mock.get '/', 'REMOTE_ADDR' => '1.2.3.4'
1198
- res.body.must_equal '1.2.3.4'
1199
-
1200
- res = mock.get '/', 'REMOTE_ADDR' => 'fe80::202:b3ff:fe1e:8329'
1201
- res.body.must_equal 'fe80::202:b3ff:fe1e:8329'
1202
-
1203
- res = mock.get '/', 'REMOTE_ADDR' => '1.2.3.4,3.4.5.6'
1204
- res.body.must_equal '1.2.3.4'
1205
- end
1206
-
1207
- it 'deals with proxies' do
1208
- mock = Rack::MockRequest.new(Rack::Lint.new(ip_app))
1209
-
1210
- res = mock.get '/',
1211
- 'REMOTE_ADDR' => '1.2.3.4',
1212
- 'HTTP_X_FORWARDED_FOR' => '3.4.5.6'
1213
- res.body.must_equal '1.2.3.4'
1214
-
1215
- res = mock.get '/',
1216
- 'REMOTE_ADDR' => '1.2.3.4',
1217
- 'HTTP_X_FORWARDED_FOR' => 'unknown'
1218
- res.body.must_equal '1.2.3.4'
1219
-
1220
- res = mock.get '/',
1221
- 'REMOTE_ADDR' => '127.0.0.1',
1222
- 'HTTP_X_FORWARDED_FOR' => '3.4.5.6'
1223
- res.body.must_equal '3.4.5.6'
1224
-
1225
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => 'unknown,3.4.5.6'
1226
- res.body.must_equal '3.4.5.6'
1227
-
1228
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '192.168.0.1,3.4.5.6'
1229
- res.body.must_equal '3.4.5.6'
1230
-
1231
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '10.0.0.1,3.4.5.6'
1232
- res.body.must_equal '3.4.5.6'
1233
-
1234
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '10.0.0.1, 10.0.0.1, 3.4.5.6'
1235
- res.body.must_equal '3.4.5.6'
1236
-
1237
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '127.0.0.1, 3.4.5.6'
1238
- res.body.must_equal '3.4.5.6'
1239
-
1240
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => 'unknown,192.168.0.1'
1241
- res.body.must_equal 'unknown'
1242
-
1243
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => 'other,unknown,192.168.0.1'
1244
- res.body.must_equal 'unknown'
1245
-
1246
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => 'unknown,localhost,192.168.0.1'
1247
- res.body.must_equal 'unknown'
1248
-
1249
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '9.9.9.9, 3.4.5.6, 10.0.0.1, 172.31.4.4'
1250
- res.body.must_equal '3.4.5.6'
1251
-
1252
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '::1,2620:0:1c00:0:812c:9583:754b:ca11'
1253
- res.body.must_equal '2620:0:1c00:0:812c:9583:754b:ca11'
1254
-
1255
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '2620:0:1c00:0:812c:9583:754b:ca11,::1'
1256
- res.body.must_equal '2620:0:1c00:0:812c:9583:754b:ca11'
1257
-
1258
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => 'fd5b:982e:9130:247f:0000:0000:0000:0000,2620:0:1c00:0:812c:9583:754b:ca11'
1259
- res.body.must_equal '2620:0:1c00:0:812c:9583:754b:ca11'
1260
-
1261
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '2620:0:1c00:0:812c:9583:754b:ca11,fd5b:982e:9130:247f:0000:0000:0000:0000'
1262
- res.body.must_equal '2620:0:1c00:0:812c:9583:754b:ca11'
1263
-
1264
- res = mock.get '/',
1265
- 'HTTP_X_FORWARDED_FOR' => '1.1.1.1, 127.0.0.1',
1266
- 'HTTP_CLIENT_IP' => '1.1.1.1'
1267
- res.body.must_equal '1.1.1.1'
1268
-
1269
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '8.8.8.8, 9.9.9.9'
1270
- res.body.must_equal '9.9.9.9'
1271
-
1272
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '8.8.8.8, fe80::202:b3ff:fe1e:8329'
1273
- res.body.must_equal 'fe80::202:b3ff:fe1e:8329'
1274
-
1275
- # Unix Sockets
1276
- res = mock.get '/',
1277
- 'REMOTE_ADDR' => 'unix',
1278
- 'HTTP_X_FORWARDED_FOR' => '3.4.5.6'
1279
- res.body.must_equal '3.4.5.6'
1280
-
1281
- res = mock.get '/',
1282
- 'REMOTE_ADDR' => 'unix:/tmp/foo',
1283
- 'HTTP_X_FORWARDED_FOR' => '3.4.5.6'
1284
- res.body.must_equal '3.4.5.6'
1285
- end
1286
-
1287
- it "not allow IP spoofing via Client-IP and X-Forwarded-For headers" do
1288
- mock = Rack::MockRequest.new(Rack::Lint.new(ip_app))
1289
-
1290
- # IP Spoofing attempt:
1291
- # Client sends X-Forwarded-For: 6.6.6.6
1292
- # Client-IP: 6.6.6.6
1293
- # Load balancer adds X-Forwarded-For: 2.2.2.3, 192.168.0.7
1294
- # App receives: X-Forwarded-For: 6.6.6.6
1295
- # X-Forwarded-For: 2.2.2.3, 192.168.0.7
1296
- # Client-IP: 6.6.6.6
1297
- # Rack env: HTTP_X_FORWARDED_FOR: '6.6.6.6, 2.2.2.3, 192.168.0.7'
1298
- # HTTP_CLIENT_IP: '6.6.6.6'
1299
- res = mock.get '/',
1300
- 'HTTP_X_FORWARDED_FOR' => '6.6.6.6, 2.2.2.3, 192.168.0.7',
1301
- 'HTTP_CLIENT_IP' => '6.6.6.6'
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
1341
- end
1342
-
1343
- class MyRequest < Rack::Request
1344
- def params
1345
- {:foo => "bar"}
1346
- end
1347
- end
1348
-
1349
- it "allow subclass request to be instantiated after parent request" do
1350
- env = Rack::MockRequest.env_for("/?foo=bar")
1351
-
1352
- req1 = make_request(env)
1353
- req1.GET.must_equal "foo" => "bar"
1354
- req1.params.must_equal "foo" => "bar"
1355
-
1356
- req2 = MyRequest.new(env)
1357
- req2.GET.must_equal "foo" => "bar"
1358
- req2.params.must_equal :foo => "bar"
1359
- end
1360
-
1361
- it "allow parent request to be instantiated after subclass request" do
1362
- env = Rack::MockRequest.env_for("/?foo=bar")
1363
-
1364
- req1 = MyRequest.new(env)
1365
- req1.GET.must_equal "foo" => "bar"
1366
- req1.params.must_equal :foo => "bar"
1367
-
1368
- req2 = make_request(env)
1369
- req2.GET.must_equal "foo" => "bar"
1370
- req2.params.must_equal "foo" => "bar"
1371
- end
1372
-
1373
- it "raise TypeError every time if request parameters are broken" do
1374
- broken_query = Rack::MockRequest.env_for("/?foo%5B%5D=0&foo%5Bbar%5D=1")
1375
- req = make_request(broken_query)
1376
- lambda{req.GET}.must_raise TypeError
1377
- lambda{req.params}.must_raise TypeError
1378
- end
1379
-
1380
- (0x20...0x7E).collect { |a|
1381
- b = a.chr
1382
- c = CGI.escape(b)
1383
- it "not strip '#{a}' => '#{c}' => '#{b}' escaped character from parameters when accessed as string" do
1384
- url = "/?foo=#{c}bar#{c}"
1385
- env = Rack::MockRequest.env_for(url)
1386
- req2 = make_request(env)
1387
- req2.GET.must_equal "foo" => "#{b}bar#{b}"
1388
- req2.params.must_equal "foo" => "#{b}bar#{b}"
1389
- end
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
1423
- end