rack 2.0.9.3 → 3.0.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 (201) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +808 -0
  3. data/CONTRIBUTING.md +142 -0
  4. data/{COPYING → MIT-LICENSE} +4 -2
  5. data/README.md +293 -0
  6. data/SPEC.rdoc +340 -0
  7. data/lib/rack/auth/abstract/handler.rb +6 -2
  8. data/lib/rack/auth/abstract/request.rb +4 -2
  9. data/lib/rack/auth/basic.rb +7 -4
  10. data/lib/rack/auth/digest/md5.rb +1 -129
  11. data/lib/rack/auth/digest/nonce.rb +1 -51
  12. data/lib/rack/auth/digest/params.rb +1 -52
  13. data/lib/rack/auth/digest/request.rb +1 -41
  14. data/lib/rack/auth/digest.rb +256 -0
  15. data/lib/rack/body_proxy.rb +18 -15
  16. data/lib/rack/builder.rb +151 -40
  17. data/lib/rack/cascade.rb +30 -12
  18. data/lib/rack/chunked.rb +74 -23
  19. data/lib/rack/common_logger.rb +49 -36
  20. data/lib/rack/conditional_get.rb +33 -26
  21. data/lib/rack/config.rb +2 -0
  22. data/lib/rack/constants.rb +63 -0
  23. data/lib/rack/content_length.rb +13 -16
  24. data/lib/rack/content_type.rb +12 -8
  25. data/lib/rack/deflater.rb +84 -45
  26. data/lib/rack/directory.rb +90 -64
  27. data/lib/rack/etag.rb +17 -23
  28. data/lib/rack/events.rb +23 -20
  29. data/lib/rack/file.rb +5 -172
  30. data/lib/rack/files.rb +216 -0
  31. data/lib/rack/head.rb +10 -9
  32. data/lib/rack/headers.rb +154 -0
  33. data/lib/rack/lint.rb +786 -645
  34. data/lib/rack/lock.rb +4 -6
  35. data/lib/rack/logger.rb +4 -0
  36. data/lib/rack/media_type.rb +10 -5
  37. data/lib/rack/method_override.rb +8 -2
  38. data/lib/rack/mime.rb +17 -1
  39. data/lib/rack/mock.rb +2 -195
  40. data/lib/rack/mock_request.rb +166 -0
  41. data/lib/rack/mock_response.rb +126 -0
  42. data/lib/rack/multipart/generator.rb +21 -15
  43. data/lib/rack/multipart/parser.rb +161 -118
  44. data/lib/rack/multipart/uploaded_file.rb +19 -7
  45. data/lib/rack/multipart.rb +23 -41
  46. data/lib/rack/null_logger.rb +11 -0
  47. data/lib/rack/query_parser.rb +126 -65
  48. data/lib/rack/recursive.rb +9 -5
  49. data/lib/rack/reloader.rb +6 -4
  50. data/lib/rack/request.rb +331 -74
  51. data/lib/rack/response.rb +223 -70
  52. data/lib/rack/rewindable_input.rb +28 -8
  53. data/lib/rack/runtime.rb +11 -8
  54. data/lib/rack/sendfile.rb +42 -33
  55. data/lib/rack/show_exceptions.rb +35 -18
  56. data/lib/rack/show_status.rb +25 -15
  57. data/lib/rack/static.rb +30 -18
  58. data/lib/rack/tempfile_reaper.rb +16 -5
  59. data/lib/rack/urlmap.rb +14 -6
  60. data/lib/rack/utils.rb +268 -260
  61. data/lib/rack/version.rb +34 -0
  62. data/lib/rack.rb +15 -92
  63. metadata +44 -207
  64. data/HISTORY.md +0 -520
  65. data/README.rdoc +0 -316
  66. data/Rakefile +0 -116
  67. data/SPEC +0 -263
  68. data/bin/rackup +0 -4
  69. data/contrib/rack.png +0 -0
  70. data/contrib/rack.svg +0 -150
  71. data/contrib/rack_logo.svg +0 -164
  72. data/contrib/rdoc.css +0 -412
  73. data/example/lobster.ru +0 -4
  74. data/example/protectedlobster.rb +0 -14
  75. data/example/protectedlobster.ru +0 -8
  76. data/lib/rack/handler/cgi.rb +0 -60
  77. data/lib/rack/handler/fastcgi.rb +0 -100
  78. data/lib/rack/handler/lsws.rb +0 -61
  79. data/lib/rack/handler/scgi.rb +0 -70
  80. data/lib/rack/handler/thin.rb +0 -36
  81. data/lib/rack/handler/webrick.rb +0 -120
  82. data/lib/rack/handler.rb +0 -99
  83. data/lib/rack/lobster.rb +0 -70
  84. data/lib/rack/server.rb +0 -395
  85. data/lib/rack/session/abstract/id.rb +0 -510
  86. data/lib/rack/session/cookie.rb +0 -204
  87. data/lib/rack/session/memcache.rb +0 -99
  88. data/lib/rack/session/pool.rb +0 -83
  89. data/rack.gemspec +0 -34
  90. data/test/builder/an_underscore_app.rb +0 -5
  91. data/test/builder/anything.rb +0 -5
  92. data/test/builder/comment.ru +0 -4
  93. data/test/builder/end.ru +0 -5
  94. data/test/builder/line.ru +0 -1
  95. data/test/builder/options.ru +0 -2
  96. data/test/cgi/assets/folder/test.js +0 -1
  97. data/test/cgi/assets/fonts/font.eot +0 -1
  98. data/test/cgi/assets/images/image.png +0 -1
  99. data/test/cgi/assets/index.html +0 -1
  100. data/test/cgi/assets/javascripts/app.js +0 -1
  101. data/test/cgi/assets/stylesheets/app.css +0 -1
  102. data/test/cgi/lighttpd.conf +0 -26
  103. data/test/cgi/rackup_stub.rb +0 -6
  104. data/test/cgi/sample_rackup.ru +0 -5
  105. data/test/cgi/test +0 -9
  106. data/test/cgi/test+directory/test+file +0 -1
  107. data/test/cgi/test.fcgi +0 -9
  108. data/test/cgi/test.gz +0 -0
  109. data/test/cgi/test.ru +0 -5
  110. data/test/gemloader.rb +0 -10
  111. data/test/helper.rb +0 -34
  112. data/test/multipart/bad_robots +0 -259
  113. data/test/multipart/binary +0 -0
  114. data/test/multipart/content_type_and_no_filename +0 -6
  115. data/test/multipart/empty +0 -10
  116. data/test/multipart/fail_16384_nofile +0 -814
  117. data/test/multipart/file1.txt +0 -1
  118. data/test/multipart/filename_and_modification_param +0 -7
  119. data/test/multipart/filename_and_no_name +0 -6
  120. data/test/multipart/filename_with_encoded_words +0 -7
  121. data/test/multipart/filename_with_escaped_quotes +0 -6
  122. data/test/multipart/filename_with_escaped_quotes_and_modification_param +0 -7
  123. data/test/multipart/filename_with_null_byte +0 -7
  124. data/test/multipart/filename_with_percent_escaped_quotes +0 -6
  125. data/test/multipart/filename_with_single_quote +0 -7
  126. data/test/multipart/filename_with_unescaped_percentages +0 -6
  127. data/test/multipart/filename_with_unescaped_percentages2 +0 -6
  128. data/test/multipart/filename_with_unescaped_percentages3 +0 -6
  129. data/test/multipart/filename_with_unescaped_quotes +0 -6
  130. data/test/multipart/ie +0 -6
  131. data/test/multipart/invalid_character +0 -6
  132. data/test/multipart/mixed_files +0 -21
  133. data/test/multipart/nested +0 -10
  134. data/test/multipart/none +0 -9
  135. data/test/multipart/quoted +0 -15
  136. data/test/multipart/rack-logo.png +0 -0
  137. data/test/multipart/semicolon +0 -6
  138. data/test/multipart/text +0 -15
  139. data/test/multipart/three_files_three_fields +0 -31
  140. data/test/multipart/unity3d_wwwform +0 -11
  141. data/test/multipart/webkit +0 -32
  142. data/test/rackup/config.ru +0 -31
  143. data/test/registering_handler/rack/handler/registering_myself.rb +0 -8
  144. data/test/spec_auth_basic.rb +0 -89
  145. data/test/spec_auth_digest.rb +0 -260
  146. data/test/spec_body_proxy.rb +0 -85
  147. data/test/spec_builder.rb +0 -233
  148. data/test/spec_cascade.rb +0 -63
  149. data/test/spec_cgi.rb +0 -84
  150. data/test/spec_chunked.rb +0 -103
  151. data/test/spec_common_logger.rb +0 -107
  152. data/test/spec_conditional_get.rb +0 -103
  153. data/test/spec_config.rb +0 -23
  154. data/test/spec_content_length.rb +0 -86
  155. data/test/spec_content_type.rb +0 -46
  156. data/test/spec_deflater.rb +0 -375
  157. data/test/spec_directory.rb +0 -148
  158. data/test/spec_etag.rb +0 -108
  159. data/test/spec_events.rb +0 -133
  160. data/test/spec_fastcgi.rb +0 -85
  161. data/test/spec_file.rb +0 -264
  162. data/test/spec_handler.rb +0 -57
  163. data/test/spec_head.rb +0 -46
  164. data/test/spec_lint.rb +0 -520
  165. data/test/spec_lobster.rb +0 -59
  166. data/test/spec_lock.rb +0 -204
  167. data/test/spec_logger.rb +0 -24
  168. data/test/spec_media_type.rb +0 -42
  169. data/test/spec_method_override.rb +0 -110
  170. data/test/spec_mime.rb +0 -51
  171. data/test/spec_mock.rb +0 -359
  172. data/test/spec_multipart.rb +0 -721
  173. data/test/spec_null_logger.rb +0 -21
  174. data/test/spec_recursive.rb +0 -75
  175. data/test/spec_request.rb +0 -1423
  176. data/test/spec_response.rb +0 -528
  177. data/test/spec_rewindable_input.rb +0 -128
  178. data/test/spec_runtime.rb +0 -50
  179. data/test/spec_sendfile.rb +0 -125
  180. data/test/spec_server.rb +0 -193
  181. data/test/spec_session_abstract_id.rb +0 -31
  182. data/test/spec_session_abstract_session_hash.rb +0 -45
  183. data/test/spec_session_cookie.rb +0 -442
  184. data/test/spec_session_memcache.rb +0 -357
  185. data/test/spec_session_persisted_secure_secure_session_hash.rb +0 -73
  186. data/test/spec_session_pool.rb +0 -247
  187. data/test/spec_show_exceptions.rb +0 -93
  188. data/test/spec_show_status.rb +0 -104
  189. data/test/spec_static.rb +0 -184
  190. data/test/spec_tempfile_reaper.rb +0 -64
  191. data/test/spec_thin.rb +0 -96
  192. data/test/spec_urlmap.rb +0 -237
  193. data/test/spec_utils.rb +0 -742
  194. data/test/spec_version.rb +0 -11
  195. data/test/spec_webrick.rb +0 -206
  196. data/test/static/another/index.html +0 -1
  197. data/test/static/foo.html +0 -1
  198. data/test/static/index.html +0 -1
  199. data/test/testrequest.rb +0 -78
  200. data/test/unregistered_handler/rack/handler/unregistered.rb +0 -7
  201. data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +0 -7
data/test/spec_utils.rb DELETED
@@ -1,742 +0,0 @@
1
- # -*- encoding: utf-8 -*-
2
- require 'minitest/autorun'
3
- require 'rack/utils'
4
- require 'rack/mock'
5
- require 'timeout'
6
-
7
- describe Rack::Utils do
8
-
9
- def assert_sets exp, act
10
- exp = Set.new exp.split '&'
11
- act = Set.new act.split '&'
12
-
13
- assert_equal exp, act
14
- end
15
-
16
- def assert_query exp, act
17
- assert_sets exp, Rack::Utils.build_query(act)
18
- end
19
-
20
- def assert_nested_query exp, act
21
- assert_sets exp, Rack::Utils.build_nested_query(act)
22
- end
23
-
24
- it 'can be mixed in and used' do
25
- instance = Class.new {
26
- include Rack::Utils
27
-
28
- public :parse_nested_query
29
- public :parse_query
30
- }.new
31
-
32
- assert_equal({ "foo" => "bar" }, instance.parse_nested_query("foo=bar"))
33
- assert_equal({ "foo" => "bar" }, instance.parse_query("foo=bar"))
34
- end
35
-
36
- it "round trip binary data" do
37
- r = [218, 0].pack 'CC'
38
- z = Rack::Utils.unescape(Rack::Utils.escape(r), Encoding::BINARY)
39
- r.must_equal z
40
- end
41
-
42
- it "escape correctly" do
43
- Rack::Utils.escape("fo<o>bar").must_equal "fo%3Co%3Ebar"
44
- Rack::Utils.escape("a space").must_equal "a+space"
45
- Rack::Utils.escape("q1!2\"'w$5&7/z8)?\\").
46
- must_equal "q1%212%22%27w%245%267%2Fz8%29%3F%5C"
47
- end
48
-
49
- it "escape correctly for multibyte characters" do
50
- matz_name = "\xE3\x81\xBE\xE3\x81\xA4\xE3\x82\x82\xE3\x81\xA8".unpack("a*")[0] # Matsumoto
51
- matz_name.force_encoding(Encoding::UTF_8)
52
- Rack::Utils.escape(matz_name).must_equal '%E3%81%BE%E3%81%A4%E3%82%82%E3%81%A8'
53
- matz_name_sep = "\xE3\x81\xBE\xE3\x81\xA4 \xE3\x82\x82\xE3\x81\xA8".unpack("a*")[0] # Matsu moto
54
- matz_name_sep.force_encoding("UTF-8") if matz_name_sep.respond_to? :force_encoding
55
- Rack::Utils.escape(matz_name_sep).must_equal '%E3%81%BE%E3%81%A4+%E3%82%82%E3%81%A8'
56
- end
57
-
58
- it "escape objects that responds to to_s" do
59
- Rack::Utils.escape(:id).must_equal "id"
60
- end
61
-
62
- it "escape non-UTF8 strings" do
63
- Rack::Utils.escape("ø".encode("ISO-8859-1")).must_equal "%F8"
64
- end
65
-
66
- it "not hang on escaping long strings that end in % (http://redmine.ruby-lang.org/issues/5149)" do
67
- Timeout.timeout(1) do
68
- lambda {
69
- URI.decode_www_form_component "A string that causes catastrophic backtracking as it gets longer %"
70
- }.must_raise ArgumentError
71
- end
72
- end
73
-
74
- it "escape path spaces with %20" do
75
- Rack::Utils.escape_path("foo bar").must_equal "foo%20bar"
76
- end
77
-
78
- it "unescape correctly" do
79
- Rack::Utils.unescape("fo%3Co%3Ebar").must_equal "fo<o>bar"
80
- Rack::Utils.unescape("a+space").must_equal "a space"
81
- Rack::Utils.unescape("a%20space").must_equal "a space"
82
- Rack::Utils.unescape("q1%212%22%27w%245%267%2Fz8%29%3F%5C").
83
- must_equal "q1!2\"'w$5&7/z8)?\\"
84
- end
85
-
86
- it "parse query strings correctly" do
87
- Rack::Utils.parse_query("foo=bar").
88
- must_equal "foo" => "bar"
89
- Rack::Utils.parse_query("foo=\"bar\"").
90
- must_equal "foo" => "\"bar\""
91
- Rack::Utils.parse_query("foo=bar&foo=quux").
92
- must_equal "foo" => ["bar", "quux"]
93
- Rack::Utils.parse_query("foo=1&bar=2").
94
- must_equal "foo" => "1", "bar" => "2"
95
- Rack::Utils.parse_query("my+weird+field=q1%212%22%27w%245%267%2Fz8%29%3F").
96
- must_equal "my weird field" => "q1!2\"'w$5&7/z8)?"
97
- Rack::Utils.parse_query("foo%3Dbaz=bar").must_equal "foo=baz" => "bar"
98
- Rack::Utils.parse_query("=").must_equal "" => ""
99
- Rack::Utils.parse_query("=value").must_equal "" => "value"
100
- Rack::Utils.parse_query("key=").must_equal "key" => ""
101
- Rack::Utils.parse_query("&key&").must_equal "key" => nil
102
- Rack::Utils.parse_query(";key;", ";,").must_equal "key" => nil
103
- Rack::Utils.parse_query(",key,", ";,").must_equal "key" => nil
104
- Rack::Utils.parse_query(";foo=bar,;", ";,").must_equal "foo" => "bar"
105
- Rack::Utils.parse_query(",foo=bar;,", ";,").must_equal "foo" => "bar"
106
- end
107
-
108
- it "not create infinite loops with cycle structures" do
109
- ex = { "foo" => nil }
110
- ex["foo"] = ex
111
-
112
- params = Rack::Utils::KeySpaceConstrainedParams.new(65536)
113
- params['foo'] = params
114
- params.to_params_hash.to_s.must_equal ex.to_s
115
- end
116
-
117
- it "parse nil as an empty query string" do
118
- Rack::Utils.parse_nested_query(nil).must_equal({})
119
- end
120
-
121
- it "raise an exception if the params are too deep" do
122
- len = Rack::Utils.param_depth_limit
123
-
124
- lambda {
125
- Rack::Utils.parse_nested_query("foo#{"[a]" * len}=bar")
126
- }.must_raise(RangeError)
127
-
128
- Rack::Utils.parse_nested_query("foo#{"[a]" * (len - 1)}=bar")
129
- end
130
-
131
- it "parse nested query strings correctly" do
132
- Rack::Utils.parse_nested_query("foo").
133
- must_equal "foo" => nil
134
- Rack::Utils.parse_nested_query("foo=").
135
- must_equal "foo" => ""
136
- Rack::Utils.parse_nested_query("foo=bar").
137
- must_equal "foo" => "bar"
138
- Rack::Utils.parse_nested_query("foo=\"bar\"").
139
- must_equal "foo" => "\"bar\""
140
-
141
- Rack::Utils.parse_nested_query("foo=bar&foo=quux").
142
- must_equal "foo" => "quux"
143
- Rack::Utils.parse_nested_query("foo&foo=").
144
- must_equal "foo" => ""
145
- Rack::Utils.parse_nested_query("foo=1&bar=2").
146
- must_equal "foo" => "1", "bar" => "2"
147
- Rack::Utils.parse_nested_query("&foo=1&&bar=2").
148
- must_equal "foo" => "1", "bar" => "2"
149
- Rack::Utils.parse_nested_query("foo&bar=").
150
- must_equal "foo" => nil, "bar" => ""
151
- Rack::Utils.parse_nested_query("foo=bar&baz=").
152
- must_equal "foo" => "bar", "baz" => ""
153
- Rack::Utils.parse_nested_query("my+weird+field=q1%212%22%27w%245%267%2Fz8%29%3F").
154
- must_equal "my weird field" => "q1!2\"'w$5&7/z8)?"
155
-
156
- Rack::Utils.parse_nested_query("a=b&pid%3D1234=1023").
157
- must_equal "pid=1234" => "1023", "a" => "b"
158
-
159
- Rack::Utils.parse_nested_query("foo[]").
160
- must_equal "foo" => [nil]
161
- Rack::Utils.parse_nested_query("foo[]=").
162
- must_equal "foo" => [""]
163
- Rack::Utils.parse_nested_query("foo[]=bar").
164
- must_equal "foo" => ["bar"]
165
- Rack::Utils.parse_nested_query("foo[]=bar&foo").
166
- must_equal "foo" => nil
167
- Rack::Utils.parse_nested_query("foo[]=bar&foo[").
168
- must_equal "foo" => ["bar"], "foo[" => nil
169
- Rack::Utils.parse_nested_query("foo[]=bar&foo[=baz").
170
- must_equal "foo" => ["bar"], "foo[" => "baz"
171
- Rack::Utils.parse_nested_query("foo[]=bar&foo[]").
172
- must_equal "foo" => ["bar", nil]
173
- Rack::Utils.parse_nested_query("foo[]=bar&foo[]=").
174
- must_equal "foo" => ["bar", ""]
175
-
176
- Rack::Utils.parse_nested_query("foo[]=1&foo[]=2").
177
- must_equal "foo" => ["1", "2"]
178
- Rack::Utils.parse_nested_query("foo=bar&baz[]=1&baz[]=2&baz[]=3").
179
- must_equal "foo" => "bar", "baz" => ["1", "2", "3"]
180
- Rack::Utils.parse_nested_query("foo[]=bar&baz[]=1&baz[]=2&baz[]=3").
181
- must_equal "foo" => ["bar"], "baz" => ["1", "2", "3"]
182
-
183
- Rack::Utils.parse_nested_query("x[y][z]=1").
184
- must_equal "x" => {"y" => {"z" => "1"}}
185
- Rack::Utils.parse_nested_query("x[y][z][]=1").
186
- must_equal "x" => {"y" => {"z" => ["1"]}}
187
- Rack::Utils.parse_nested_query("x[y][z]=1&x[y][z]=2").
188
- must_equal "x" => {"y" => {"z" => "2"}}
189
- Rack::Utils.parse_nested_query("x[y][z][]=1&x[y][z][]=2").
190
- must_equal "x" => {"y" => {"z" => ["1", "2"]}}
191
-
192
- Rack::Utils.parse_nested_query("x[y][][z]=1").
193
- must_equal "x" => {"y" => [{"z" => "1"}]}
194
- Rack::Utils.parse_nested_query("x[y][][z][]=1").
195
- must_equal "x" => {"y" => [{"z" => ["1"]}]}
196
- Rack::Utils.parse_nested_query("x[y][][z]=1&x[y][][w]=2").
197
- must_equal "x" => {"y" => [{"z" => "1", "w" => "2"}]}
198
-
199
- Rack::Utils.parse_nested_query("x[y][][v][w]=1").
200
- must_equal "x" => {"y" => [{"v" => {"w" => "1"}}]}
201
- Rack::Utils.parse_nested_query("x[y][][z]=1&x[y][][v][w]=2").
202
- must_equal "x" => {"y" => [{"z" => "1", "v" => {"w" => "2"}}]}
203
-
204
- Rack::Utils.parse_nested_query("x[y][][z]=1&x[y][][z]=2").
205
- must_equal "x" => {"y" => [{"z" => "1"}, {"z" => "2"}]}
206
- Rack::Utils.parse_nested_query("x[y][][z]=1&x[y][][w]=a&x[y][][z]=2&x[y][][w]=3").
207
- must_equal "x" => {"y" => [{"z" => "1", "w" => "a"}, {"z" => "2", "w" => "3"}]}
208
-
209
- Rack::Utils.parse_nested_query("x[][y]=1&x[][z][w]=a&x[][y]=2&x[][z][w]=b").
210
- must_equal "x" => [{"y" => "1", "z" => {"w" => "a"}}, {"y" => "2", "z" => {"w" => "b"}}]
211
- Rack::Utils.parse_nested_query("x[][z][w]=a&x[][y]=1&x[][z][w]=b&x[][y]=2").
212
- must_equal "x" => [{"y" => "1", "z" => {"w" => "a"}}, {"y" => "2", "z" => {"w" => "b"}}]
213
-
214
- Rack::Utils.parse_nested_query("data[books][][data][page]=1&data[books][][data][page]=2").
215
- must_equal "data" => { "books" => [{ "data" => { "page" => "1"}}, { "data" => { "page" => "2"}}] }
216
-
217
- lambda { Rack::Utils.parse_nested_query("x[y]=1&x[y]z=2") }.
218
- must_raise(Rack::Utils::ParameterTypeError).
219
- message.must_equal "expected Hash (got String) for param `y'"
220
-
221
- lambda { Rack::Utils.parse_nested_query("x[y]=1&x[]=1") }.
222
- must_raise(Rack::Utils::ParameterTypeError).
223
- message.must_match(/expected Array \(got [^)]*\) for param `x'/)
224
-
225
- lambda { Rack::Utils.parse_nested_query("x[y]=1&x[y][][w]=2") }.
226
- must_raise(Rack::Utils::ParameterTypeError).
227
- message.must_equal "expected Array (got String) for param `y'"
228
-
229
- lambda { Rack::Utils.parse_nested_query("foo%81E=1") }.
230
- must_raise(Rack::Utils::InvalidParameterError).
231
- message.must_equal "invalid byte sequence in UTF-8"
232
- end
233
-
234
- it "only moves to a new array when the full key has been seen" do
235
- Rack::Utils.parse_nested_query("x[][y][][z]=1&x[][y][][w]=2").
236
- must_equal "x" => [{"y" => [{"z" => "1", "w" => "2"}]}]
237
-
238
- Rack::Utils.parse_nested_query(
239
- "x[][id]=1&x[][y][a]=5&x[][y][b]=7&x[][z][id]=3&x[][z][w]=0&x[][id]=2&x[][y][a]=6&x[][y][b]=8&x[][z][id]=4&x[][z][w]=0"
240
- ).must_equal "x" => [
241
- {"id" => "1", "y" => {"a" => "5", "b" => "7"}, "z" => {"id" => "3", "w" => "0"}},
242
- {"id" => "2", "y" => {"a" => "6", "b" => "8"}, "z" => {"id" => "4", "w" => "0"}},
243
- ]
244
- end
245
-
246
- it "allow setting the params hash class to use for parsing query strings" do
247
- begin
248
- default_parser = Rack::Utils.default_query_parser
249
- param_parser_class = Class.new(Rack::QueryParser::Params) do
250
- def initialize(*)
251
- super
252
- @params = Hash.new{|h,k| h[k.to_s] if k.is_a?(Symbol)}
253
- end
254
- end
255
- Rack::Utils.default_query_parser = Rack::QueryParser.new(param_parser_class, 65536, 100)
256
- Rack::Utils.parse_query(",foo=bar;,", ";,")[:foo].must_equal "bar"
257
- Rack::Utils.parse_nested_query("x[y][][z]=1&x[y][][w]=2")[:x][:y][0][:z].must_equal "1"
258
- ensure
259
- Rack::Utils.default_query_parser = default_parser
260
- end
261
- end
262
-
263
- it "build query strings correctly" do
264
- assert_query "foo=bar", "foo" => "bar"
265
- assert_query "foo=bar&foo=quux", "foo" => ["bar", "quux"]
266
- assert_query "foo=1&bar=2", "foo" => "1", "bar" => "2"
267
- assert_query("my+weird+field=q1%212%22%27w%245%267%2Fz8%29%3F",
268
- "my weird field" => "q1!2\"'w$5&7/z8)?")
269
- end
270
-
271
- it "build nested query strings correctly" do
272
- Rack::Utils.build_nested_query("foo" => nil).must_equal "foo"
273
- Rack::Utils.build_nested_query("foo" => "").must_equal "foo="
274
- Rack::Utils.build_nested_query("foo" => "bar").must_equal "foo=bar"
275
-
276
- assert_nested_query("foo=1&bar=2",
277
- "foo" => "1", "bar" => "2")
278
- assert_nested_query("foo=1&bar=2",
279
- "foo" => 1, "bar" => 2)
280
- assert_nested_query("my+weird+field=q1%212%22%27w%245%267%2Fz8%29%3F",
281
- "my weird field" => "q1!2\"'w$5&7/z8)?")
282
-
283
- Rack::Utils.build_nested_query("foo" => [nil]).must_equal "foo[]"
284
- Rack::Utils.build_nested_query("foo" => [""]).must_equal "foo[]="
285
- Rack::Utils.build_nested_query("foo" => ["bar"]).must_equal "foo[]=bar"
286
- Rack::Utils.build_nested_query('foo' => []).must_equal ''
287
- Rack::Utils.build_nested_query('foo' => {}).must_equal ''
288
- Rack::Utils.build_nested_query('foo' => 'bar', 'baz' => []).must_equal 'foo=bar'
289
- Rack::Utils.build_nested_query('foo' => 'bar', 'baz' => {}).must_equal 'foo=bar'
290
-
291
- Rack::Utils.build_nested_query('foo' => nil, 'bar' => '').
292
- must_equal 'foo&bar='
293
- Rack::Utils.build_nested_query('foo' => 'bar', 'baz' => '').
294
- must_equal 'foo=bar&baz='
295
- Rack::Utils.build_nested_query('foo' => ['1', '2']).
296
- must_equal 'foo[]=1&foo[]=2'
297
- Rack::Utils.build_nested_query('foo' => 'bar', 'baz' => ['1', '2', '3']).
298
- must_equal 'foo=bar&baz[]=1&baz[]=2&baz[]=3'
299
- Rack::Utils.build_nested_query('foo' => ['bar'], 'baz' => ['1', '2', '3']).
300
- must_equal 'foo[]=bar&baz[]=1&baz[]=2&baz[]=3'
301
- Rack::Utils.build_nested_query('foo' => ['bar'], 'baz' => ['1', '2', '3']).
302
- must_equal 'foo[]=bar&baz[]=1&baz[]=2&baz[]=3'
303
- Rack::Utils.build_nested_query('x' => { 'y' => { 'z' => '1' } }).
304
- must_equal 'x[y][z]=1'
305
- Rack::Utils.build_nested_query('x' => { 'y' => { 'z' => ['1'] } }).
306
- must_equal 'x[y][z][]=1'
307
- Rack::Utils.build_nested_query('x' => { 'y' => { 'z' => ['1', '2'] } }).
308
- must_equal 'x[y][z][]=1&x[y][z][]=2'
309
- Rack::Utils.build_nested_query('x' => { 'y' => [{ 'z' => '1' }] }).
310
- must_equal 'x[y][][z]=1'
311
- Rack::Utils.build_nested_query('x' => { 'y' => [{ 'z' => ['1'] }] }).
312
- must_equal 'x[y][][z][]=1'
313
- Rack::Utils.build_nested_query('x' => { 'y' => [{ 'z' => '1', 'w' => '2' }] }).
314
- must_equal 'x[y][][z]=1&x[y][][w]=2'
315
- Rack::Utils.build_nested_query('x' => { 'y' => [{ 'v' => { 'w' => '1' } }] }).
316
- must_equal 'x[y][][v][w]=1'
317
- Rack::Utils.build_nested_query('x' => { 'y' => [{ 'z' => '1', 'v' => { 'w' => '2' } }] }).
318
- must_equal 'x[y][][z]=1&x[y][][v][w]=2'
319
- Rack::Utils.build_nested_query('x' => { 'y' => [{ 'z' => '1' }, { 'z' => '2' }] }).
320
- must_equal 'x[y][][z]=1&x[y][][z]=2'
321
- Rack::Utils.build_nested_query('x' => { 'y' => [{ 'z' => '1', 'w' => 'a' }, { 'z' => '2', 'w' => '3' }] }).
322
- must_equal 'x[y][][z]=1&x[y][][w]=a&x[y][][z]=2&x[y][][w]=3'
323
- Rack::Utils.build_nested_query({"foo" => ["1", ["2"]]}).
324
- must_equal 'foo[]=1&foo[][]=2'
325
-
326
- lambda { Rack::Utils.build_nested_query("foo=bar") }.
327
- must_raise(ArgumentError).
328
- message.must_equal "value must be a Hash"
329
- end
330
-
331
- it 'performs the inverse function of #parse_nested_query' do
332
- [{"foo" => nil, "bar" => ""},
333
- {"foo" => "bar", "baz" => ""},
334
- {"foo" => ["1", "2"]},
335
- {"foo" => "bar", "baz" => ["1", "2", "3"]},
336
- {"foo" => ["bar"], "baz" => ["1", "2", "3"]},
337
- {"foo" => ["1", "2"]},
338
- {"foo" => "bar", "baz" => ["1", "2", "3"]},
339
- {"x" => {"y" => {"z" => "1"}}},
340
- {"x" => {"y" => {"z" => ["1"]}}},
341
- {"x" => {"y" => {"z" => ["1", "2"]}}},
342
- {"x" => {"y" => [{"z" => "1"}]}},
343
- {"x" => {"y" => [{"z" => ["1"]}]}},
344
- {"x" => {"y" => [{"z" => "1", "w" => "2"}]}},
345
- {"x" => {"y" => [{"v" => {"w" => "1"}}]}},
346
- {"x" => {"y" => [{"z" => "1", "v" => {"w" => "2"}}]}},
347
- {"x" => {"y" => [{"z" => "1"}, {"z" => "2"}]}},
348
- {"x" => {"y" => [{"z" => "1", "w" => "a"}, {"z" => "2", "w" => "3"}]}},
349
- {"foo" => ["1", ["2"]]},
350
- ].each { |params|
351
- qs = Rack::Utils.build_nested_query(params)
352
- Rack::Utils.parse_nested_query(qs).must_equal params
353
- }
354
-
355
- lambda { Rack::Utils.build_nested_query("foo=bar") }.
356
- must_raise(ArgumentError).
357
- message.must_equal "value must be a Hash"
358
- end
359
-
360
- it "parse query strings that have a non-existent value" do
361
- key = "post/2011/08/27/Deux-%22rat%C3%A9s%22-de-l-Universit"
362
- Rack::Utils.parse_query(key).must_equal Rack::Utils.unescape(key) => nil
363
- end
364
-
365
- it "build query strings without = with non-existent values" do
366
- key = "post/2011/08/27/Deux-%22rat%C3%A9s%22-de-l-Universit"
367
- key = Rack::Utils.unescape(key)
368
- Rack::Utils.build_query(key => nil).must_equal Rack::Utils.escape(key)
369
- end
370
-
371
- it "parse q-values" do
372
- # XXX handle accept-extension
373
- Rack::Utils.q_values("foo;q=0.5,bar,baz;q=0.9").must_equal [
374
- [ 'foo', 0.5 ],
375
- [ 'bar', 1.0 ],
376
- [ 'baz', 0.9 ]
377
- ]
378
- end
379
-
380
- it "select best quality match" do
381
- Rack::Utils.best_q_match("text/html", %w[text/html]).must_equal "text/html"
382
-
383
- # More specific matches are preferred
384
- Rack::Utils.best_q_match("text/*;q=0.5,text/html;q=1.0", %w[text/html]).must_equal "text/html"
385
-
386
- # Higher quality matches are preferred
387
- Rack::Utils.best_q_match("text/*;q=0.5,text/plain;q=1.0", %w[text/plain text/html]).must_equal "text/plain"
388
-
389
- # Respect requested content type
390
- Rack::Utils.best_q_match("application/json", %w[application/vnd.lotus-1-2-3 application/json]).must_equal "application/json"
391
-
392
- # All else equal, the available mimes are preferred in order
393
- Rack::Utils.best_q_match("text/*", %w[text/html text/plain]).must_equal "text/html"
394
- Rack::Utils.best_q_match("text/plain,text/html", %w[text/html text/plain]).must_equal "text/html"
395
-
396
- # When there are no matches, return nil:
397
- Rack::Utils.best_q_match("application/json", %w[text/html text/plain]).must_be_nil
398
- end
399
-
400
- it "escape html entities [&><'\"/]" do
401
- Rack::Utils.escape_html("foo").must_equal "foo"
402
- Rack::Utils.escape_html("f&o").must_equal "f&amp;o"
403
- Rack::Utils.escape_html("f<o").must_equal "f&lt;o"
404
- Rack::Utils.escape_html("f>o").must_equal "f&gt;o"
405
- Rack::Utils.escape_html("f'o").must_equal "f&#x27;o"
406
- Rack::Utils.escape_html('f"o').must_equal "f&quot;o"
407
- Rack::Utils.escape_html("f/o").must_equal "f&#x2F;o"
408
- Rack::Utils.escape_html("<foo></foo>").must_equal "&lt;foo&gt;&lt;&#x2F;foo&gt;"
409
- end
410
-
411
- it "escape html entities even on MRI when it's bugged" do
412
- test_escape = lambda do
413
- Rack::Utils.escape_html("\300<").must_equal "\300&lt;"
414
- end
415
-
416
- test_escape.must_raise ArgumentError
417
- end
418
-
419
- it "escape html entities in unicode strings" do
420
- # the following will cause warnings if the regex is poorly encoded:
421
- Rack::Utils.escape_html("☃").must_equal "☃"
422
- end
423
-
424
- it "figure out which encodings are acceptable" do
425
- helper = lambda do |a, b|
426
- Rack::Request.new(Rack::MockRequest.env_for("", "HTTP_ACCEPT_ENCODING" => a))
427
- Rack::Utils.select_best_encoding(a, b)
428
- end
429
-
430
- helper.call(%w(), [["x", 1]]).must_be_nil
431
- helper.call(%w(identity), [["identity", 0.0]]).must_be_nil
432
- helper.call(%w(identity), [["*", 0.0]]).must_be_nil
433
-
434
- helper.call(%w(identity), [["compress", 1.0], ["gzip", 1.0]]).must_equal "identity"
435
-
436
- helper.call(%w(compress gzip identity), [["compress", 1.0], ["gzip", 1.0]]).must_equal "compress"
437
- helper.call(%w(compress gzip identity), [["compress", 0.5], ["gzip", 1.0]]).must_equal "gzip"
438
-
439
- helper.call(%w(foo bar identity), []).must_equal "identity"
440
- helper.call(%w(foo bar identity), [["*", 1.0]]).must_equal "foo"
441
- helper.call(%w(foo bar identity), [["*", 1.0], ["foo", 0.9]]).must_equal "bar"
442
-
443
- helper.call(%w(foo bar identity), [["foo", 0], ["bar", 0]]).must_equal "identity"
444
- helper.call(%w(foo bar baz identity), [["*", 0], ["identity", 0.1]]).must_equal "identity"
445
- end
446
-
447
- it "should perform constant time string comparison" do
448
- Rack::Utils.secure_compare('a', 'a').must_equal true
449
- Rack::Utils.secure_compare('a', 'b').must_equal false
450
- end
451
-
452
- it "return status code for integer" do
453
- Rack::Utils.status_code(200).must_equal 200
454
- end
455
-
456
- it "return status code for string" do
457
- Rack::Utils.status_code("200").must_equal 200
458
- end
459
-
460
- it "return status code for symbol" do
461
- Rack::Utils.status_code(:ok).must_equal 200
462
- end
463
-
464
- it "return rfc2822 format from rfc2822 helper" do
465
- Rack::Utils.rfc2822(Time.at(0).gmtime).must_equal "Thu, 01 Jan 1970 00:00:00 -0000"
466
- end
467
-
468
- it "return rfc2109 format from rfc2109 helper" do
469
- Rack::Utils.rfc2109(Time.at(0).gmtime).must_equal "Thu, 01-Jan-1970 00:00:00 GMT"
470
- end
471
-
472
- it "clean directory traversal" do
473
- Rack::Utils.clean_path_info("/cgi/../cgi/test").must_equal "/cgi/test"
474
- Rack::Utils.clean_path_info(".").must_be_empty
475
- Rack::Utils.clean_path_info("test/..").must_be_empty
476
- end
477
-
478
- it "clean unsafe directory traversal to safe path" do
479
- Rack::Utils.clean_path_info("/../README.rdoc").must_equal "/README.rdoc"
480
- Rack::Utils.clean_path_info("../test/spec_utils.rb").must_equal "test/spec_utils.rb"
481
- end
482
-
483
- it "not clean directory traversal with encoded periods" do
484
- Rack::Utils.clean_path_info("/%2E%2E/README").must_equal "/%2E%2E/README"
485
- end
486
-
487
- it "clean slash only paths" do
488
- Rack::Utils.clean_path_info("/").must_equal "/"
489
- end
490
- end
491
-
492
- describe Rack::Utils, "cookies" do
493
- it "parses cookies" do
494
- env = Rack::MockRequest.env_for("", "HTTP_COOKIE" => "zoo=m")
495
- Rack::Utils.parse_cookies(env).must_equal({"zoo" => "m"})
496
-
497
- env = Rack::MockRequest.env_for("", "HTTP_COOKIE" => "foo=%")
498
- Rack::Utils.parse_cookies(env).must_equal({"foo" => "%"})
499
-
500
- env = Rack::MockRequest.env_for("", "HTTP_COOKIE" => "foo=bar;foo=car")
501
- Rack::Utils.parse_cookies(env).must_equal({"foo" => "bar"})
502
-
503
- env = Rack::MockRequest.env_for("", "HTTP_COOKIE" => "foo=bar;quux=h&m")
504
- Rack::Utils.parse_cookies(env).must_equal({"foo" => "bar", "quux" => "h&m"})
505
-
506
- env = Rack::MockRequest.env_for("", "HTTP_COOKIE" => "foo=bar").freeze
507
- Rack::Utils.parse_cookies(env).must_equal({"foo" => "bar"})
508
- end
509
-
510
- it "adds new cookies to nil header" do
511
- Rack::Utils.add_cookie_to_header(nil, 'name', 'value').must_equal 'name=value'
512
- end
513
-
514
- it "adds new cookies to blank header" do
515
- header = ''
516
- Rack::Utils.add_cookie_to_header(header, 'name', 'value').must_equal 'name=value'
517
- header.must_equal ''
518
- end
519
-
520
- it "adds new cookies to string header" do
521
- header = 'existing-cookie'
522
- Rack::Utils.add_cookie_to_header(header, 'name', 'value').must_equal "existing-cookie\nname=value"
523
- header.must_equal 'existing-cookie'
524
- end
525
-
526
- it "adds new cookies to array header" do
527
- header = %w[ existing-cookie ]
528
- Rack::Utils.add_cookie_to_header(header, 'name', 'value').must_equal "existing-cookie\nname=value"
529
- header.must_equal %w[ existing-cookie ]
530
- end
531
-
532
- it "adds new cookies to an unrecognized header" do
533
- lambda {
534
- Rack::Utils.add_cookie_to_header(Object.new, 'name', 'value')
535
- }.must_raise ArgumentError
536
- end
537
- end
538
-
539
- describe Rack::Utils, "byte_range" do
540
- it "ignore missing or syntactically invalid byte ranges" do
541
- Rack::Utils.byte_ranges({},500).must_be_nil
542
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "foobar"},500).must_be_nil
543
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "furlongs=123-456"},500).must_be_nil
544
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes="},500).must_be_nil
545
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=-"},500).must_be_nil
546
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=123,456"},500).must_be_nil
547
- # A range of non-positive length is syntactically invalid and ignored:
548
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=456-123"},500).must_be_nil
549
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=456-455"},500).must_be_nil
550
- end
551
-
552
- it "parse simple byte ranges" do
553
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=123-456"},500).must_equal [(123..456)]
554
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=123-"},500).must_equal [(123..499)]
555
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=-100"},500).must_equal [(400..499)]
556
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=0-0"},500).must_equal [(0..0)]
557
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=499-499"},500).must_equal [(499..499)]
558
- end
559
-
560
- it "parse several byte ranges" do
561
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=500-600,601-999"},1000).must_equal [(500..600),(601..999)]
562
- end
563
-
564
- it "truncate byte ranges" do
565
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=123-999"},500).must_equal [(123..499)]
566
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=600-999"},500).must_equal []
567
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=-999"},500).must_equal [(0..499)]
568
- end
569
-
570
- it "ignore unsatisfiable byte ranges" do
571
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=500-501"},500).must_equal []
572
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=500-"},500).must_equal []
573
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=999-"},500).must_equal []
574
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=-0"},500).must_equal []
575
- end
576
-
577
- it "handle byte ranges of empty files" do
578
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=123-456"},0).must_equal []
579
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=0-"},0).must_equal []
580
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=-100"},0).must_equal []
581
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=0-0"},0).must_equal []
582
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=-0"},0).must_equal []
583
- end
584
- end
585
-
586
- describe Rack::Utils::HeaderHash do
587
- it "retain header case" do
588
- h = Rack::Utils::HeaderHash.new("Content-MD5" => "d5ff4e2a0 ...")
589
- h['ETag'] = 'Boo!'
590
- h.to_hash.must_equal "Content-MD5" => "d5ff4e2a0 ...", "ETag" => 'Boo!'
591
- end
592
-
593
- it "check existence of keys case insensitively" do
594
- h = Rack::Utils::HeaderHash.new("Content-MD5" => "d5ff4e2a0 ...")
595
- h.must_include 'content-md5'
596
- h.wont_include 'ETag'
597
- end
598
-
599
- it "create deep HeaderHash copy on dup" do
600
- h1 = Rack::Utils::HeaderHash.new("Content-MD5" => "d5ff4e2a0 ...")
601
- h2 = h1.dup
602
-
603
- h1.must_include 'content-md5'
604
- h2.must_include 'content-md5'
605
-
606
- h2.delete("Content-MD5")
607
-
608
- h2.wont_include 'content-md5'
609
- h1.must_include 'content-md5'
610
- end
611
-
612
- it "merge case-insensitively" do
613
- h = Rack::Utils::HeaderHash.new("ETag" => 'HELLO', "content-length" => '123')
614
- merged = h.merge("Etag" => 'WORLD', 'Content-Length' => '321', "Foo" => 'BAR')
615
- merged.must_equal "Etag"=>'WORLD', "Content-Length"=>'321', "Foo"=>'BAR'
616
- end
617
-
618
- it "overwrite case insensitively and assume the new key's case" do
619
- h = Rack::Utils::HeaderHash.new("Foo-Bar" => "baz")
620
- h["foo-bar"] = "bizzle"
621
- h["FOO-BAR"].must_equal "bizzle"
622
- h.length.must_equal 1
623
- h.to_hash.must_equal "foo-bar" => "bizzle"
624
- end
625
-
626
- it "be converted to real Hash" do
627
- h = Rack::Utils::HeaderHash.new("foo" => "bar")
628
- h.to_hash.must_be_instance_of Hash
629
- end
630
-
631
- it "convert Array values to Strings when converting to Hash" do
632
- h = Rack::Utils::HeaderHash.new("foo" => ["bar", "baz"])
633
- h.to_hash.must_equal({ "foo" => "bar\nbaz" })
634
- end
635
-
636
- it "replace hashes correctly" do
637
- h = Rack::Utils::HeaderHash.new("Foo-Bar" => "baz")
638
- j = {"foo" => "bar"}
639
- h.replace(j)
640
- h["foo"].must_equal "bar"
641
- end
642
-
643
- it "be able to delete the given key case-sensitively" do
644
- h = Rack::Utils::HeaderHash.new("foo" => "bar")
645
- h.delete("foo")
646
- h["foo"].must_be_nil
647
- h["FOO"].must_be_nil
648
- end
649
-
650
- it "be able to delete the given key case-insensitively" do
651
- h = Rack::Utils::HeaderHash.new("foo" => "bar")
652
- h.delete("FOO")
653
- h["foo"].must_be_nil
654
- h["FOO"].must_be_nil
655
- end
656
-
657
- it "return the deleted value when #delete is called on an existing key" do
658
- h = Rack::Utils::HeaderHash.new("foo" => "bar")
659
- h.delete("Foo").must_equal "bar"
660
- end
661
-
662
- it "return nil when #delete is called on a non-existant key" do
663
- h = Rack::Utils::HeaderHash.new("foo" => "bar")
664
- h.delete("Hello").must_be_nil
665
- end
666
-
667
- it "avoid unnecessary object creation if possible" do
668
- a = Rack::Utils::HeaderHash.new("foo" => "bar")
669
- b = Rack::Utils::HeaderHash.new(a)
670
- b.object_id.must_equal a.object_id
671
- b.must_equal a
672
- end
673
-
674
- it "convert Array values to Strings when responding to #each" do
675
- h = Rack::Utils::HeaderHash.new("foo" => ["bar", "baz"])
676
- h.each do |k,v|
677
- k.must_equal "foo"
678
- v.must_equal "bar\nbaz"
679
- end
680
- end
681
-
682
- it "not create headers out of thin air" do
683
- h = Rack::Utils::HeaderHash.new
684
- h['foo']
685
- h['foo'].must_be_nil
686
- h.wont_include 'foo'
687
- end
688
- end
689
-
690
- describe Rack::Utils::Context do
691
- class ContextTest
692
- attr_reader :app
693
- def initialize app; @app=app; end
694
- def call env; context env; end
695
- def context env, app=@app; app.call(env); end
696
- end
697
- test_target1 = proc{|e| e.to_s+' world' }
698
- test_target2 = proc{|e| e.to_i+2 }
699
- test_target3 = proc{|e| nil }
700
- test_target4 = proc{|e| [200,{'Content-Type'=>'text/plain', 'Content-Length'=>'0'},['']] }
701
- test_app = ContextTest.new test_target4
702
-
703
- it "set context correctly" do
704
- test_app.app.must_equal test_target4
705
- c1 = Rack::Utils::Context.new(test_app, test_target1)
706
- c1.for.must_equal test_app
707
- c1.app.must_equal test_target1
708
- c2 = Rack::Utils::Context.new(test_app, test_target2)
709
- c2.for.must_equal test_app
710
- c2.app.must_equal test_target2
711
- end
712
-
713
- it "alter app on recontexting" do
714
- c1 = Rack::Utils::Context.new(test_app, test_target1)
715
- c2 = c1.recontext(test_target2)
716
- c2.for.must_equal test_app
717
- c2.app.must_equal test_target2
718
- c3 = c2.recontext(test_target3)
719
- c3.for.must_equal test_app
720
- c3.app.must_equal test_target3
721
- end
722
-
723
- it "run different apps" do
724
- c1 = Rack::Utils::Context.new test_app, test_target1
725
- c2 = c1.recontext test_target2
726
- c3 = c2.recontext test_target3
727
- c4 = c3.recontext test_target4
728
- a4 = Rack::Lint.new c4
729
- a5 = Rack::Lint.new test_app
730
- r1 = c1.call('hello')
731
- r1.must_equal 'hello world'
732
- r2 = c2.call(2)
733
- r2.must_equal 4
734
- r3 = c3.call(:misc_symbol)
735
- r3.must_be_nil
736
- r4 = Rack::MockRequest.new(a4).get('/')
737
- r4.status.must_equal 200
738
- r5 = Rack::MockRequest.new(a5).get('/')
739
- r5.status.must_equal 200
740
- r4.body.must_equal r5.body
741
- end
742
- end