rack 1.6.11 → 2.1.4

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 (187) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +77 -0
  3. data/{COPYING → MIT-LICENSE} +4 -2
  4. data/README.rdoc +89 -139
  5. data/Rakefile +27 -28
  6. data/SPEC +6 -7
  7. data/bin/rackup +1 -0
  8. data/contrib/rack_logo.svg +164 -111
  9. data/example/lobster.ru +2 -0
  10. data/example/protectedlobster.rb +4 -2
  11. data/example/protectedlobster.ru +3 -1
  12. data/lib/rack/auth/abstract/handler.rb +3 -1
  13. data/lib/rack/auth/abstract/request.rb +7 -1
  14. data/lib/rack/auth/basic.rb +4 -1
  15. data/lib/rack/auth/digest/md5.rb +9 -7
  16. data/lib/rack/auth/digest/nonce.rb +6 -3
  17. data/lib/rack/auth/digest/params.rb +5 -4
  18. data/lib/rack/auth/digest/request.rb +3 -1
  19. data/lib/rack/body_proxy.rb +11 -9
  20. data/lib/rack/builder.rb +42 -18
  21. data/lib/rack/cascade.rb +6 -5
  22. data/lib/rack/chunked.rb +33 -10
  23. data/lib/rack/{commonlogger.rb → common_logger.rb} +11 -10
  24. data/lib/rack/{conditionalget.rb → conditional_get.rb} +3 -1
  25. data/lib/rack/config.rb +2 -0
  26. data/lib/rack/content_length.rb +5 -3
  27. data/lib/rack/content_type.rb +3 -1
  28. data/lib/rack/core_ext/regexp.rb +14 -0
  29. data/lib/rack/deflater.rb +33 -53
  30. data/lib/rack/directory.rb +75 -60
  31. data/lib/rack/etag.rb +8 -5
  32. data/lib/rack/events.rb +156 -0
  33. data/lib/rack/file.rb +4 -149
  34. data/lib/rack/files.rb +178 -0
  35. data/lib/rack/handler/cgi.rb +18 -17
  36. data/lib/rack/handler/fastcgi.rb +17 -16
  37. data/lib/rack/handler/lsws.rb +14 -12
  38. data/lib/rack/handler/scgi.rb +22 -19
  39. data/lib/rack/handler/thin.rb +6 -1
  40. data/lib/rack/handler/webrick.rb +28 -28
  41. data/lib/rack/handler.rb +9 -26
  42. data/lib/rack/head.rb +17 -17
  43. data/lib/rack/lint.rb +54 -51
  44. data/lib/rack/lobster.rb +8 -6
  45. data/lib/rack/lock.rb +17 -10
  46. data/lib/rack/logger.rb +4 -2
  47. data/lib/rack/media_type.rb +43 -0
  48. data/lib/rack/{methodoverride.rb → method_override.rb} +10 -8
  49. data/lib/rack/mime.rb +27 -6
  50. data/lib/rack/mock.rb +101 -60
  51. data/lib/rack/multipart/generator.rb +11 -12
  52. data/lib/rack/multipart/parser.rb +280 -161
  53. data/lib/rack/multipart/uploaded_file.rb +3 -2
  54. data/lib/rack/multipart.rb +39 -8
  55. data/lib/rack/{nulllogger.rb → null_logger.rb} +3 -1
  56. data/lib/rack/query_parser.rb +218 -0
  57. data/lib/rack/recursive.rb +11 -9
  58. data/lib/rack/reloader.rb +10 -4
  59. data/lib/rack/request.rb +447 -305
  60. data/lib/rack/response.rb +196 -83
  61. data/lib/rack/rewindable_input.rb +5 -14
  62. data/lib/rack/runtime.rb +12 -18
  63. data/lib/rack/sendfile.rb +19 -14
  64. data/lib/rack/server.rb +118 -41
  65. data/lib/rack/session/abstract/id.rb +215 -94
  66. data/lib/rack/session/cookie.rb +45 -28
  67. data/lib/rack/session/memcache.rb +4 -87
  68. data/lib/rack/session/pool.rb +25 -16
  69. data/lib/rack/show_exceptions.rb +392 -0
  70. data/lib/rack/{showstatus.rb → show_status.rb} +7 -5
  71. data/lib/rack/static.rb +41 -11
  72. data/lib/rack/tempfile_reaper.rb +4 -2
  73. data/lib/rack/urlmap.rb +25 -15
  74. data/lib/rack/utils.rb +186 -272
  75. data/lib/rack.rb +76 -24
  76. data/rack.gemspec +25 -14
  77. metadata +62 -182
  78. data/HISTORY.md +0 -375
  79. data/KNOWN-ISSUES +0 -44
  80. data/lib/rack/backports/uri/common_18.rb +0 -56
  81. data/lib/rack/backports/uri/common_192.rb +0 -52
  82. data/lib/rack/backports/uri/common_193.rb +0 -29
  83. data/lib/rack/handler/evented_mongrel.rb +0 -8
  84. data/lib/rack/handler/mongrel.rb +0 -106
  85. data/lib/rack/handler/swiftiplied_mongrel.rb +0 -8
  86. data/lib/rack/showexceptions.rb +0 -387
  87. data/lib/rack/utils/okjson.rb +0 -600
  88. data/test/builder/anything.rb +0 -5
  89. data/test/builder/comment.ru +0 -4
  90. data/test/builder/end.ru +0 -5
  91. data/test/builder/line.ru +0 -1
  92. data/test/builder/options.ru +0 -2
  93. data/test/cgi/assets/folder/test.js +0 -1
  94. data/test/cgi/assets/fonts/font.eot +0 -1
  95. data/test/cgi/assets/images/image.png +0 -1
  96. data/test/cgi/assets/index.html +0 -1
  97. data/test/cgi/assets/javascripts/app.js +0 -1
  98. data/test/cgi/assets/stylesheets/app.css +0 -1
  99. data/test/cgi/lighttpd.conf +0 -26
  100. data/test/cgi/rackup_stub.rb +0 -6
  101. data/test/cgi/sample_rackup.ru +0 -5
  102. data/test/cgi/test +0 -9
  103. data/test/cgi/test+directory/test+file +0 -1
  104. data/test/cgi/test.fcgi +0 -8
  105. data/test/cgi/test.ru +0 -5
  106. data/test/gemloader.rb +0 -10
  107. data/test/multipart/bad_robots +0 -259
  108. data/test/multipart/binary +0 -0
  109. data/test/multipart/content_type_and_no_filename +0 -6
  110. data/test/multipart/empty +0 -10
  111. data/test/multipart/fail_16384_nofile +0 -814
  112. data/test/multipart/file1.txt +0 -1
  113. data/test/multipart/filename_and_modification_param +0 -7
  114. data/test/multipart/filename_and_no_name +0 -6
  115. data/test/multipart/filename_with_escaped_quotes +0 -6
  116. data/test/multipart/filename_with_escaped_quotes_and_modification_param +0 -7
  117. data/test/multipart/filename_with_null_byte +0 -7
  118. data/test/multipart/filename_with_percent_escaped_quotes +0 -6
  119. data/test/multipart/filename_with_unescaped_percentages +0 -6
  120. data/test/multipart/filename_with_unescaped_percentages2 +0 -6
  121. data/test/multipart/filename_with_unescaped_percentages3 +0 -6
  122. data/test/multipart/filename_with_unescaped_quotes +0 -6
  123. data/test/multipart/ie +0 -6
  124. data/test/multipart/invalid_character +0 -6
  125. data/test/multipart/mixed_files +0 -21
  126. data/test/multipart/nested +0 -10
  127. data/test/multipart/none +0 -9
  128. data/test/multipart/semicolon +0 -6
  129. data/test/multipart/text +0 -15
  130. data/test/multipart/three_files_three_fields +0 -31
  131. data/test/multipart/webkit +0 -32
  132. data/test/rackup/config.ru +0 -31
  133. data/test/registering_handler/rack/handler/registering_myself.rb +0 -8
  134. data/test/spec_auth_basic.rb +0 -81
  135. data/test/spec_auth_digest.rb +0 -259
  136. data/test/spec_body_proxy.rb +0 -85
  137. data/test/spec_builder.rb +0 -223
  138. data/test/spec_cascade.rb +0 -61
  139. data/test/spec_cgi.rb +0 -102
  140. data/test/spec_chunked.rb +0 -101
  141. data/test/spec_commonlogger.rb +0 -93
  142. data/test/spec_conditionalget.rb +0 -102
  143. data/test/spec_config.rb +0 -22
  144. data/test/spec_content_length.rb +0 -85
  145. data/test/spec_content_type.rb +0 -45
  146. data/test/spec_deflater.rb +0 -339
  147. data/test/spec_directory.rb +0 -88
  148. data/test/spec_etag.rb +0 -107
  149. data/test/spec_fastcgi.rb +0 -107
  150. data/test/spec_file.rb +0 -221
  151. data/test/spec_handler.rb +0 -72
  152. data/test/spec_head.rb +0 -45
  153. data/test/spec_lint.rb +0 -550
  154. data/test/spec_lobster.rb +0 -58
  155. data/test/spec_lock.rb +0 -164
  156. data/test/spec_logger.rb +0 -23
  157. data/test/spec_methodoverride.rb +0 -111
  158. data/test/spec_mime.rb +0 -51
  159. data/test/spec_mock.rb +0 -297
  160. data/test/spec_mongrel.rb +0 -182
  161. data/test/spec_multipart.rb +0 -600
  162. data/test/spec_nulllogger.rb +0 -20
  163. data/test/spec_recursive.rb +0 -72
  164. data/test/spec_request.rb +0 -1232
  165. data/test/spec_response.rb +0 -407
  166. data/test/spec_rewindable_input.rb +0 -118
  167. data/test/spec_runtime.rb +0 -49
  168. data/test/spec_sendfile.rb +0 -130
  169. data/test/spec_server.rb +0 -167
  170. data/test/spec_session_abstract_id.rb +0 -53
  171. data/test/spec_session_cookie.rb +0 -410
  172. data/test/spec_session_memcache.rb +0 -321
  173. data/test/spec_session_pool.rb +0 -209
  174. data/test/spec_showexceptions.rb +0 -98
  175. data/test/spec_showstatus.rb +0 -103
  176. data/test/spec_static.rb +0 -145
  177. data/test/spec_tempfile_reaper.rb +0 -63
  178. data/test/spec_thin.rb +0 -91
  179. data/test/spec_urlmap.rb +0 -236
  180. data/test/spec_utils.rb +0 -647
  181. data/test/spec_version.rb +0 -17
  182. data/test/spec_webrick.rb +0 -184
  183. data/test/static/another/index.html +0 -1
  184. data/test/static/index.html +0 -1
  185. data/test/testrequest.rb +0 -78
  186. data/test/unregistered_handler/rack/handler/unregistered.rb +0 -7
  187. data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +0 -7
data/test/spec_request.rb DELETED
@@ -1,1232 +0,0 @@
1
- require 'stringio'
2
- require 'cgi'
3
- require 'rack/request'
4
- require 'rack/mock'
5
- require 'securerandom'
6
-
7
- describe Rack::Request do
8
- should "wrap the rack variables" do
9
- req = Rack::Request.new(Rack::MockRequest.env_for("http://example.com:8080/"))
10
-
11
- req.body.should.respond_to? :gets
12
- req.scheme.should.equal "http"
13
- req.request_method.should.equal "GET"
14
-
15
- req.should.be.get
16
- req.should.not.be.post
17
- req.should.not.be.put
18
- req.should.not.be.delete
19
- req.should.not.be.head
20
- req.should.not.be.patch
21
-
22
- req.script_name.should.equal ""
23
- req.path_info.should.equal "/"
24
- req.query_string.should.equal ""
25
-
26
- req.host.should.equal "example.com"
27
- req.port.should.equal 8080
28
-
29
- req.content_length.should.equal "0"
30
- req.content_type.should.be.nil
31
- end
32
-
33
- should "figure out the correct host" do
34
- req = Rack::Request.new \
35
- Rack::MockRequest.env_for("/", "HTTP_HOST" => "www2.example.org")
36
- req.host.should.equal "www2.example.org"
37
-
38
- req = Rack::Request.new \
39
- Rack::MockRequest.env_for("/", "SERVER_NAME" => "example.org", "SERVER_PORT" => "9292")
40
- req.host.should.equal "example.org"
41
-
42
- req = Rack::Request.new \
43
- Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org:9292")
44
- req.host.should.equal "example.org"
45
-
46
- env = Rack::MockRequest.env_for("/", "SERVER_ADDR" => "192.168.1.1", "SERVER_PORT" => "9292")
47
- env.delete("SERVER_NAME")
48
- req = Rack::Request.new(env)
49
- req.host.should.equal "192.168.1.1"
50
-
51
- env = Rack::MockRequest.env_for("/")
52
- env.delete("SERVER_NAME")
53
- req = Rack::Request.new(env)
54
- req.host.should.equal ""
55
- end
56
-
57
- should "figure out the correct port" do
58
- req = Rack::Request.new \
59
- Rack::MockRequest.env_for("/", "HTTP_HOST" => "www2.example.org")
60
- req.port.should.equal 80
61
-
62
- req = Rack::Request.new \
63
- Rack::MockRequest.env_for("/", "HTTP_HOST" => "www2.example.org:81")
64
- req.port.should.equal 81
65
-
66
- req = Rack::Request.new \
67
- Rack::MockRequest.env_for("/", "SERVER_NAME" => "example.org", "SERVER_PORT" => "9292")
68
- req.port.should.equal 9292
69
-
70
- req = Rack::Request.new \
71
- Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org:9292")
72
- req.port.should.equal 9292
73
-
74
- req = Rack::Request.new \
75
- Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org")
76
- req.port.should.equal 80
77
-
78
- req = Rack::Request.new \
79
- Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org", "HTTP_X_FORWARDED_SSL" => "on")
80
- req.port.should.equal 443
81
-
82
- req = Rack::Request.new \
83
- Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org", "HTTP_X_FORWARDED_PROTO" => "https")
84
- req.port.should.equal 443
85
-
86
- req = Rack::Request.new \
87
- Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org", "HTTP_X_FORWARDED_PORT" => "9393")
88
- req.port.should.equal 9393
89
-
90
- req = Rack::Request.new \
91
- Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org:9393", "SERVER_PORT" => "80")
92
- req.port.should.equal 9393
93
-
94
- req = Rack::Request.new \
95
- Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org", "SERVER_PORT" => "9393")
96
- req.port.should.equal 80
97
-
98
- req = Rack::Request.new \
99
- Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost", "HTTP_X_FORWARDED_PROTO" => "https", "SERVER_PORT" => "80")
100
- req.port.should.equal 443
101
-
102
- req = Rack::Request.new \
103
- Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost", "HTTP_X_FORWARDED_PROTO" => "https,https", "SERVER_PORT" => "80")
104
- req.port.should.equal 443
105
- end
106
-
107
- should "figure out the correct host with port" do
108
- req = Rack::Request.new \
109
- Rack::MockRequest.env_for("/", "HTTP_HOST" => "www2.example.org")
110
- req.host_with_port.should.equal "www2.example.org"
111
-
112
- req = Rack::Request.new \
113
- Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81")
114
- req.host_with_port.should.equal "localhost:81"
115
-
116
- req = Rack::Request.new \
117
- Rack::MockRequest.env_for("/", "SERVER_NAME" => "example.org", "SERVER_PORT" => "9292")
118
- req.host_with_port.should.equal "example.org:9292"
119
-
120
- req = Rack::Request.new \
121
- Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org:9292")
122
- req.host_with_port.should.equal "example.org:9292"
123
-
124
- req = Rack::Request.new \
125
- Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org", "SERVER_PORT" => "9393")
126
- req.host_with_port.should.equal "example.org"
127
- end
128
-
129
- should "parse the query string" do
130
- req = Rack::Request.new(Rack::MockRequest.env_for("/?foo=bar&quux=bla"))
131
- req.query_string.should.equal "foo=bar&quux=bla"
132
- req.GET.should.equal "foo" => "bar", "quux" => "bla"
133
- req.POST.should.be.empty
134
- req.params.should.equal "foo" => "bar", "quux" => "bla"
135
- end
136
-
137
- should "not truncate query strings containing semi-colons #543 only in POST" do
138
- mr = Rack::MockRequest.env_for("/",
139
- "REQUEST_METHOD" => 'POST',
140
- :input => "foo=bar&quux=b;la")
141
- req = Rack::Request.new mr
142
- req.query_string.should.equal ""
143
- req.GET.should.be.empty
144
- req.POST.should.equal "foo" => "bar", "quux" => "b;la"
145
- req.params.should.equal req.GET.merge(req.POST)
146
- end
147
-
148
- should "use semi-colons as separators for query strings in GET" do
149
- req = Rack::Request.new(Rack::MockRequest.env_for("/?foo=bar&quux=b;la;wun=duh"))
150
- req.query_string.should.equal "foo=bar&quux=b;la;wun=duh"
151
- req.GET.should.equal "foo" => "bar", "quux" => "b", "la" => nil, "wun" => "duh"
152
- req.POST.should.be.empty
153
- req.params.should.equal "foo" => "bar", "quux" => "b", "la" => nil, "wun" => "duh"
154
- end
155
-
156
- should "limit the keys from the GET query string" do
157
- env = Rack::MockRequest.env_for("/?foo=bar")
158
-
159
- old, Rack::Utils.key_space_limit = Rack::Utils.key_space_limit, 1
160
- begin
161
- req = Rack::Request.new(env)
162
- lambda { req.GET }.should.raise(RangeError)
163
- ensure
164
- Rack::Utils.key_space_limit = old
165
- end
166
- end
167
-
168
- should "limit the key size per nested params hash" do
169
- nested_query = Rack::MockRequest.env_for("/?foo%5Bbar%5D%5Bbaz%5D%5Bqux%5D=1")
170
- plain_query = Rack::MockRequest.env_for("/?foo_bar__baz__qux_=1")
171
-
172
- old, Rack::Utils.key_space_limit = Rack::Utils.key_space_limit, 3
173
- begin
174
- lambda { Rack::Request.new(nested_query).GET }.should.not.raise(RangeError)
175
- lambda { Rack::Request.new(plain_query).GET }.should.raise(RangeError)
176
- ensure
177
- Rack::Utils.key_space_limit = old
178
- end
179
- end
180
-
181
- should "not unify GET and POST when calling params" do
182
- mr = Rack::MockRequest.env_for("/?foo=quux",
183
- "REQUEST_METHOD" => 'POST',
184
- :input => "foo=bar&quux=bla"
185
- )
186
- req = Rack::Request.new mr
187
-
188
- req.params
189
-
190
- req.GET.should.equal "foo" => "quux"
191
- req.POST.should.equal "foo" => "bar", "quux" => "bla"
192
- req.params.should.equal req.GET.merge(req.POST)
193
- end
194
-
195
- should "raise if input params has invalid %-encoding" do
196
- mr = Rack::MockRequest.env_for("/?foo=quux",
197
- "REQUEST_METHOD" => 'POST',
198
- :input => "a%=1"
199
- )
200
- req = Rack::Request.new mr
201
-
202
- lambda { req.POST }.
203
- should.raise(Rack::Utils::InvalidParameterError).
204
- message.should.equal "invalid %-encoding (a%)"
205
- end
206
-
207
- should "raise if rack.input is missing" do
208
- req = Rack::Request.new({})
209
- lambda { req.POST }.should.raise(RuntimeError)
210
- end
211
-
212
- should "parse POST data when method is POST and no Content-Type given" do
213
- req = Rack::Request.new \
214
- Rack::MockRequest.env_for("/?foo=quux",
215
- "REQUEST_METHOD" => 'POST',
216
- :input => "foo=bar&quux=bla")
217
- req.content_type.should.be.nil
218
- req.media_type.should.be.nil
219
- req.query_string.should.equal "foo=quux"
220
- req.GET.should.equal "foo" => "quux"
221
- req.POST.should.equal "foo" => "bar", "quux" => "bla"
222
- req.params.should.equal "foo" => "bar", "quux" => "bla"
223
- end
224
-
225
- should "limit the keys from the POST form data" do
226
- env = Rack::MockRequest.env_for("",
227
- "REQUEST_METHOD" => 'POST',
228
- :input => "foo=bar&quux=bla")
229
-
230
- old, Rack::Utils.key_space_limit = Rack::Utils.key_space_limit, 1
231
- begin
232
- req = Rack::Request.new(env)
233
- lambda { req.POST }.should.raise(RangeError)
234
- ensure
235
- Rack::Utils.key_space_limit = old
236
- end
237
- end
238
-
239
- should "parse POST data with explicit content type regardless of method" do
240
- req = Rack::Request.new \
241
- Rack::MockRequest.env_for("/",
242
- "CONTENT_TYPE" => 'application/x-www-form-urlencoded;foo=bar',
243
- :input => "foo=bar&quux=bla")
244
- req.content_type.should.equal 'application/x-www-form-urlencoded;foo=bar'
245
- req.media_type.should.equal 'application/x-www-form-urlencoded'
246
- req.media_type_params['foo'].should.equal 'bar'
247
- req.POST.should.equal "foo" => "bar", "quux" => "bla"
248
- req.params.should.equal "foo" => "bar", "quux" => "bla"
249
- end
250
-
251
- should "not parse POST data when media type is not form-data" do
252
- req = Rack::Request.new \
253
- Rack::MockRequest.env_for("/?foo=quux",
254
- "REQUEST_METHOD" => 'POST',
255
- "CONTENT_TYPE" => 'text/plain;charset=utf-8',
256
- :input => "foo=bar&quux=bla")
257
- req.content_type.should.equal 'text/plain;charset=utf-8'
258
- req.media_type.should.equal 'text/plain'
259
- req.media_type_params['charset'].should.equal 'utf-8'
260
- req.POST.should.be.empty
261
- req.params.should.equal "foo" => "quux"
262
- req.body.read.should.equal "foo=bar&quux=bla"
263
- end
264
-
265
- should "parse POST data on PUT when media type is form-data" do
266
- req = Rack::Request.new \
267
- Rack::MockRequest.env_for("/?foo=quux",
268
- "REQUEST_METHOD" => 'PUT',
269
- "CONTENT_TYPE" => 'application/x-www-form-urlencoded',
270
- :input => "foo=bar&quux=bla")
271
- req.POST.should.equal "foo" => "bar", "quux" => "bla"
272
- req.body.read.should.equal "foo=bar&quux=bla"
273
- end
274
-
275
- should "rewind input after parsing POST data" do
276
- input = StringIO.new("foo=bar&quux=bla")
277
- req = Rack::Request.new \
278
- Rack::MockRequest.env_for("/",
279
- "CONTENT_TYPE" => 'application/x-www-form-urlencoded;foo=bar',
280
- :input => input)
281
- req.params.should.equal "foo" => "bar", "quux" => "bla"
282
- input.read.should.equal "foo=bar&quux=bla"
283
- end
284
-
285
- should "clean up Safari's ajax POST body" do
286
- req = Rack::Request.new \
287
- Rack::MockRequest.env_for("/",
288
- 'REQUEST_METHOD' => 'POST', :input => "foo=bar&quux=bla\0")
289
- req.POST.should.equal "foo" => "bar", "quux" => "bla"
290
- end
291
-
292
- should "get value by key from params with #[]" do
293
- req = Rack::Request.new \
294
- Rack::MockRequest.env_for("?foo=quux")
295
- req['foo'].should.equal 'quux'
296
- req[:foo].should.equal 'quux'
297
- end
298
-
299
- should "set value to key on params with #[]=" do
300
- req = Rack::Request.new \
301
- Rack::MockRequest.env_for("?foo=duh")
302
- req['foo'].should.equal 'duh'
303
- req[:foo].should.equal 'duh'
304
- req.params.should.equal 'foo' => 'duh'
305
-
306
- req['foo'] = 'bar'
307
- req.params.should.equal 'foo' => 'bar'
308
- req['foo'].should.equal 'bar'
309
- req[:foo].should.equal 'bar'
310
-
311
- req[:foo] = 'jaz'
312
- req.params.should.equal 'foo' => 'jaz'
313
- req['foo'].should.equal 'jaz'
314
- req[:foo].should.equal 'jaz'
315
- end
316
-
317
- should "return values for the keys in the order given from values_at" do
318
- req = Rack::Request.new \
319
- Rack::MockRequest.env_for("?foo=baz&wun=der&bar=ful")
320
- req.values_at('foo').should.equal ['baz']
321
- req.values_at('foo', 'wun').should.equal ['baz', 'der']
322
- req.values_at('bar', 'foo', 'wun').should.equal ['ful', 'baz', 'der']
323
- end
324
-
325
- should "extract referrer correctly" do
326
- req = Rack::Request.new \
327
- Rack::MockRequest.env_for("/", "HTTP_REFERER" => "/some/path")
328
- req.referer.should.equal "/some/path"
329
-
330
- req = Rack::Request.new \
331
- Rack::MockRequest.env_for("/")
332
- req.referer.should.equal nil
333
- end
334
-
335
- should "extract user agent correctly" do
336
- req = Rack::Request.new \
337
- Rack::MockRequest.env_for("/", "HTTP_USER_AGENT" => "Mozilla/4.0 (compatible)")
338
- req.user_agent.should.equal "Mozilla/4.0 (compatible)"
339
-
340
- req = Rack::Request.new \
341
- Rack::MockRequest.env_for("/")
342
- req.user_agent.should.equal nil
343
- end
344
-
345
- should "treat missing content type as nil" do
346
- req = Rack::Request.new \
347
- Rack::MockRequest.env_for("/")
348
- req.content_type.should.equal nil
349
- end
350
-
351
- should "treat empty content type as nil" do
352
- req = Rack::Request.new \
353
- Rack::MockRequest.env_for("/", "CONTENT_TYPE" => "")
354
- req.content_type.should.equal nil
355
- end
356
-
357
- should "return nil media type for empty content type" do
358
- req = Rack::Request.new \
359
- Rack::MockRequest.env_for("/", "CONTENT_TYPE" => "")
360
- req.media_type.should.equal nil
361
- end
362
-
363
- should "cache, but invalidates the cache" do
364
- req = Rack::Request.new \
365
- Rack::MockRequest.env_for("/?foo=quux",
366
- "CONTENT_TYPE" => "application/x-www-form-urlencoded",
367
- :input => "foo=bar&quux=bla")
368
- req.GET.should.equal "foo" => "quux"
369
- req.GET.should.equal "foo" => "quux"
370
- req.env["QUERY_STRING"] = "bla=foo"
371
- req.GET.should.equal "bla" => "foo"
372
- req.GET.should.equal "bla" => "foo"
373
-
374
- req.POST.should.equal "foo" => "bar", "quux" => "bla"
375
- req.POST.should.equal "foo" => "bar", "quux" => "bla"
376
- req.env["rack.input"] = StringIO.new("foo=bla&quux=bar")
377
- req.POST.should.equal "foo" => "bla", "quux" => "bar"
378
- req.POST.should.equal "foo" => "bla", "quux" => "bar"
379
- end
380
-
381
- should "figure out if called via XHR" do
382
- req = Rack::Request.new(Rack::MockRequest.env_for(""))
383
- req.should.not.be.xhr
384
-
385
- req = Rack::Request.new \
386
- Rack::MockRequest.env_for("", "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest")
387
- req.should.be.xhr
388
- end
389
-
390
- should "ssl detection" do
391
- request = Rack::Request.new(Rack::MockRequest.env_for("/"))
392
- request.scheme.should.equal "http"
393
- request.should.not.be.ssl?
394
-
395
- request = Rack::Request.new(Rack::MockRequest.env_for("/", 'HTTPS' => 'on'))
396
- request.scheme.should.equal "https"
397
- request.should.be.ssl?
398
-
399
- request = Rack::Request.new(Rack::MockRequest.env_for("/", 'rack.url_scheme' => 'https'))
400
- request.scheme.should.equal "https"
401
- request.should.be.ssl?
402
-
403
- request = Rack::Request.new(Rack::MockRequest.env_for("/", 'HTTP_HOST' => 'www.example.org:8080'))
404
- request.scheme.should.equal "http"
405
- request.should.not.be.ssl?
406
-
407
- request = Rack::Request.new(Rack::MockRequest.env_for("/", 'HTTP_HOST' => 'www.example.org:8443', 'HTTPS' => 'on'))
408
- request.scheme.should.equal "https"
409
- request.should.be.ssl?
410
-
411
- request = Rack::Request.new(Rack::MockRequest.env_for("/", 'HTTP_HOST' => 'www.example.org:8443', 'HTTP_X_FORWARDED_SSL' => 'on'))
412
- request.scheme.should.equal "https"
413
- request.should.be.ssl?
414
-
415
- request = Rack::Request.new(Rack::MockRequest.env_for("/", 'HTTP_X_FORWARDED_SCHEME' => 'https'))
416
- request.scheme.should.equal "https"
417
- request.should.be.ssl?
418
-
419
- request = Rack::Request.new(Rack::MockRequest.env_for("/", 'HTTP_X_FORWARDED_PROTO' => 'https'))
420
- request.scheme.should.equal "https"
421
- request.should.be.ssl?
422
-
423
- request = Rack::Request.new(Rack::MockRequest.env_for("/", 'HTTP_X_FORWARDED_PROTO' => 'https, http, http'))
424
- request.scheme.should.equal "https"
425
- request.should.be.ssl?
426
- end
427
-
428
- should "prevent scheme abuse" do
429
- request = Rack::Request.new(Rack::MockRequest.env_for("/", 'HTTP_X_FORWARDED_SCHEME' => 'a."><script>alert(1)</script>'))
430
- request.scheme.should.not.equal 'a."><script>alert(1)</script>'
431
- end
432
-
433
- should "parse cookies" do
434
- req = Rack::Request.new \
435
- Rack::MockRequest.env_for("", "HTTP_COOKIE" => "foo=bar;quux=h&m")
436
- req.cookies.should.equal "foo" => "bar", "quux" => "h&m"
437
- req.cookies.should.equal "foo" => "bar", "quux" => "h&m"
438
- req.env.delete("HTTP_COOKIE")
439
- req.cookies.should.equal({})
440
- end
441
-
442
- should "always return the same hash object" do
443
- req = Rack::Request.new \
444
- Rack::MockRequest.env_for("", "HTTP_COOKIE" => "foo=bar;quux=h&m")
445
- hash = req.cookies
446
- req.env.delete("HTTP_COOKIE")
447
- req.cookies.should.equal(hash)
448
- req.env["HTTP_COOKIE"] = "zoo=m"
449
- req.cookies.should.equal(hash)
450
- end
451
-
452
- should "modify the cookies hash in place" do
453
- req = Rack::Request.new(Rack::MockRequest.env_for(""))
454
- req.cookies.should.equal({})
455
- req.cookies['foo'] = 'bar'
456
- req.cookies.should.equal 'foo' => 'bar'
457
- end
458
-
459
- should "not modify the params hash in place" do
460
- e = Rack::MockRequest.env_for("")
461
- req1 = Rack::Request.new(e)
462
- req1.params.should.equal({})
463
- req1.params['foo'] = 'bar'
464
- req1.params.should.equal 'foo' => 'bar'
465
- req2 = Rack::Request.new(e)
466
- req2.params.should.equal({})
467
- end
468
-
469
- should "modify params hash if param is in GET" do
470
- e = Rack::MockRequest.env_for("?foo=duh")
471
- req1 = Rack::Request.new(e)
472
- req1.params.should.equal 'foo' => 'duh'
473
- req1.update_param 'foo', 'bar'
474
- req1.params.should.equal 'foo' => 'bar'
475
- req2 = Rack::Request.new(e)
476
- req2.params.should.equal 'foo' => 'bar'
477
- end
478
-
479
- should "modify params hash if param is in POST" do
480
- e = Rack::MockRequest.env_for("", "REQUEST_METHOD" => 'POST', :input => 'foo=duh')
481
- req1 = Rack::Request.new(e)
482
- req1.params.should.equal 'foo' => 'duh'
483
- req1.update_param 'foo', 'bar'
484
- req1.params.should.equal 'foo' => 'bar'
485
- req2 = Rack::Request.new(e)
486
- req2.params.should.equal 'foo' => 'bar'
487
- end
488
-
489
- should "modify params hash, even if param didn't exist before" do
490
- e = Rack::MockRequest.env_for("")
491
- req1 = Rack::Request.new(e)
492
- req1.params.should.equal({})
493
- req1.update_param 'foo', 'bar'
494
- req1.params.should.equal 'foo' => 'bar'
495
- req2 = Rack::Request.new(e)
496
- req2.params.should.equal 'foo' => 'bar'
497
- end
498
-
499
- should "modify params hash by changing only GET" do
500
- e = Rack::MockRequest.env_for("?foo=duhget")
501
- req = Rack::Request.new(e)
502
- req.GET.should.equal 'foo' => 'duhget'
503
- req.POST.should.equal({})
504
- req.update_param 'foo', 'bar'
505
- req.GET.should.equal 'foo' => 'bar'
506
- req.POST.should.equal({})
507
- end
508
-
509
- should "modify params hash by changing only POST" do
510
- e = Rack::MockRequest.env_for("", "REQUEST_METHOD" => 'POST', :input => "foo=duhpost")
511
- req = Rack::Request.new(e)
512
- req.GET.should.equal({})
513
- req.POST.should.equal 'foo' => 'duhpost'
514
- req.update_param 'foo', 'bar'
515
- req.GET.should.equal({})
516
- req.POST.should.equal 'foo' => 'bar'
517
- end
518
-
519
- should "modify params hash, even if param is defined in both POST and GET" do
520
- e = Rack::MockRequest.env_for("?foo=duhget", "REQUEST_METHOD" => 'POST', :input => "foo=duhpost")
521
- req1 = Rack::Request.new(e)
522
- req1.GET.should.equal 'foo' => 'duhget'
523
- req1.POST.should.equal 'foo' => 'duhpost'
524
- req1.params.should.equal 'foo' => 'duhpost'
525
- req1.update_param 'foo', 'bar'
526
- req1.GET.should.equal 'foo' => 'bar'
527
- req1.POST.should.equal 'foo' => 'bar'
528
- req1.params.should.equal 'foo' => 'bar'
529
- req2 = Rack::Request.new(e)
530
- req2.GET.should.equal 'foo' => 'bar'
531
- req2.POST.should.equal 'foo' => 'bar'
532
- req2.params.should.equal 'foo' => 'bar'
533
- req2.params.should.equal 'foo' => 'bar'
534
- end
535
-
536
- should "allow deleting from params hash if param is in GET" do
537
- e = Rack::MockRequest.env_for("?foo=bar")
538
- req1 = Rack::Request.new(e)
539
- req1.params.should.equal 'foo' => 'bar'
540
- req1.delete_param('foo').should.equal 'bar'
541
- req1.params.should.equal({})
542
- req2 = Rack::Request.new(e)
543
- req2.params.should.equal({})
544
- end
545
-
546
- should "allow deleting from params hash if param is in POST" do
547
- e = Rack::MockRequest.env_for("", "REQUEST_METHOD" => 'POST', :input => 'foo=bar')
548
- req1 = Rack::Request.new(e)
549
- req1.params.should.equal 'foo' => 'bar'
550
- req1.delete_param('foo').should.equal 'bar'
551
- req1.params.should.equal({})
552
- req2 = Rack::Request.new(e)
553
- req2.params.should.equal({})
554
- end
555
-
556
- should "pass through non-uri escaped cookies as-is" do
557
- req = Rack::Request.new Rack::MockRequest.env_for("", "HTTP_COOKIE" => "foo=%")
558
- req.cookies["foo"].should == "%"
559
- end
560
-
561
- should "parse cookies according to RFC 2109" do
562
- req = Rack::Request.new \
563
- Rack::MockRequest.env_for('', 'HTTP_COOKIE' => 'foo=bar;foo=car')
564
- req.cookies.should.equal 'foo' => 'bar'
565
- end
566
-
567
- should 'parse cookies with quotes' do
568
- req = Rack::Request.new Rack::MockRequest.env_for('', {
569
- 'HTTP_COOKIE' => '$Version="1"; Customer="WILE_E_COYOTE"; $Path="/acme"; Part_Number="Rocket_Launcher_0001"; $Path="/acme"'
570
- })
571
- req.cookies.should.equal({
572
- '$Version' => '"1"',
573
- 'Customer' => '"WILE_E_COYOTE"',
574
- '$Path' => '"/acme"',
575
- 'Part_Number' => '"Rocket_Launcher_0001"',
576
- })
577
- end
578
-
579
- should "provide setters" do
580
- req = Rack::Request.new(e=Rack::MockRequest.env_for(""))
581
- req.script_name.should.equal ""
582
- req.script_name = "/foo"
583
- req.script_name.should.equal "/foo"
584
- e["SCRIPT_NAME"].should.equal "/foo"
585
-
586
- req.path_info.should.equal "/"
587
- req.path_info = "/foo"
588
- req.path_info.should.equal "/foo"
589
- e["PATH_INFO"].should.equal "/foo"
590
- end
591
-
592
- should "provide the original env" do
593
- req = Rack::Request.new(e = Rack::MockRequest.env_for(""))
594
- req.env.should == e
595
- end
596
-
597
- should "restore the base URL" do
598
- Rack::Request.new(Rack::MockRequest.env_for("")).base_url.
599
- should.equal "http://example.org"
600
- Rack::Request.new(Rack::MockRequest.env_for("", "SCRIPT_NAME" => "/foo")).base_url.
601
- should.equal "http://example.org"
602
- end
603
-
604
- should "restore the URL" do
605
- Rack::Request.new(Rack::MockRequest.env_for("")).url.
606
- should.equal "http://example.org/"
607
- Rack::Request.new(Rack::MockRequest.env_for("", "SCRIPT_NAME" => "/foo")).url.
608
- should.equal "http://example.org/foo/"
609
- Rack::Request.new(Rack::MockRequest.env_for("/foo")).url.
610
- should.equal "http://example.org/foo"
611
- Rack::Request.new(Rack::MockRequest.env_for("?foo")).url.
612
- should.equal "http://example.org/?foo"
613
- Rack::Request.new(Rack::MockRequest.env_for("http://example.org:8080/")).url.
614
- should.equal "http://example.org:8080/"
615
- Rack::Request.new(Rack::MockRequest.env_for("https://example.org/")).url.
616
- should.equal "https://example.org/"
617
- Rack::Request.new(Rack::MockRequest.env_for("coffee://example.org/")).url.
618
- should.equal "coffee://example.org/"
619
- Rack::Request.new(Rack::MockRequest.env_for("coffee://example.org:443/")).url.
620
- should.equal "coffee://example.org:443/"
621
- Rack::Request.new(Rack::MockRequest.env_for("https://example.com:8080/foo?foo")).url.
622
- should.equal "https://example.com:8080/foo?foo"
623
- end
624
-
625
- should "restore the full path" do
626
- Rack::Request.new(Rack::MockRequest.env_for("")).fullpath.
627
- should.equal "/"
628
- Rack::Request.new(Rack::MockRequest.env_for("", "SCRIPT_NAME" => "/foo")).fullpath.
629
- should.equal "/foo/"
630
- Rack::Request.new(Rack::MockRequest.env_for("/foo")).fullpath.
631
- should.equal "/foo"
632
- Rack::Request.new(Rack::MockRequest.env_for("?foo")).fullpath.
633
- should.equal "/?foo"
634
- Rack::Request.new(Rack::MockRequest.env_for("http://example.org:8080/")).fullpath.
635
- should.equal "/"
636
- Rack::Request.new(Rack::MockRequest.env_for("https://example.org/")).fullpath.
637
- should.equal "/"
638
-
639
- Rack::Request.new(Rack::MockRequest.env_for("https://example.com:8080/foo?foo")).fullpath.
640
- should.equal "/foo?foo"
641
- end
642
-
643
- should "handle multiple media type parameters" do
644
- req = Rack::Request.new \
645
- Rack::MockRequest.env_for("/",
646
- "CONTENT_TYPE" => 'text/plain; foo=BAR,baz=bizzle dizzle;BLING=bam;blong="boo";zump="zoo\"o";weird=lol"')
647
- req.should.not.be.form_data
648
- req.media_type_params.should.include 'foo'
649
- req.media_type_params['foo'].should.equal 'BAR'
650
- req.media_type_params.should.include 'baz'
651
- req.media_type_params['baz'].should.equal 'bizzle dizzle'
652
- req.media_type_params.should.not.include 'BLING'
653
- req.media_type_params.should.include 'bling'
654
- req.media_type_params['bling'].should.equal 'bam'
655
- req.media_type_params['blong'].should.equal 'boo'
656
- req.media_type_params['zump'].should.equal 'zoo\"o'
657
- req.media_type_params['weird'].should.equal 'lol"'
658
- end
659
-
660
- should "parse with junk before boundry" do
661
- # Adapted from RFC 1867.
662
- input = <<EOF
663
- blah blah\r
664
- \r
665
- --AaB03x\r
666
- content-disposition: form-data; name="reply"\r
667
- \r
668
- yes\r
669
- --AaB03x\r
670
- content-disposition: form-data; name="fileupload"; filename="dj.jpg"\r
671
- Content-Type: image/jpeg\r
672
- Content-Transfer-Encoding: base64\r
673
- \r
674
- /9j/4AAQSkZJRgABAQAAAQABAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcg\r
675
- --AaB03x--\r
676
- EOF
677
- req = Rack::Request.new Rack::MockRequest.env_for("/",
678
- "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
679
- "CONTENT_LENGTH" => input.size,
680
- :input => input)
681
-
682
- req.POST.should.include "fileupload"
683
- req.POST.should.include "reply"
684
-
685
- req.should.be.form_data
686
- req.content_length.should.equal input.size
687
- req.media_type.should.equal 'multipart/form-data'
688
- req.media_type_params.should.include 'boundary'
689
- req.media_type_params['boundary'].should.equal 'AaB03x'
690
-
691
- req.POST["reply"].should.equal "yes"
692
-
693
- f = req.POST["fileupload"]
694
- f.should.be.kind_of Hash
695
- f[:type].should.equal "image/jpeg"
696
- f[:filename].should.equal "dj.jpg"
697
- f.should.include :tempfile
698
- f[:tempfile].size.should.equal 76
699
- end
700
-
701
- should "not infinite loop with a malformed HTTP request" do
702
- # Adapted from RFC 1867.
703
- input = <<EOF
704
- --AaB03x
705
- content-disposition: form-data; name="reply"
706
-
707
- yes
708
- --AaB03x
709
- content-disposition: form-data; name="fileupload"; filename="dj.jpg"
710
- Content-Type: image/jpeg
711
- Content-Transfer-Encoding: base64
712
-
713
- /9j/4AAQSkZJRgABAQAAAQABAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcg
714
- --AaB03x--
715
- EOF
716
- req = Rack::Request.new Rack::MockRequest.env_for("/",
717
- "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
718
- "CONTENT_LENGTH" => input.size,
719
- :input => input)
720
-
721
- lambda{req.POST}.should.raise(EOFError)
722
- end
723
-
724
-
725
- should "parse multipart form data" do
726
- # Adapted from RFC 1867.
727
- input = <<EOF
728
- --AaB03x\r
729
- content-disposition: form-data; name="reply"\r
730
- \r
731
- yes\r
732
- --AaB03x\r
733
- content-disposition: form-data; name="fileupload"; filename="dj.jpg"\r
734
- Content-Type: image/jpeg\r
735
- Content-Transfer-Encoding: base64\r
736
- \r
737
- /9j/4AAQSkZJRgABAQAAAQABAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcg\r
738
- --AaB03x--\r
739
- EOF
740
- req = Rack::Request.new Rack::MockRequest.env_for("/",
741
- "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
742
- "CONTENT_LENGTH" => input.size,
743
- :input => input)
744
-
745
- req.POST.should.include "fileupload"
746
- req.POST.should.include "reply"
747
-
748
- req.should.be.form_data
749
- req.content_length.should.equal input.size
750
- req.media_type.should.equal 'multipart/form-data'
751
- req.media_type_params.should.include 'boundary'
752
- req.media_type_params['boundary'].should.equal 'AaB03x'
753
-
754
- req.POST["reply"].should.equal "yes"
755
-
756
- f = req.POST["fileupload"]
757
- f.should.be.kind_of Hash
758
- f[:type].should.equal "image/jpeg"
759
- f[:filename].should.equal "dj.jpg"
760
- f.should.include :tempfile
761
- f[:tempfile].size.should.equal 76
762
- end
763
-
764
- should "MultipartPartLimitError when request has too many multipart parts if limit set" do
765
- begin
766
- 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
- data += "--AaB03x--\r"
768
-
769
- options = {
770
- "CONTENT_TYPE" => "multipart/form-data; boundary=AaB03x",
771
- "CONTENT_LENGTH" => data.length.to_s,
772
- :input => StringIO.new(data)
773
- }
774
-
775
- request = Rack::Request.new Rack::MockRequest.env_for("/", options)
776
- lambda { request.POST }.should.raise(Rack::Multipart::MultipartPartLimitError)
777
- end
778
- end
779
-
780
- should "parse big multipart form data" do
781
- input = <<EOF
782
- --AaB03x\r
783
- content-disposition: form-data; name="huge"; filename="huge"\r
784
- \r
785
- #{"x"*32768}\r
786
- --AaB03x\r
787
- content-disposition: form-data; name="mean"; filename="mean"\r
788
- \r
789
- --AaB03xha\r
790
- --AaB03x--\r
791
- EOF
792
- req = Rack::Request.new Rack::MockRequest.env_for("/",
793
- "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
794
- "CONTENT_LENGTH" => input.size,
795
- :input => input)
796
-
797
- req.POST["huge"][:tempfile].size.should.equal 32768
798
- req.POST["mean"][:tempfile].size.should.equal 10
799
- req.POST["mean"][:tempfile].read.should.equal "--AaB03xha"
800
- end
801
-
802
- should "record tempfiles from multipart form data in env[rack.tempfiles]" do
803
- input = <<EOF
804
- --AaB03x\r
805
- content-disposition: form-data; name="fileupload"; filename="foo.jpg"\r
806
- Content-Type: image/jpeg\r
807
- Content-Transfer-Encoding: base64\r
808
- \r
809
- /9j/4AAQSkZJRgABAQAAAQABAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcg\r
810
- --AaB03x\r
811
- content-disposition: form-data; name="fileupload"; filename="bar.jpg"\r
812
- Content-Type: image/jpeg\r
813
- Content-Transfer-Encoding: base64\r
814
- \r
815
- /9j/4AAQSkZJRgABAQAAAQABAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcg\r
816
- --AaB03x--\r
817
- EOF
818
- env = Rack::MockRequest.env_for("/",
819
- "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
820
- "CONTENT_LENGTH" => input.size,
821
- :input => input)
822
- req = Rack::Request.new(env)
823
- req.params
824
- env['rack.tempfiles'].size.should.equal(2)
825
- end
826
-
827
- should "detect invalid multipart form data" do
828
- input = <<EOF
829
- --AaB03x\r
830
- content-disposition: form-data; name="huge"; filename="huge"\r
831
- EOF
832
- req = Rack::Request.new Rack::MockRequest.env_for("/",
833
- "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
834
- "CONTENT_LENGTH" => input.size,
835
- :input => input)
836
-
837
- lambda { req.POST }.should.raise(EOFError)
838
-
839
- input = <<EOF
840
- --AaB03x\r
841
- content-disposition: form-data; name="huge"; filename="huge"\r
842
- \r
843
- foo\r
844
- EOF
845
- req = Rack::Request.new Rack::MockRequest.env_for("/",
846
- "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
847
- "CONTENT_LENGTH" => input.size,
848
- :input => input)
849
-
850
- lambda { req.POST }.should.raise(EOFError)
851
-
852
- input = <<EOF
853
- --AaB03x\r
854
- content-disposition: form-data; name="huge"; filename="huge"\r
855
- \r
856
- foo\r
857
- EOF
858
- req = Rack::Request.new Rack::MockRequest.env_for("/",
859
- "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
860
- "CONTENT_LENGTH" => input.size,
861
- :input => input)
862
-
863
- lambda { req.POST }.should.raise(EOFError)
864
- end
865
-
866
- should "consistently raise EOFError on bad multipart form data" do
867
- input = <<EOF
868
- --AaB03x\r
869
- content-disposition: form-data; name="huge"; filename="huge"\r
870
- EOF
871
- req = Rack::Request.new Rack::MockRequest.env_for("/",
872
- "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
873
- "CONTENT_LENGTH" => input.size,
874
- :input => input)
875
-
876
- lambda { req.POST }.should.raise(EOFError)
877
- lambda { req.POST }.should.raise(EOFError)
878
- end
879
-
880
- should "correctly parse the part name from Content-Id header" do
881
- input = <<EOF
882
- --AaB03x\r
883
- Content-Type: text/xml; charset=utf-8\r
884
- Content-Id: <soap-start>\r
885
- Content-Transfer-Encoding: 7bit\r
886
- \r
887
- foo\r
888
- --AaB03x--\r
889
- EOF
890
- req = Rack::Request.new Rack::MockRequest.env_for("/",
891
- "CONTENT_TYPE" => "multipart/related, boundary=AaB03x",
892
- "CONTENT_LENGTH" => input.size,
893
- :input => input)
894
-
895
- req.params.keys.should.equal ["<soap-start>"]
896
- end
897
-
898
- should "not try to interpret binary as utf8" do
899
- if /regexp/.respond_to?(:kcode) # < 1.9
900
- begin
901
- original_kcode = $KCODE
902
- $KCODE='UTF8'
903
-
904
- input = <<EOF
905
- --AaB03x\r
906
- content-disposition: form-data; name="fileupload"; filename="junk.a"\r
907
- content-type: application/octet-stream\r
908
- \r
909
- #{[0x36,0xCF,0x0A,0xF8].pack('c*')}\r
910
- --AaB03x--\r
911
- EOF
912
-
913
- req = Rack::Request.new Rack::MockRequest.env_for("/",
914
- "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
915
- "CONTENT_LENGTH" => input.size,
916
- :input => input)
917
-
918
- lambda{req.POST}.should.not.raise(EOFError)
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
941
- end
942
-
943
- should "work around buggy 1.8.* Tempfile equality" do
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
966
- input = "{foo: 'bar'}"
967
-
968
- rack_input = Tempfile.new("rackspec")
969
- rack_input.write(input)
970
- rack_input.rewind
971
-
972
- req = Rack::Request.new Rack::MockRequest.env_for("/",
973
- "rack.request.form_hash" => {'foo' => 'bar'},
974
- "rack.request.form_input" => rack_input,
975
- :input => rack_input)
976
-
977
- req.POST.should.equal(req.env['rack.request.form_hash'])
978
- end
979
-
980
- should "conform to the Rack spec" do
981
- app = lambda { |env|
982
- content = Rack::Request.new(env).POST["file"].inspect
983
- size = content.respond_to?(:bytesize) ? content.bytesize : content.size
984
- [200, {"Content-Type" => "text/html", "Content-Length" => size.to_s}, [content]]
985
- }
986
-
987
- input = <<EOF
988
- --AaB03x\r
989
- content-disposition: form-data; name="reply"\r
990
- \r
991
- yes\r
992
- --AaB03x\r
993
- content-disposition: form-data; name="fileupload"; filename="dj.jpg"\r
994
- Content-Type: image/jpeg\r
995
- Content-Transfer-Encoding: base64\r
996
- \r
997
- /9j/4AAQSkZJRgABAQAAAQABAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcg\r
998
- --AaB03x--\r
999
- EOF
1000
- input.force_encoding("ASCII-8BIT") if input.respond_to? :force_encoding
1001
- res = Rack::MockRequest.new(Rack::Lint.new(app)).get "/",
1002
- "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
1003
- "CONTENT_LENGTH" => input.size.to_s, "rack.input" => StringIO.new(input)
1004
-
1005
- res.should.be.ok
1006
- end
1007
-
1008
- should "parse Accept-Encoding correctly" do
1009
- parser = lambda do |x|
1010
- Rack::Request.new(Rack::MockRequest.env_for("", "HTTP_ACCEPT_ENCODING" => x)).accept_encoding
1011
- end
1012
-
1013
- parser.call(nil).should.equal([])
1014
-
1015
- parser.call("compress, gzip").should.equal([["compress", 1.0], ["gzip", 1.0]])
1016
- parser.call("").should.equal([])
1017
- parser.call("*").should.equal([["*", 1.0]])
1018
- parser.call("compress;q=0.5, gzip;q=1.0").should.equal([["compress", 0.5], ["gzip", 1.0]])
1019
- parser.call("gzip;q=1.0, identity; q=0.5, *;q=0").should.equal([["gzip", 1.0], ["identity", 0.5], ["*", 0] ])
1020
-
1021
- parser.call("gzip ; q=0.9").should.equal([["gzip", 0.9]])
1022
- parser.call("gzip ; deflate").should.equal([["gzip", 1.0]])
1023
- end
1024
-
1025
- should "parse Accept-Language correctly" do
1026
- parser = lambda do |x|
1027
- Rack::Request.new(Rack::MockRequest.env_for("", "HTTP_ACCEPT_LANGUAGE" => x)).accept_language
1028
- end
1029
-
1030
- parser.call(nil).should.equal([])
1031
-
1032
- parser.call("fr, en").should.equal([["fr", 1.0], ["en", 1.0]])
1033
- parser.call("").should.equal([])
1034
- parser.call("*").should.equal([["*", 1.0]])
1035
- parser.call("fr;q=0.5, en;q=1.0").should.equal([["fr", 0.5], ["en", 1.0]])
1036
- parser.call("fr;q=1.0, en; q=0.5, *;q=0").should.equal([["fr", 1.0], ["en", 0.5], ["*", 0] ])
1037
-
1038
- parser.call("fr ; q=0.9").should.equal([["fr", 0.9]])
1039
- parser.call("fr").should.equal([["fr", 1.0]])
1040
- end
1041
-
1042
- ip_app = lambda { |env|
1043
- request = Rack::Request.new(env)
1044
- response = Rack::Response.new
1045
- response.write request.ip
1046
- response.finish
1047
- }
1048
-
1049
- should 'provide ip information' do
1050
- mock = Rack::MockRequest.new(Rack::Lint.new(ip_app))
1051
-
1052
- res = mock.get '/', 'REMOTE_ADDR' => '1.2.3.4'
1053
- res.body.should.equal '1.2.3.4'
1054
-
1055
- res = mock.get '/', 'REMOTE_ADDR' => 'fe80::202:b3ff:fe1e:8329'
1056
- res.body.should.equal 'fe80::202:b3ff:fe1e:8329'
1057
-
1058
- res = mock.get '/', 'REMOTE_ADDR' => '1.2.3.4,3.4.5.6'
1059
- res.body.should.equal '1.2.3.4'
1060
- end
1061
-
1062
- should 'deals with proxies' do
1063
- mock = Rack::MockRequest.new(Rack::Lint.new(ip_app))
1064
-
1065
- res = mock.get '/',
1066
- 'REMOTE_ADDR' => '1.2.3.4',
1067
- 'HTTP_X_FORWARDED_FOR' => '3.4.5.6'
1068
- res.body.should.equal '1.2.3.4'
1069
-
1070
- res = mock.get '/',
1071
- 'REMOTE_ADDR' => '1.2.3.4',
1072
- 'HTTP_X_FORWARDED_FOR' => 'unknown'
1073
- res.body.should.equal '1.2.3.4'
1074
-
1075
- res = mock.get '/',
1076
- 'REMOTE_ADDR' => '127.0.0.1',
1077
- 'HTTP_X_FORWARDED_FOR' => '3.4.5.6'
1078
- res.body.should.equal '3.4.5.6'
1079
-
1080
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => 'unknown,3.4.5.6'
1081
- res.body.should.equal '3.4.5.6'
1082
-
1083
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '192.168.0.1,3.4.5.6'
1084
- res.body.should.equal '3.4.5.6'
1085
-
1086
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '10.0.0.1,3.4.5.6'
1087
- res.body.should.equal '3.4.5.6'
1088
-
1089
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '10.0.0.1, 10.0.0.1, 3.4.5.6'
1090
- res.body.should.equal '3.4.5.6'
1091
-
1092
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '127.0.0.1, 3.4.5.6'
1093
- res.body.should.equal '3.4.5.6'
1094
-
1095
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => 'unknown,192.168.0.1'
1096
- res.body.should.equal 'unknown'
1097
-
1098
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => 'other,unknown,192.168.0.1'
1099
- res.body.should.equal 'unknown'
1100
-
1101
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => 'unknown,localhost,192.168.0.1'
1102
- res.body.should.equal 'unknown'
1103
-
1104
- 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.should.equal '3.4.5.6'
1106
-
1107
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '::1,2620:0:1c00:0:812c:9583:754b:ca11'
1108
- res.body.should.equal '2620:0:1c00:0:812c:9583:754b:ca11'
1109
-
1110
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '2620:0:1c00:0:812c:9583:754b:ca11,::1'
1111
- res.body.should.equal '2620:0:1c00:0:812c:9583:754b:ca11'
1112
-
1113
- 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.should.equal '2620:0:1c00:0:812c:9583:754b:ca11'
1115
-
1116
- 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.should.equal '2620:0:1c00:0:812c:9583:754b:ca11'
1118
-
1119
- res = mock.get '/',
1120
- 'HTTP_X_FORWARDED_FOR' => '1.1.1.1, 127.0.0.1',
1121
- 'HTTP_CLIENT_IP' => '1.1.1.1'
1122
- res.body.should.equal '1.1.1.1'
1123
-
1124
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '8.8.8.8, 9.9.9.9'
1125
- res.body.should.equal '9.9.9.9'
1126
-
1127
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '8.8.8.8, fe80::202:b3ff:fe1e:8329'
1128
- res.body.should.equal 'fe80::202:b3ff:fe1e:8329'
1129
-
1130
- # Unix Sockets
1131
- res = mock.get '/',
1132
- 'REMOTE_ADDR' => 'unix',
1133
- 'HTTP_X_FORWARDED_FOR' => '3.4.5.6'
1134
- res.body.should.equal '3.4.5.6'
1135
-
1136
- res = mock.get '/',
1137
- 'REMOTE_ADDR' => 'unix:/tmp/foo',
1138
- 'HTTP_X_FORWARDED_FOR' => '3.4.5.6'
1139
- res.body.should.equal '3.4.5.6'
1140
- end
1141
-
1142
- should "not allow IP spoofing via Client-IP and X-Forwarded-For headers" do
1143
- mock = Rack::MockRequest.new(Rack::Lint.new(ip_app))
1144
-
1145
- # IP Spoofing attempt:
1146
- # Client sends X-Forwarded-For: 6.6.6.6
1147
- # Client-IP: 6.6.6.6
1148
- # Load balancer adds X-Forwarded-For: 2.2.2.3, 192.168.0.7
1149
- # App receives: X-Forwarded-For: 6.6.6.6
1150
- # X-Forwarded-For: 2.2.2.3, 192.168.0.7
1151
- # Client-IP: 6.6.6.6
1152
- # Rack env: HTTP_X_FORWARDED_FOR: '6.6.6.6, 2.2.2.3, 192.168.0.7'
1153
- # HTTP_CLIENT_IP: '6.6.6.6'
1154
- res = mock.get '/',
1155
- 'HTTP_X_FORWARDED_FOR' => '6.6.6.6, 2.2.2.3, 192.168.0.7',
1156
- 'HTTP_CLIENT_IP' => '6.6.6.6'
1157
- res.body.should.equal '2.2.2.3'
1158
- end
1159
-
1160
- should "regard local addresses as proxies" do
1161
- req = Rack::Request.new(Rack::MockRequest.env_for("/"))
1162
- req.trusted_proxy?('127.0.0.1').should.equal 0
1163
- req.trusted_proxy?('10.0.0.1').should.equal 0
1164
- req.trusted_proxy?('172.16.0.1').should.equal 0
1165
- req.trusted_proxy?('172.20.0.1').should.equal 0
1166
- req.trusted_proxy?('172.30.0.1').should.equal 0
1167
- req.trusted_proxy?('172.31.0.1').should.equal 0
1168
- req.trusted_proxy?('192.168.0.1').should.equal 0
1169
- req.trusted_proxy?('::1').should.equal 0
1170
- req.trusted_proxy?('fd00::').should.equal 0
1171
- req.trusted_proxy?('localhost').should.equal 0
1172
- req.trusted_proxy?('unix').should.equal 0
1173
- req.trusted_proxy?('unix:/tmp/sock').should.equal 0
1174
-
1175
- req.trusted_proxy?("unix.example.org").should.equal nil
1176
- req.trusted_proxy?("example.org\n127.0.0.1").should.equal nil
1177
- req.trusted_proxy?("127.0.0.1\nexample.org").should.equal nil
1178
- req.trusted_proxy?("11.0.0.1").should.equal nil
1179
- req.trusted_proxy?("172.15.0.1").should.equal nil
1180
- req.trusted_proxy?("172.32.0.1").should.equal nil
1181
- req.trusted_proxy?("2001:470:1f0b:18f8::1").should.equal nil
1182
- end
1183
-
1184
- class MyRequest < Rack::Request
1185
- def params
1186
- {:foo => "bar"}
1187
- end
1188
- end
1189
-
1190
- should "allow subclass request to be instantiated after parent request" do
1191
- env = Rack::MockRequest.env_for("/?foo=bar")
1192
-
1193
- req1 = Rack::Request.new(env)
1194
- req1.GET.should.equal "foo" => "bar"
1195
- req1.params.should.equal "foo" => "bar"
1196
-
1197
- req2 = MyRequest.new(env)
1198
- req2.GET.should.equal "foo" => "bar"
1199
- req2.params.should.equal :foo => "bar"
1200
- end
1201
-
1202
- should "allow parent request to be instantiated after subclass request" do
1203
- env = Rack::MockRequest.env_for("/?foo=bar")
1204
-
1205
- req1 = MyRequest.new(env)
1206
- req1.GET.should.equal "foo" => "bar"
1207
- req1.params.should.equal :foo => "bar"
1208
-
1209
- req2 = Rack::Request.new(env)
1210
- req2.GET.should.equal "foo" => "bar"
1211
- req2.params.should.equal "foo" => "bar"
1212
- end
1213
-
1214
- should "raise TypeError every time if request parameters are broken" do
1215
- broken_query = Rack::MockRequest.env_for("/?foo%5B%5D=0&foo%5Bbar%5D=1")
1216
- req = Rack::Request.new(broken_query)
1217
- lambda{req.GET}.should.raise(TypeError)
1218
- lambda{req.params}.should.raise(TypeError)
1219
- end
1220
-
1221
- (0x20...0x7E).collect { |a|
1222
- b = a.chr
1223
- c = CGI.escape(b)
1224
- should "not strip '#{a}' => '#{c}' => '#{b}' escaped character from parameters when accessed as string" do
1225
- url = "/?foo=#{c}bar#{c}"
1226
- env = Rack::MockRequest.env_for(url)
1227
- req2 = Rack::Request.new(env)
1228
- req2.GET.should.equal "foo" => "#{b}bar#{b}"
1229
- req2.params.should.equal "foo" => "#{b}bar#{b}"
1230
- end
1231
- }
1232
- end