rack 2.0.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 (187) hide show
  1. checksums.yaml +4 -4
  2. data/{HISTORY.md → CHANGELOG.md} +220 -155
  3. data/{COPYING → MIT-LICENSE} +4 -2
  4. data/README.rdoc +77 -119
  5. data/Rakefile +25 -18
  6. data/SPEC +3 -4
  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.rb +63 -60
  12. data/lib/rack/auth/abstract/handler.rb +3 -1
  13. data/lib/rack/auth/abstract/request.rb +2 -0
  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 +4 -2
  18. data/lib/rack/auth/digest/request.rb +2 -0
  19. data/lib/rack/body_proxy.rb +3 -6
  20. data/lib/rack/builder.rb +38 -15
  21. data/lib/rack/cascade.rb +6 -5
  22. data/lib/rack/chunked.rb +29 -6
  23. data/lib/rack/common_logger.rb +9 -8
  24. data/lib/rack/conditional_get.rb +3 -1
  25. data/lib/rack/config.rb +2 -0
  26. data/lib/rack/content_length.rb +3 -1
  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 +28 -17
  30. data/lib/rack/directory.rb +17 -14
  31. data/lib/rack/etag.rb +3 -1
  32. data/lib/rack/events.rb +5 -3
  33. data/lib/rack/file.rb +5 -173
  34. data/lib/rack/files.rb +178 -0
  35. data/lib/rack/handler.rb +7 -2
  36. data/lib/rack/handler/cgi.rb +3 -1
  37. data/lib/rack/handler/fastcgi.rb +4 -2
  38. data/lib/rack/handler/lsws.rb +3 -1
  39. data/lib/rack/handler/scgi.rb +9 -6
  40. data/lib/rack/handler/thin.rb +3 -1
  41. data/lib/rack/handler/webrick.rb +4 -2
  42. data/lib/rack/head.rb +2 -0
  43. data/lib/rack/lint.rb +14 -11
  44. data/lib/rack/lobster.rb +7 -5
  45. data/lib/rack/lock.rb +2 -0
  46. data/lib/rack/logger.rb +2 -0
  47. data/lib/rack/media_type.rb +10 -5
  48. data/lib/rack/method_override.rb +9 -3
  49. data/lib/rack/mime.rb +9 -1
  50. data/lib/rack/mock.rb +74 -15
  51. data/lib/rack/multipart.rb +5 -3
  52. data/lib/rack/multipart/generator.rb +6 -7
  53. data/lib/rack/multipart/parser.rb +54 -51
  54. data/lib/rack/multipart/uploaded_file.rb +2 -0
  55. data/lib/rack/null_logger.rb +2 -0
  56. data/lib/rack/query_parser.rb +51 -25
  57. data/lib/rack/recursive.rb +7 -5
  58. data/lib/rack/reloader.rb +10 -4
  59. data/lib/rack/request.rb +89 -23
  60. data/lib/rack/response.rb +71 -31
  61. data/lib/rack/rewindable_input.rb +4 -2
  62. data/lib/rack/runtime.rb +4 -2
  63. data/lib/rack/sendfile.rb +15 -8
  64. data/lib/rack/server.rb +88 -16
  65. data/lib/rack/session/abstract/id.rb +104 -21
  66. data/lib/rack/session/cookie.rb +21 -11
  67. data/lib/rack/session/memcache.rb +4 -87
  68. data/lib/rack/session/pool.rb +17 -8
  69. data/lib/rack/show_exceptions.rb +16 -10
  70. data/lib/rack/show_status.rb +4 -2
  71. data/lib/rack/static.rb +15 -10
  72. data/lib/rack/tempfile_reaper.rb +2 -0
  73. data/lib/rack/urlmap.rb +11 -2
  74. data/lib/rack/utils.rb +55 -70
  75. data/rack.gemspec +19 -9
  76. metadata +32 -173
  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 -95
  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 -515
  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 -96
  157. data/test/spec_mime.rb +0 -51
  158. data/test/spec_mock.rb +0 -359
  159. data/test/spec_multipart.rb +0 -722
  160. data/test/spec_null_logger.rb +0 -21
  161. data/test/spec_recursive.rb +0 -75
  162. data/test/spec_request.rb +0 -1393
  163. data/test/spec_response.rb +0 -510
  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 -320
  172. data/test/spec_session_pool.rb +0 -210
  173. data/test/spec_show_exceptions.rb +0 -80
  174. data/test/spec_show_status.rb +0 -104
  175. data/test/spec_static.rb +0 -184
  176. data/test/spec_tempfile_reaper.rb +0 -64
  177. data/test/spec_thin.rb +0 -96
  178. data/test/spec_urlmap.rb +0 -237
  179. data/test/spec_utils.rb +0 -742
  180. data/test/spec_version.rb +0 -11
  181. data/test/spec_webrick.rb +0 -206
  182. data/test/static/another/index.html +0 -1
  183. data/test/static/foo.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
@@ -1,21 +0,0 @@
1
- require 'minitest/autorun'
2
- require 'rack/lint'
3
- require 'rack/mock'
4
- require 'rack/null_logger'
5
-
6
- describe Rack::NullLogger do
7
- it "act as a noop logger" do
8
- app = lambda { |env|
9
- env['rack.logger'].warn "b00m"
10
- [200, {'Content-Type' => 'text/plain'}, ["Hello, World!"]]
11
- }
12
-
13
- logger = Rack::Lint.new(Rack::NullLogger.new(app))
14
-
15
- res = logger.call(Rack::MockRequest.env_for)
16
- res[0..1].must_equal [
17
- 200, {'Content-Type' => 'text/plain'}
18
- ]
19
- res[2].to_enum.to_a.must_equal ["Hello, World!"]
20
- end
21
- end
@@ -1,75 +0,0 @@
1
- require 'minitest/autorun'
2
- require 'rack/lint'
3
- require 'rack/recursive'
4
- require 'rack/mock'
5
-
6
- describe Rack::Recursive do
7
- before do
8
- @app1 = lambda { |env|
9
- res = Rack::Response.new
10
- res["X-Path-Info"] = env["PATH_INFO"]
11
- res["X-Query-String"] = env["QUERY_STRING"]
12
- res.finish do |inner_res|
13
- inner_res.write "App1"
14
- end
15
- }
16
-
17
- @app2 = lambda { |env|
18
- Rack::Response.new.finish do |res|
19
- res.write "App2"
20
- _, _, body = env['rack.recursive.include'].call(env, "/app1")
21
- body.each { |b|
22
- res.write b
23
- }
24
- end
25
- }
26
-
27
- @app3 = lambda { |env|
28
- raise Rack::ForwardRequest.new("/app1")
29
- }
30
-
31
- @app4 = lambda { |env|
32
- raise Rack::ForwardRequest.new("http://example.org/app1/quux?meh")
33
- }
34
- end
35
-
36
- def recursive(map)
37
- Rack::Lint.new Rack::Recursive.new(Rack::URLMap.new(map))
38
- end
39
-
40
- it "allow for subrequests" do
41
- res = Rack::MockRequest.new(recursive("/app1" => @app1,
42
- "/app2" => @app2)).
43
- get("/app2")
44
-
45
- res.must_be :ok?
46
- res.body.must_equal "App2App1"
47
- end
48
-
49
- it "raise error on requests not below the app" do
50
- app = Rack::URLMap.new("/app1" => @app1,
51
- "/app" => recursive("/1" => @app1,
52
- "/2" => @app2))
53
-
54
- lambda {
55
- Rack::MockRequest.new(app).get("/app/2")
56
- }.must_raise(ArgumentError).
57
- message.must_match(/can only include below/)
58
- end
59
-
60
- it "support forwarding" do
61
- app = recursive("/app1" => @app1,
62
- "/app3" => @app3,
63
- "/app4" => @app4)
64
-
65
- res = Rack::MockRequest.new(app).get("/app3")
66
- res.must_be :ok?
67
- res.body.must_equal "App1"
68
-
69
- res = Rack::MockRequest.new(app).get("/app4")
70
- res.must_be :ok?
71
- res.body.must_equal "App1"
72
- res["X-Path-Info"].must_equal "/quux"
73
- res["X-Query-String"].must_equal "meh"
74
- end
75
- end
@@ -1,1393 +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 "parse cookies" do
576
- req = make_request \
577
- Rack::MockRequest.env_for("", "HTTP_COOKIE" => "foo=bar;quux=h&m")
578
- req.cookies.must_equal "foo" => "bar", "quux" => "h&m"
579
- req.cookies.must_equal "foo" => "bar", "quux" => "h&m"
580
- req.delete_header("HTTP_COOKIE")
581
- req.cookies.must_equal({})
582
- end
583
-
584
- it "always return the same hash object" do
585
- req = make_request \
586
- Rack::MockRequest.env_for("", "HTTP_COOKIE" => "foo=bar;quux=h&m")
587
- hash = req.cookies
588
- req.env.delete("HTTP_COOKIE")
589
- req.cookies.must_equal hash
590
- req.env["HTTP_COOKIE"] = "zoo=m"
591
- req.cookies.must_equal hash
592
- end
593
-
594
- it "modify the cookies hash in place" do
595
- req = make_request(Rack::MockRequest.env_for(""))
596
- req.cookies.must_equal({})
597
- req.cookies['foo'] = 'bar'
598
- req.cookies.must_equal 'foo' => 'bar'
599
- end
600
-
601
- it "not modify the params hash in place" do
602
- e = Rack::MockRequest.env_for("")
603
- req1 = make_request(e)
604
- if req1.delegate?
605
- skip "delegate requests don't cache params, so mutations have no impact"
606
- end
607
- req1.params.must_equal({})
608
- req1.params['foo'] = 'bar'
609
- req1.params.must_equal 'foo' => 'bar'
610
- req2 = make_request(e)
611
- req2.params.must_equal({})
612
- end
613
-
614
- it "modify params hash if param is in GET" do
615
- e = Rack::MockRequest.env_for("?foo=duh")
616
- req1 = make_request(e)
617
- req1.params.must_equal 'foo' => 'duh'
618
- req1.update_param 'foo', 'bar'
619
- req1.params.must_equal 'foo' => 'bar'
620
- req2 = make_request(e)
621
- req2.params.must_equal 'foo' => 'bar'
622
- end
623
-
624
- it "modify params hash if param is in POST" do
625
- e = Rack::MockRequest.env_for("", "REQUEST_METHOD" => 'POST', :input => 'foo=duh')
626
- req1 = make_request(e)
627
- req1.params.must_equal 'foo' => 'duh'
628
- req1.update_param 'foo', 'bar'
629
- req1.params.must_equal 'foo' => 'bar'
630
- req2 = make_request(e)
631
- req2.params.must_equal 'foo' => 'bar'
632
- end
633
-
634
- it "modify params hash, even if param didn't exist before" do
635
- e = Rack::MockRequest.env_for("")
636
- req1 = make_request(e)
637
- req1.params.must_equal({})
638
- req1.update_param 'foo', 'bar'
639
- req1.params.must_equal 'foo' => 'bar'
640
- req2 = make_request(e)
641
- req2.params.must_equal 'foo' => 'bar'
642
- end
643
-
644
- it "modify params hash by changing only GET" do
645
- e = Rack::MockRequest.env_for("?foo=duhget")
646
- req = make_request(e)
647
- req.GET.must_equal 'foo' => 'duhget'
648
- req.POST.must_equal({})
649
- req.update_param 'foo', 'bar'
650
- req.GET.must_equal 'foo' => 'bar'
651
- req.POST.must_equal({})
652
- end
653
-
654
- it "modify params hash by changing only POST" do
655
- e = Rack::MockRequest.env_for("", "REQUEST_METHOD" => 'POST', :input => "foo=duhpost")
656
- req = make_request(e)
657
- req.GET.must_equal({})
658
- req.POST.must_equal 'foo' => 'duhpost'
659
- req.update_param 'foo', 'bar'
660
- req.GET.must_equal({})
661
- req.POST.must_equal 'foo' => 'bar'
662
- end
663
-
664
- it "modify params hash, even if param is defined in both POST and GET" do
665
- e = Rack::MockRequest.env_for("?foo=duhget", "REQUEST_METHOD" => 'POST', :input => "foo=duhpost")
666
- req1 = make_request(e)
667
- req1.GET.must_equal 'foo' => 'duhget'
668
- req1.POST.must_equal 'foo' => 'duhpost'
669
- req1.params.must_equal 'foo' => 'duhpost'
670
- req1.update_param 'foo', 'bar'
671
- req1.GET.must_equal 'foo' => 'bar'
672
- req1.POST.must_equal 'foo' => 'bar'
673
- req1.params.must_equal 'foo' => 'bar'
674
- req2 = make_request(e)
675
- req2.GET.must_equal 'foo' => 'bar'
676
- req2.POST.must_equal 'foo' => 'bar'
677
- req2.params.must_equal 'foo' => 'bar'
678
- req2.params.must_equal 'foo' => 'bar'
679
- end
680
-
681
- it "allow deleting from params hash if param is in GET" do
682
- e = Rack::MockRequest.env_for("?foo=bar")
683
- req1 = make_request(e)
684
- req1.params.must_equal 'foo' => 'bar'
685
- req1.delete_param('foo').must_equal 'bar'
686
- req1.params.must_equal({})
687
- req2 = make_request(e)
688
- req2.params.must_equal({})
689
- end
690
-
691
- it "allow deleting from params hash if param is in POST" do
692
- e = Rack::MockRequest.env_for("", "REQUEST_METHOD" => 'POST', :input => 'foo=bar')
693
- req1 = make_request(e)
694
- req1.params.must_equal 'foo' => 'bar'
695
- req1.delete_param('foo').must_equal 'bar'
696
- req1.params.must_equal({})
697
- req2 = make_request(e)
698
- req2.params.must_equal({})
699
- end
700
-
701
- it "pass through non-uri escaped cookies as-is" do
702
- req = make_request Rack::MockRequest.env_for("", "HTTP_COOKIE" => "foo=%")
703
- req.cookies["foo"].must_equal "%"
704
- end
705
-
706
- it "parse cookies according to RFC 2109" do
707
- req = make_request \
708
- Rack::MockRequest.env_for('', 'HTTP_COOKIE' => 'foo=bar;foo=car')
709
- req.cookies.must_equal 'foo' => 'bar'
710
- end
711
-
712
- it 'parse cookies with quotes' do
713
- req = make_request Rack::MockRequest.env_for('', {
714
- 'HTTP_COOKIE' => '$Version="1"; Customer="WILE_E_COYOTE"; $Path="/acme"; Part_Number="Rocket_Launcher_0001"; $Path="/acme"'
715
- })
716
- req.cookies.must_equal({
717
- '$Version' => '"1"',
718
- 'Customer' => '"WILE_E_COYOTE"',
719
- '$Path' => '"/acme"',
720
- 'Part_Number' => '"Rocket_Launcher_0001"',
721
- })
722
- end
723
-
724
- it "provide setters" do
725
- req = make_request(e=Rack::MockRequest.env_for(""))
726
- req.script_name.must_equal ""
727
- req.script_name = "/foo"
728
- req.script_name.must_equal "/foo"
729
- e["SCRIPT_NAME"].must_equal "/foo"
730
-
731
- req.path_info.must_equal "/"
732
- req.path_info = "/foo"
733
- req.path_info.must_equal "/foo"
734
- e["PATH_INFO"].must_equal "/foo"
735
- end
736
-
737
- it "provide the original env" do
738
- req = make_request(e = Rack::MockRequest.env_for(""))
739
- req.env.must_equal e
740
- end
741
-
742
- it "restore the base URL" do
743
- make_request(Rack::MockRequest.env_for("")).base_url.
744
- must_equal "http://example.org"
745
- make_request(Rack::MockRequest.env_for("", "SCRIPT_NAME" => "/foo")).base_url.
746
- must_equal "http://example.org"
747
- end
748
-
749
- it "restore the URL" do
750
- make_request(Rack::MockRequest.env_for("")).url.
751
- must_equal "http://example.org/"
752
- make_request(Rack::MockRequest.env_for("", "SCRIPT_NAME" => "/foo")).url.
753
- must_equal "http://example.org/foo/"
754
- make_request(Rack::MockRequest.env_for("/foo")).url.
755
- must_equal "http://example.org/foo"
756
- make_request(Rack::MockRequest.env_for("?foo")).url.
757
- must_equal "http://example.org/?foo"
758
- make_request(Rack::MockRequest.env_for("http://example.org:8080/")).url.
759
- must_equal "http://example.org:8080/"
760
- make_request(Rack::MockRequest.env_for("https://example.org/")).url.
761
- must_equal "https://example.org/"
762
- make_request(Rack::MockRequest.env_for("coffee://example.org/")).url.
763
- must_equal "coffee://example.org/"
764
- make_request(Rack::MockRequest.env_for("coffee://example.org:443/")).url.
765
- must_equal "coffee://example.org:443/"
766
- make_request(Rack::MockRequest.env_for("https://example.com:8080/foo?foo")).url.
767
- must_equal "https://example.com:8080/foo?foo"
768
- end
769
-
770
- it "restore the full path" do
771
- make_request(Rack::MockRequest.env_for("")).fullpath.
772
- must_equal "/"
773
- make_request(Rack::MockRequest.env_for("", "SCRIPT_NAME" => "/foo")).fullpath.
774
- must_equal "/foo/"
775
- make_request(Rack::MockRequest.env_for("/foo")).fullpath.
776
- must_equal "/foo"
777
- make_request(Rack::MockRequest.env_for("?foo")).fullpath.
778
- must_equal "/?foo"
779
- make_request(Rack::MockRequest.env_for("http://example.org:8080/")).fullpath.
780
- must_equal "/"
781
- make_request(Rack::MockRequest.env_for("https://example.org/")).fullpath.
782
- must_equal "/"
783
-
784
- make_request(Rack::MockRequest.env_for("https://example.com:8080/foo?foo")).fullpath.
785
- must_equal "/foo?foo"
786
- end
787
-
788
- it "handle multiple media type parameters" do
789
- req = make_request \
790
- Rack::MockRequest.env_for("/",
791
- "CONTENT_TYPE" => 'text/plain; foo=BAR,baz=bizzle dizzle;BLING=bam;blong="boo";zump="zoo\"o";weird=lol"')
792
- req.wont_be :form_data?
793
- req.media_type_params.must_include 'foo'
794
- req.media_type_params['foo'].must_equal 'BAR'
795
- req.media_type_params.must_include 'baz'
796
- req.media_type_params['baz'].must_equal 'bizzle dizzle'
797
- req.media_type_params.wont_include 'BLING'
798
- req.media_type_params.must_include 'bling'
799
- req.media_type_params['bling'].must_equal 'bam'
800
- req.media_type_params['blong'].must_equal 'boo'
801
- req.media_type_params['zump'].must_equal 'zoo\"o'
802
- req.media_type_params['weird'].must_equal 'lol"'
803
- end
804
-
805
- it "parse with junk before boundary" do
806
- # Adapted from RFC 1867.
807
- input = <<EOF
808
- blah blah\r
809
- \r
810
- --AaB03x\r
811
- content-disposition: form-data; name="reply"\r
812
- \r
813
- yes\r
814
- --AaB03x\r
815
- content-disposition: form-data; name="fileupload"; filename="dj.jpg"\r
816
- Content-Type: image/jpeg\r
817
- Content-Transfer-Encoding: base64\r
818
- \r
819
- /9j/4AAQSkZJRgABAQAAAQABAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcg\r
820
- --AaB03x--\r
821
- EOF
822
- req = make_request Rack::MockRequest.env_for("/",
823
- "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
824
- "CONTENT_LENGTH" => input.size,
825
- :input => input)
826
-
827
- req.POST.must_include "fileupload"
828
- req.POST.must_include "reply"
829
-
830
- req.must_be :form_data?
831
- req.content_length.must_equal input.size
832
- req.media_type.must_equal 'multipart/form-data'
833
- req.media_type_params.must_include 'boundary'
834
- req.media_type_params['boundary'].must_equal 'AaB03x'
835
-
836
- req.POST["reply"].must_equal "yes"
837
-
838
- f = req.POST["fileupload"]
839
- f.must_be_kind_of Hash
840
- f[:type].must_equal "image/jpeg"
841
- f[:filename].must_equal "dj.jpg"
842
- f.must_include :tempfile
843
- f[:tempfile].size.must_equal 76
844
- end
845
-
846
- it "not infinite loop with a malformed HTTP request" do
847
- # Adapted from RFC 1867.
848
- input = <<EOF
849
- --AaB03x
850
- content-disposition: form-data; name="reply"
851
-
852
- yes
853
- --AaB03x
854
- content-disposition: form-data; name="fileupload"; filename="dj.jpg"
855
- Content-Type: image/jpeg
856
- Content-Transfer-Encoding: base64
857
-
858
- /9j/4AAQSkZJRgABAQAAAQABAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcg
859
- --AaB03x--
860
- EOF
861
- req = make_request Rack::MockRequest.env_for("/",
862
- "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
863
- "CONTENT_LENGTH" => input.size,
864
- :input => input)
865
-
866
- lambda{req.POST}.must_raise EOFError
867
- end
868
-
869
-
870
- it "parse multipart form data" do
871
- # Adapted from RFC 1867.
872
- input = <<EOF
873
- --AaB03x\r
874
- content-disposition: form-data; name="reply"\r
875
- \r
876
- yes\r
877
- --AaB03x\r
878
- content-disposition: form-data; name="fileupload"; filename="dj.jpg"\r
879
- Content-Type: image/jpeg\r
880
- Content-Transfer-Encoding: base64\r
881
- \r
882
- /9j/4AAQSkZJRgABAQAAAQABAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcg\r
883
- --AaB03x--\r
884
- EOF
885
- req = make_request Rack::MockRequest.env_for("/",
886
- "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
887
- "CONTENT_LENGTH" => input.size,
888
- :input => input)
889
-
890
- req.POST.must_include "fileupload"
891
- req.POST.must_include "reply"
892
-
893
- req.must_be :form_data?
894
- req.content_length.must_equal input.size
895
- req.media_type.must_equal 'multipart/form-data'
896
- req.media_type_params.must_include 'boundary'
897
- req.media_type_params['boundary'].must_equal 'AaB03x'
898
-
899
- req.POST["reply"].must_equal "yes"
900
-
901
- f = req.POST["fileupload"]
902
- f.must_be_kind_of Hash
903
- f[:type].must_equal "image/jpeg"
904
- f[:filename].must_equal "dj.jpg"
905
- f.must_include :tempfile
906
- f[:tempfile].size.must_equal 76
907
- end
908
-
909
- it "MultipartPartLimitError when request has too many multipart parts if limit set" do
910
- begin
911
- data = 10000.times.map { "--AaB03x\r\nContent-Type: text/plain\r\nContent-Disposition: attachment; name=#{SecureRandom.hex(10)}; filename=#{SecureRandom.hex(10)}\r\n\r\ncontents\r\n" }.join("\r\n")
912
- data += "--AaB03x--\r"
913
-
914
- options = {
915
- "CONTENT_TYPE" => "multipart/form-data; boundary=AaB03x",
916
- "CONTENT_LENGTH" => data.length.to_s,
917
- :input => StringIO.new(data)
918
- }
919
-
920
- request = make_request Rack::MockRequest.env_for("/", options)
921
- lambda { request.POST }.must_raise Rack::Multipart::MultipartPartLimitError
922
- end
923
- end
924
-
925
- it 'closes tempfiles it created in the case of too many created' do
926
- begin
927
- data = 10000.times.map { "--AaB03x\r\nContent-Type: text/plain\r\nContent-Disposition: attachment; name=#{SecureRandom.hex(10)}; filename=#{SecureRandom.hex(10)}\r\n\r\ncontents\r\n" }.join("\r\n")
928
- data += "--AaB03x--\r"
929
-
930
- files = []
931
- options = {
932
- "CONTENT_TYPE" => "multipart/form-data; boundary=AaB03x",
933
- "CONTENT_LENGTH" => data.length.to_s,
934
- Rack::RACK_MULTIPART_TEMPFILE_FACTORY => lambda { |filename, content_type|
935
- file = Tempfile.new(["RackMultipart", ::File.extname(filename)])
936
- files << file
937
- file
938
- },
939
- :input => StringIO.new(data)
940
- }
941
-
942
- request = make_request Rack::MockRequest.env_for("/", options)
943
- assert_raises(Rack::Multipart::MultipartPartLimitError) do
944
- request.POST
945
- end
946
- refute_predicate files, :empty?
947
- files.each { |f| assert_predicate f, :closed? }
948
- end
949
- end
950
-
951
- it "parse big multipart form data" do
952
- input = <<EOF
953
- --AaB03x\r
954
- content-disposition: form-data; name="huge"; filename="huge"\r
955
- \r
956
- #{"x"*32768}\r
957
- --AaB03x\r
958
- content-disposition: form-data; name="mean"; filename="mean"\r
959
- \r
960
- --AaB03xha\r
961
- --AaB03x--\r
962
- EOF
963
- req = make_request Rack::MockRequest.env_for("/",
964
- "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
965
- "CONTENT_LENGTH" => input.size,
966
- :input => input)
967
-
968
- req.POST["huge"][:tempfile].size.must_equal 32768
969
- req.POST["mean"][:tempfile].size.must_equal 10
970
- req.POST["mean"][:tempfile].read.must_equal "--AaB03xha"
971
- end
972
-
973
- it "record tempfiles from multipart form data in env[rack.tempfiles]" do
974
- input = <<EOF
975
- --AaB03x\r
976
- content-disposition: form-data; name="fileupload"; filename="foo.jpg"\r
977
- Content-Type: image/jpeg\r
978
- Content-Transfer-Encoding: base64\r
979
- \r
980
- /9j/4AAQSkZJRgABAQAAAQABAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcg\r
981
- --AaB03x\r
982
- content-disposition: form-data; name="fileupload"; filename="bar.jpg"\r
983
- Content-Type: image/jpeg\r
984
- Content-Transfer-Encoding: base64\r
985
- \r
986
- /9j/4AAQSkZJRgABAQAAAQABAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcg\r
987
- --AaB03x--\r
988
- EOF
989
- env = Rack::MockRequest.env_for("/",
990
- "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
991
- "CONTENT_LENGTH" => input.size,
992
- :input => input)
993
- req = make_request(env)
994
- req.params
995
- env['rack.tempfiles'].size.must_equal 2
996
- end
997
-
998
- it "detect invalid multipart form data" do
999
- input = <<EOF
1000
- --AaB03x\r
1001
- content-disposition: form-data; name="huge"; filename="huge"\r
1002
- EOF
1003
- req = make_request Rack::MockRequest.env_for("/",
1004
- "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
1005
- "CONTENT_LENGTH" => input.size,
1006
- :input => input)
1007
-
1008
- lambda { req.POST }.must_raise EOFError
1009
-
1010
- input = <<EOF
1011
- --AaB03x\r
1012
- content-disposition: form-data; name="huge"; filename="huge"\r
1013
- \r
1014
- foo\r
1015
- EOF
1016
- req = make_request Rack::MockRequest.env_for("/",
1017
- "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
1018
- "CONTENT_LENGTH" => input.size,
1019
- :input => input)
1020
-
1021
- lambda { req.POST }.must_raise EOFError
1022
-
1023
- input = <<EOF
1024
- --AaB03x\r
1025
- content-disposition: form-data; name="huge"; filename="huge"\r
1026
- \r
1027
- foo\r
1028
- EOF
1029
- req = make_request Rack::MockRequest.env_for("/",
1030
- "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
1031
- "CONTENT_LENGTH" => input.size,
1032
- :input => input)
1033
-
1034
- lambda { req.POST }.must_raise EOFError
1035
- end
1036
-
1037
- it "consistently raise EOFError on bad multipart form data" do
1038
- input = <<EOF
1039
- --AaB03x\r
1040
- content-disposition: form-data; name="huge"; filename="huge"\r
1041
- EOF
1042
- req = make_request Rack::MockRequest.env_for("/",
1043
- "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
1044
- "CONTENT_LENGTH" => input.size,
1045
- :input => input)
1046
-
1047
- lambda { req.POST }.must_raise EOFError
1048
- lambda { req.POST }.must_raise EOFError
1049
- end
1050
-
1051
- it "correctly parse the part name from Content-Id header" do
1052
- input = <<EOF
1053
- --AaB03x\r
1054
- Content-Type: text/xml; charset=utf-8\r
1055
- Content-Id: <soap-start>\r
1056
- Content-Transfer-Encoding: 7bit\r
1057
- \r
1058
- foo\r
1059
- --AaB03x--\r
1060
- EOF
1061
- req = make_request Rack::MockRequest.env_for("/",
1062
- "CONTENT_TYPE" => "multipart/related, boundary=AaB03x",
1063
- "CONTENT_LENGTH" => input.size,
1064
- :input => input)
1065
-
1066
- req.params.keys.must_equal ["<soap-start>"]
1067
- end
1068
-
1069
- it "not try to interpret binary as utf8" do
1070
- input = <<EOF
1071
- --AaB03x\r
1072
- content-disposition: form-data; name="fileupload"; filename="junk.a"\r
1073
- content-type: application/octet-stream\r
1074
- \r
1075
- #{[0x36,0xCF,0x0A,0xF8].pack('c*')}\r
1076
- --AaB03x--\r
1077
- EOF
1078
-
1079
- req = make_request Rack::MockRequest.env_for("/",
1080
- "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
1081
- "CONTENT_LENGTH" => input.size,
1082
- :input => input)
1083
-
1084
- req.POST["fileupload"][:tempfile].size.must_equal 4
1085
- end
1086
-
1087
- it "use form_hash when form_input is a Tempfile" do
1088
- input = "{foo: 'bar'}"
1089
-
1090
- rack_input = Tempfile.new("rackspec")
1091
- rack_input.write(input)
1092
- rack_input.rewind
1093
-
1094
- req = make_request Rack::MockRequest.env_for("/",
1095
- "rack.request.form_hash" => {'foo' => 'bar'},
1096
- "rack.request.form_input" => rack_input,
1097
- :input => rack_input)
1098
-
1099
- req.POST.must_equal req.env['rack.request.form_hash']
1100
- end
1101
-
1102
- it "conform to the Rack spec" do
1103
- app = lambda { |env|
1104
- content = make_request(env).POST["file"].inspect
1105
- size = content.bytesize
1106
- [200, {"Content-Type" => "text/html", "Content-Length" => size.to_s}, [content]]
1107
- }
1108
-
1109
- input = <<EOF
1110
- --AaB03x\r
1111
- content-disposition: form-data; name="reply"\r
1112
- \r
1113
- yes\r
1114
- --AaB03x\r
1115
- content-disposition: form-data; name="fileupload"; filename="dj.jpg"\r
1116
- Content-Type: image/jpeg\r
1117
- Content-Transfer-Encoding: base64\r
1118
- \r
1119
- /9j/4AAQSkZJRgABAQAAAQABAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcg\r
1120
- --AaB03x--\r
1121
- EOF
1122
- input.force_encoding(Encoding::ASCII_8BIT)
1123
- res = Rack::MockRequest.new(Rack::Lint.new(app)).get "/",
1124
- "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
1125
- "CONTENT_LENGTH" => input.size.to_s, "rack.input" => StringIO.new(input)
1126
-
1127
- res.must_be :ok?
1128
- end
1129
-
1130
- it "parse Accept-Encoding correctly" do
1131
- parser = lambda do |x|
1132
- make_request(Rack::MockRequest.env_for("", "HTTP_ACCEPT_ENCODING" => x)).accept_encoding
1133
- end
1134
-
1135
- parser.call(nil).must_equal []
1136
-
1137
- parser.call("compress, gzip").must_equal [["compress", 1.0], ["gzip", 1.0]]
1138
- parser.call("").must_equal []
1139
- parser.call("*").must_equal [["*", 1.0]]
1140
- parser.call("compress;q=0.5, gzip;q=1.0").must_equal [["compress", 0.5], ["gzip", 1.0]]
1141
- parser.call("gzip;q=1.0, identity; q=0.5, *;q=0").must_equal [["gzip", 1.0], ["identity", 0.5], ["*", 0] ]
1142
-
1143
- parser.call("gzip ; q=0.9").must_equal [["gzip", 0.9]]
1144
- parser.call("gzip ; deflate").must_equal [["gzip", 1.0]]
1145
- end
1146
-
1147
- it "parse Accept-Language correctly" do
1148
- parser = lambda do |x|
1149
- make_request(Rack::MockRequest.env_for("", "HTTP_ACCEPT_LANGUAGE" => x)).accept_language
1150
- end
1151
-
1152
- parser.call(nil).must_equal []
1153
-
1154
- parser.call("fr, en").must_equal [["fr", 1.0], ["en", 1.0]]
1155
- parser.call("").must_equal []
1156
- parser.call("*").must_equal [["*", 1.0]]
1157
- parser.call("fr;q=0.5, en;q=1.0").must_equal [["fr", 0.5], ["en", 1.0]]
1158
- parser.call("fr;q=1.0, en; q=0.5, *;q=0").must_equal [["fr", 1.0], ["en", 0.5], ["*", 0] ]
1159
-
1160
- parser.call("fr ; q=0.9").must_equal [["fr", 0.9]]
1161
- parser.call("fr").must_equal [["fr", 1.0]]
1162
- end
1163
-
1164
- def ip_app
1165
- lambda { |env|
1166
- request = make_request(env)
1167
- response = Rack::Response.new
1168
- response.write request.ip
1169
- response.finish
1170
- }
1171
- end
1172
-
1173
- it 'provide ip information' do
1174
- mock = Rack::MockRequest.new(Rack::Lint.new(ip_app))
1175
-
1176
- res = mock.get '/', 'REMOTE_ADDR' => '1.2.3.4'
1177
- res.body.must_equal '1.2.3.4'
1178
-
1179
- res = mock.get '/', 'REMOTE_ADDR' => 'fe80::202:b3ff:fe1e:8329'
1180
- res.body.must_equal 'fe80::202:b3ff:fe1e:8329'
1181
-
1182
- res = mock.get '/', 'REMOTE_ADDR' => '1.2.3.4,3.4.5.6'
1183
- res.body.must_equal '1.2.3.4'
1184
- end
1185
-
1186
- it 'deals with proxies' do
1187
- mock = Rack::MockRequest.new(Rack::Lint.new(ip_app))
1188
-
1189
- res = mock.get '/',
1190
- 'REMOTE_ADDR' => '1.2.3.4',
1191
- 'HTTP_X_FORWARDED_FOR' => '3.4.5.6'
1192
- res.body.must_equal '1.2.3.4'
1193
-
1194
- res = mock.get '/',
1195
- 'REMOTE_ADDR' => '1.2.3.4',
1196
- 'HTTP_X_FORWARDED_FOR' => 'unknown'
1197
- res.body.must_equal '1.2.3.4'
1198
-
1199
- res = mock.get '/',
1200
- 'REMOTE_ADDR' => '127.0.0.1',
1201
- 'HTTP_X_FORWARDED_FOR' => '3.4.5.6'
1202
- res.body.must_equal '3.4.5.6'
1203
-
1204
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => 'unknown,3.4.5.6'
1205
- res.body.must_equal '3.4.5.6'
1206
-
1207
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '192.168.0.1,3.4.5.6'
1208
- res.body.must_equal '3.4.5.6'
1209
-
1210
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '10.0.0.1,3.4.5.6'
1211
- res.body.must_equal '3.4.5.6'
1212
-
1213
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '10.0.0.1, 10.0.0.1, 3.4.5.6'
1214
- res.body.must_equal '3.4.5.6'
1215
-
1216
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '127.0.0.1, 3.4.5.6'
1217
- res.body.must_equal '3.4.5.6'
1218
-
1219
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => 'unknown,192.168.0.1'
1220
- res.body.must_equal 'unknown'
1221
-
1222
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => 'other,unknown,192.168.0.1'
1223
- res.body.must_equal 'unknown'
1224
-
1225
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => 'unknown,localhost,192.168.0.1'
1226
- res.body.must_equal 'unknown'
1227
-
1228
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '9.9.9.9, 3.4.5.6, 10.0.0.1, 172.31.4.4'
1229
- res.body.must_equal '3.4.5.6'
1230
-
1231
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '::1,2620:0:1c00:0:812c:9583:754b:ca11'
1232
- res.body.must_equal '2620:0:1c00:0:812c:9583:754b:ca11'
1233
-
1234
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '2620:0:1c00:0:812c:9583:754b:ca11,::1'
1235
- res.body.must_equal '2620:0:1c00:0:812c:9583:754b:ca11'
1236
-
1237
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => 'fd5b:982e:9130:247f:0000:0000:0000:0000,2620:0:1c00:0:812c:9583:754b:ca11'
1238
- res.body.must_equal '2620:0:1c00:0:812c:9583:754b:ca11'
1239
-
1240
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '2620:0:1c00:0:812c:9583:754b:ca11,fd5b:982e:9130:247f:0000:0000:0000:0000'
1241
- res.body.must_equal '2620:0:1c00:0:812c:9583:754b:ca11'
1242
-
1243
- res = mock.get '/',
1244
- 'HTTP_X_FORWARDED_FOR' => '1.1.1.1, 127.0.0.1',
1245
- 'HTTP_CLIENT_IP' => '1.1.1.1'
1246
- res.body.must_equal '1.1.1.1'
1247
-
1248
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '8.8.8.8, 9.9.9.9'
1249
- res.body.must_equal '9.9.9.9'
1250
-
1251
- res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '8.8.8.8, fe80::202:b3ff:fe1e:8329'
1252
- res.body.must_equal 'fe80::202:b3ff:fe1e:8329'
1253
-
1254
- # Unix Sockets
1255
- res = mock.get '/',
1256
- 'REMOTE_ADDR' => 'unix',
1257
- 'HTTP_X_FORWARDED_FOR' => '3.4.5.6'
1258
- res.body.must_equal '3.4.5.6'
1259
-
1260
- res = mock.get '/',
1261
- 'REMOTE_ADDR' => 'unix:/tmp/foo',
1262
- 'HTTP_X_FORWARDED_FOR' => '3.4.5.6'
1263
- res.body.must_equal '3.4.5.6'
1264
- end
1265
-
1266
- it "not allow IP spoofing via Client-IP and X-Forwarded-For headers" do
1267
- mock = Rack::MockRequest.new(Rack::Lint.new(ip_app))
1268
-
1269
- # IP Spoofing attempt:
1270
- # Client sends X-Forwarded-For: 6.6.6.6
1271
- # Client-IP: 6.6.6.6
1272
- # Load balancer adds X-Forwarded-For: 2.2.2.3, 192.168.0.7
1273
- # App receives: X-Forwarded-For: 6.6.6.6
1274
- # X-Forwarded-For: 2.2.2.3, 192.168.0.7
1275
- # Client-IP: 6.6.6.6
1276
- # Rack env: HTTP_X_FORWARDED_FOR: '6.6.6.6, 2.2.2.3, 192.168.0.7'
1277
- # HTTP_CLIENT_IP: '6.6.6.6'
1278
- res = mock.get '/',
1279
- 'HTTP_X_FORWARDED_FOR' => '6.6.6.6, 2.2.2.3, 192.168.0.7',
1280
- 'HTTP_CLIENT_IP' => '6.6.6.6'
1281
- res.body.must_equal '2.2.2.3'
1282
- end
1283
-
1284
- it "regard local addresses as proxies" do
1285
- req = make_request(Rack::MockRequest.env_for("/"))
1286
- req.trusted_proxy?('127.0.0.1').must_equal 0
1287
- req.trusted_proxy?('10.0.0.1').must_equal 0
1288
- req.trusted_proxy?('172.16.0.1').must_equal 0
1289
- req.trusted_proxy?('172.20.0.1').must_equal 0
1290
- req.trusted_proxy?('172.30.0.1').must_equal 0
1291
- req.trusted_proxy?('172.31.0.1').must_equal 0
1292
- req.trusted_proxy?('192.168.0.1').must_equal 0
1293
- req.trusted_proxy?('::1').must_equal 0
1294
- req.trusted_proxy?('fd00::').must_equal 0
1295
- req.trusted_proxy?('localhost').must_equal 0
1296
- req.trusted_proxy?('unix').must_equal 0
1297
- req.trusted_proxy?('unix:/tmp/sock').must_equal 0
1298
-
1299
- req.trusted_proxy?("unix.example.org").must_be_nil
1300
- req.trusted_proxy?("example.org\n127.0.0.1").must_be_nil
1301
- req.trusted_proxy?("127.0.0.1\nexample.org").must_be_nil
1302
- req.trusted_proxy?("11.0.0.1").must_be_nil
1303
- req.trusted_proxy?("172.15.0.1").must_be_nil
1304
- req.trusted_proxy?("172.32.0.1").must_be_nil
1305
- req.trusted_proxy?("2001:470:1f0b:18f8::1").must_be_nil
1306
- end
1307
-
1308
- it "sets the default session to an empty hash" do
1309
- req = make_request(Rack::MockRequest.env_for("http://example.com:8080/"))
1310
- assert_equal Hash.new, req.session
1311
- end
1312
-
1313
- class MyRequest < Rack::Request
1314
- def params
1315
- {:foo => "bar"}
1316
- end
1317
- end
1318
-
1319
- it "allow subclass request to be instantiated after parent request" do
1320
- env = Rack::MockRequest.env_for("/?foo=bar")
1321
-
1322
- req1 = make_request(env)
1323
- req1.GET.must_equal "foo" => "bar"
1324
- req1.params.must_equal "foo" => "bar"
1325
-
1326
- req2 = MyRequest.new(env)
1327
- req2.GET.must_equal "foo" => "bar"
1328
- req2.params.must_equal :foo => "bar"
1329
- end
1330
-
1331
- it "allow parent request to be instantiated after subclass request" do
1332
- env = Rack::MockRequest.env_for("/?foo=bar")
1333
-
1334
- req1 = MyRequest.new(env)
1335
- req1.GET.must_equal "foo" => "bar"
1336
- req1.params.must_equal :foo => "bar"
1337
-
1338
- req2 = make_request(env)
1339
- req2.GET.must_equal "foo" => "bar"
1340
- req2.params.must_equal "foo" => "bar"
1341
- end
1342
-
1343
- it "raise TypeError every time if request parameters are broken" do
1344
- broken_query = Rack::MockRequest.env_for("/?foo%5B%5D=0&foo%5Bbar%5D=1")
1345
- req = make_request(broken_query)
1346
- lambda{req.GET}.must_raise TypeError
1347
- lambda{req.params}.must_raise TypeError
1348
- end
1349
-
1350
- (0x20...0x7E).collect { |a|
1351
- b = a.chr
1352
- c = CGI.escape(b)
1353
- it "not strip '#{a}' => '#{c}' => '#{b}' escaped character from parameters when accessed as string" do
1354
- url = "/?foo=#{c}bar#{c}"
1355
- env = Rack::MockRequest.env_for(url)
1356
- req2 = make_request(env)
1357
- req2.GET.must_equal "foo" => "#{b}bar#{b}"
1358
- req2.params.must_equal "foo" => "#{b}bar#{b}"
1359
- end
1360
- }
1361
-
1362
- class NonDelegate < Rack::Request
1363
- def delegate?; false; end
1364
- end
1365
-
1366
- def make_request(env)
1367
- NonDelegate.new env
1368
- end
1369
-
1370
- class TestProxyRequest < RackRequestTest
1371
- class DelegateRequest
1372
- include Rack::Request::Helpers
1373
- extend Forwardable
1374
-
1375
- def_delegators :@req, :has_header?, :get_header, :fetch_header,
1376
- :each_header, :set_header, :add_header, :delete_header
1377
-
1378
- def_delegators :@req, :[], :[]=, :values_at
1379
-
1380
- def initialize(req)
1381
- @req = req
1382
- end
1383
-
1384
- def delegate?; true; end
1385
-
1386
- def env; @req.env.dup; end
1387
- end
1388
-
1389
- def make_request(env)
1390
- DelegateRequest.new super(env)
1391
- end
1392
- end
1393
- end