rack 1.4.7 → 2.1.4

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rack might be problematic. Click here for more details.

Files changed (183) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +77 -0
  3. data/{COPYING → MIT-LICENSE} +4 -2
  4. data/README.rdoc +122 -456
  5. data/Rakefile +32 -31
  6. data/SPEC +119 -29
  7. data/bin/rackup +1 -0
  8. data/contrib/rack_logo.svg +164 -111
  9. data/example/lobster.ru +2 -0
  10. data/example/protectedlobster.rb +4 -2
  11. data/example/protectedlobster.ru +3 -1
  12. data/lib/rack/auth/abstract/handler.rb +7 -5
  13. data/lib/rack/auth/abstract/request.rb +8 -6
  14. data/lib/rack/auth/basic.rb +5 -2
  15. data/lib/rack/auth/digest/md5.rb +10 -8
  16. data/lib/rack/auth/digest/nonce.rb +6 -3
  17. data/lib/rack/auth/digest/params.rb +5 -4
  18. data/lib/rack/auth/digest/request.rb +4 -2
  19. data/lib/rack/body_proxy.rb +11 -9
  20. data/lib/rack/builder.rb +63 -20
  21. data/lib/rack/cascade.rb +10 -9
  22. data/lib/rack/chunked.rb +45 -11
  23. data/lib/rack/{commonlogger.rb → common_logger.rb} +24 -15
  24. data/lib/rack/{conditionalget.rb → conditional_get.rb} +20 -6
  25. data/lib/rack/config.rb +7 -0
  26. data/lib/rack/content_length.rb +12 -6
  27. data/lib/rack/content_type.rb +4 -2
  28. data/lib/rack/core_ext/regexp.rb +14 -0
  29. data/lib/rack/deflater.rb +73 -42
  30. data/lib/rack/directory.rb +77 -56
  31. data/lib/rack/etag.rb +25 -13
  32. data/lib/rack/events.rb +156 -0
  33. data/lib/rack/file.rb +4 -143
  34. data/lib/rack/files.rb +178 -0
  35. data/lib/rack/handler/cgi.rb +18 -17
  36. data/lib/rack/handler/fastcgi.rb +21 -17
  37. data/lib/rack/handler/lsws.rb +14 -12
  38. data/lib/rack/handler/scgi.rb +27 -21
  39. data/lib/rack/handler/thin.rb +19 -5
  40. data/lib/rack/handler/webrick.rb +66 -24
  41. data/lib/rack/handler.rb +29 -19
  42. data/lib/rack/head.rb +21 -14
  43. data/lib/rack/lint.rb +259 -65
  44. data/lib/rack/lobster.rb +17 -10
  45. data/lib/rack/lock.rb +19 -10
  46. data/lib/rack/logger.rb +4 -2
  47. data/lib/rack/media_type.rb +43 -0
  48. data/lib/rack/method_override.rb +52 -0
  49. data/lib/rack/mime.rb +43 -6
  50. data/lib/rack/mock.rb +109 -44
  51. data/lib/rack/multipart/generator.rb +11 -12
  52. data/lib/rack/multipart/parser.rb +302 -115
  53. data/lib/rack/multipart/uploaded_file.rb +4 -3
  54. data/lib/rack/multipart.rb +40 -9
  55. data/lib/rack/null_logger.rb +39 -0
  56. data/lib/rack/query_parser.rb +218 -0
  57. data/lib/rack/recursive.rb +14 -11
  58. data/lib/rack/reloader.rb +12 -5
  59. data/lib/rack/request.rb +484 -270
  60. data/lib/rack/response.rb +196 -77
  61. data/lib/rack/rewindable_input.rb +5 -14
  62. data/lib/rack/runtime.rb +13 -6
  63. data/lib/rack/sendfile.rb +44 -20
  64. data/lib/rack/server.rb +175 -61
  65. data/lib/rack/session/abstract/id.rb +276 -133
  66. data/lib/rack/session/cookie.rb +75 -40
  67. data/lib/rack/session/memcache.rb +4 -87
  68. data/lib/rack/session/pool.rb +24 -18
  69. data/lib/rack/show_exceptions.rb +392 -0
  70. data/lib/rack/{showstatus.rb → show_status.rb} +11 -9
  71. data/lib/rack/static.rb +65 -38
  72. data/lib/rack/tempfile_reaper.rb +24 -0
  73. data/lib/rack/urlmap.rb +40 -15
  74. data/lib/rack/utils.rb +316 -285
  75. data/lib/rack.rb +78 -23
  76. data/rack.gemspec +26 -19
  77. metadata +44 -209
  78. data/KNOWN-ISSUES +0 -30
  79. data/lib/rack/backports/uri/common_18.rb +0 -56
  80. data/lib/rack/backports/uri/common_192.rb +0 -52
  81. data/lib/rack/backports/uri/common_193.rb +0 -29
  82. data/lib/rack/handler/evented_mongrel.rb +0 -8
  83. data/lib/rack/handler/mongrel.rb +0 -100
  84. data/lib/rack/handler/swiftiplied_mongrel.rb +0 -8
  85. data/lib/rack/methodoverride.rb +0 -33
  86. data/lib/rack/nulllogger.rb +0 -18
  87. data/lib/rack/showexceptions.rb +0 -378
  88. data/test/builder/anything.rb +0 -5
  89. data/test/builder/comment.ru +0 -4
  90. data/test/builder/end.ru +0 -5
  91. data/test/builder/line.ru +0 -1
  92. data/test/builder/options.ru +0 -2
  93. data/test/cgi/assets/folder/test.js +0 -1
  94. data/test/cgi/assets/fonts/font.eot +0 -1
  95. data/test/cgi/assets/images/image.png +0 -1
  96. data/test/cgi/assets/index.html +0 -1
  97. data/test/cgi/assets/javascripts/app.js +0 -1
  98. data/test/cgi/assets/stylesheets/app.css +0 -1
  99. data/test/cgi/lighttpd.conf +0 -26
  100. data/test/cgi/lighttpd.errors +0 -1
  101. data/test/cgi/rackup_stub.rb +0 -6
  102. data/test/cgi/sample_rackup.ru +0 -5
  103. data/test/cgi/test +0 -9
  104. data/test/cgi/test+directory/test+file +0 -1
  105. data/test/cgi/test.fcgi +0 -8
  106. data/test/cgi/test.ru +0 -5
  107. data/test/gemloader.rb +0 -10
  108. data/test/multipart/bad_robots +0 -259
  109. data/test/multipart/binary +0 -0
  110. data/test/multipart/content_type_and_no_filename +0 -6
  111. data/test/multipart/empty +0 -10
  112. data/test/multipart/fail_16384_nofile +0 -814
  113. data/test/multipart/file1.txt +0 -1
  114. data/test/multipart/filename_and_modification_param +0 -7
  115. data/test/multipart/filename_with_escaped_quotes +0 -6
  116. data/test/multipart/filename_with_escaped_quotes_and_modification_param +0 -7
  117. data/test/multipart/filename_with_percent_escaped_quotes +0 -6
  118. data/test/multipart/filename_with_unescaped_percentages +0 -6
  119. data/test/multipart/filename_with_unescaped_percentages2 +0 -6
  120. data/test/multipart/filename_with_unescaped_percentages3 +0 -6
  121. data/test/multipart/filename_with_unescaped_quotes +0 -6
  122. data/test/multipart/ie +0 -6
  123. data/test/multipart/mixed_files +0 -21
  124. data/test/multipart/nested +0 -10
  125. data/test/multipart/none +0 -9
  126. data/test/multipart/semicolon +0 -6
  127. data/test/multipart/text +0 -15
  128. data/test/multipart/three_files_three_fields +0 -31
  129. data/test/multipart/webkit +0 -32
  130. data/test/rackup/config.ru +0 -31
  131. data/test/registering_handler/rack/handler/registering_myself.rb +0 -8
  132. data/test/spec_auth.rb +0 -57
  133. data/test/spec_auth_basic.rb +0 -81
  134. data/test/spec_auth_digest.rb +0 -259
  135. data/test/spec_body_proxy.rb +0 -69
  136. data/test/spec_builder.rb +0 -207
  137. data/test/spec_cascade.rb +0 -61
  138. data/test/spec_cgi.rb +0 -102
  139. data/test/spec_chunked.rb +0 -87
  140. data/test/spec_commonlogger.rb +0 -57
  141. data/test/spec_conditionalget.rb +0 -102
  142. data/test/spec_config.rb +0 -22
  143. data/test/spec_content_length.rb +0 -86
  144. data/test/spec_content_type.rb +0 -45
  145. data/test/spec_deflater.rb +0 -187
  146. data/test/spec_directory.rb +0 -88
  147. data/test/spec_etag.rb +0 -98
  148. data/test/spec_fastcgi.rb +0 -107
  149. data/test/spec_file.rb +0 -200
  150. data/test/spec_handler.rb +0 -59
  151. data/test/spec_head.rb +0 -48
  152. data/test/spec_lint.rb +0 -515
  153. data/test/spec_lobster.rb +0 -58
  154. data/test/spec_lock.rb +0 -167
  155. data/test/spec_logger.rb +0 -23
  156. data/test/spec_methodoverride.rb +0 -72
  157. data/test/spec_mock.rb +0 -269
  158. data/test/spec_mongrel.rb +0 -182
  159. data/test/spec_multipart.rb +0 -479
  160. data/test/spec_nulllogger.rb +0 -23
  161. data/test/spec_recursive.rb +0 -72
  162. data/test/spec_request.rb +0 -955
  163. data/test/spec_response.rb +0 -313
  164. data/test/spec_rewindable_input.rb +0 -118
  165. data/test/spec_runtime.rb +0 -49
  166. data/test/spec_sendfile.rb +0 -90
  167. data/test/spec_server.rb +0 -121
  168. data/test/spec_session_abstract_id.rb +0 -43
  169. data/test/spec_session_cookie.rb +0 -361
  170. data/test/spec_session_memcache.rb +0 -321
  171. data/test/spec_session_pool.rb +0 -209
  172. data/test/spec_showexceptions.rb +0 -92
  173. data/test/spec_showstatus.rb +0 -84
  174. data/test/spec_static.rb +0 -145
  175. data/test/spec_thin.rb +0 -86
  176. data/test/spec_urlmap.rb +0 -213
  177. data/test/spec_utils.rb +0 -554
  178. data/test/spec_webrick.rb +0 -143
  179. data/test/static/another/index.html +0 -1
  180. data/test/static/index.html +0 -1
  181. data/test/testrequest.rb +0 -78
  182. data/test/unregistered_handler/rack/handler/unregistered.rb +0 -7
  183. data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +0 -7
data/test/spec_utils.rb DELETED
@@ -1,554 +0,0 @@
1
- # -*- encoding: utf-8 -*-
2
- require 'rack/utils'
3
- require 'rack/mock'
4
- require 'timeout'
5
-
6
- describe Rack::Utils do
7
-
8
- # A helper method which checks
9
- # if certain query parameters
10
- # are equal.
11
- def equal_query_to(query)
12
- parts = query.split('&')
13
- lambda{|other| (parts & other.split('&')) == parts }
14
- end
15
-
16
- def kcodeu
17
- one8 = RUBY_VERSION.to_f < 1.9
18
- default_kcode, $KCODE = $KCODE, 'U' if one8
19
- yield
20
- ensure
21
- $KCODE = default_kcode if one8
22
- end
23
-
24
- should "round trip binary data" do
25
- r = [218, 0].pack 'CC'
26
- if defined?(::Encoding)
27
- z = Rack::Utils.unescape(Rack::Utils.escape(r), Encoding::BINARY)
28
- else
29
- z = Rack::Utils.unescape(Rack::Utils.escape(r))
30
- end
31
- r.should.equal z
32
- end
33
-
34
- should "escape correctly" do
35
- Rack::Utils.escape("fo<o>bar").should.equal "fo%3Co%3Ebar"
36
- Rack::Utils.escape("a space").should.equal "a+space"
37
- Rack::Utils.escape("q1!2\"'w$5&7/z8)?\\").
38
- should.equal "q1%212%22%27w%245%267%2Fz8%29%3F%5C"
39
- end
40
-
41
- should "escape correctly for multibyte characters" do
42
- matz_name = "\xE3\x81\xBE\xE3\x81\xA4\xE3\x82\x82\xE3\x81\xA8".unpack("a*")[0] # Matsumoto
43
- matz_name.force_encoding("UTF-8") if matz_name.respond_to? :force_encoding
44
- Rack::Utils.escape(matz_name).should.equal '%E3%81%BE%E3%81%A4%E3%82%82%E3%81%A8'
45
- matz_name_sep = "\xE3\x81\xBE\xE3\x81\xA4 \xE3\x82\x82\xE3\x81\xA8".unpack("a*")[0] # Matsu moto
46
- matz_name_sep.force_encoding("UTF-8") if matz_name_sep.respond_to? :force_encoding
47
- Rack::Utils.escape(matz_name_sep).should.equal '%E3%81%BE%E3%81%A4+%E3%82%82%E3%81%A8'
48
- end
49
-
50
- if RUBY_VERSION[/^\d+\.\d+/] == '1.8'
51
- should "escape correctly for multibyte characters if $KCODE is set to 'U'" do
52
- kcodeu do
53
- matz_name = "\xE3\x81\xBE\xE3\x81\xA4\xE3\x82\x82\xE3\x81\xA8".unpack("a*")[0] # Matsumoto
54
- matz_name.force_encoding("UTF-8") if matz_name.respond_to? :force_encoding
55
- Rack::Utils.escape(matz_name).should.equal '%E3%81%BE%E3%81%A4%E3%82%82%E3%81%A8'
56
- matz_name_sep = "\xE3\x81\xBE\xE3\x81\xA4 \xE3\x82\x82\xE3\x81\xA8".unpack("a*")[0] # Matsu moto
57
- matz_name_sep.force_encoding("UTF-8") if matz_name_sep.respond_to? :force_encoding
58
- Rack::Utils.escape(matz_name_sep).should.equal '%E3%81%BE%E3%81%A4+%E3%82%82%E3%81%A8'
59
- end
60
- end
61
-
62
- should "unescape multibyte characters correctly if $KCODE is set to 'U'" do
63
- kcodeu do
64
- Rack::Utils.unescape('%E3%81%BE%E3%81%A4+%E3%82%82%E3%81%A8').should.equal(
65
- "\xE3\x81\xBE\xE3\x81\xA4 \xE3\x82\x82\xE3\x81\xA8".unpack("a*")[0])
66
- end
67
- end
68
- end
69
-
70
- should "escape objects that responds to to_s" do
71
- kcodeu do
72
- Rack::Utils.escape(:id).should.equal "id"
73
- end
74
- end
75
-
76
- if "".respond_to?(:encode)
77
- should "escape non-UTF8 strings" do
78
- Rack::Utils.escape("ø".encode("ISO-8859-1")).should.equal "%F8"
79
- end
80
- end
81
-
82
- should "not hang on escaping long strings that end in % (http://redmine.ruby-lang.org/issues/5149)" do
83
- lambda {
84
- timeout(1) do
85
- lambda {
86
- URI.decode_www_form_component "A string that causes catastrophic backtracking as it gets longer %"
87
- }.should.raise(ArgumentError)
88
- end
89
- }.should.not.raise(Timeout::Error)
90
- end
91
-
92
- should "escape path spaces with %20" do
93
- Rack::Utils.escape_path("foo bar").should.equal "foo%20bar"
94
- end
95
-
96
- should "unescape correctly" do
97
- Rack::Utils.unescape("fo%3Co%3Ebar").should.equal "fo<o>bar"
98
- Rack::Utils.unescape("a+space").should.equal "a space"
99
- Rack::Utils.unescape("a%20space").should.equal "a space"
100
- Rack::Utils.unescape("q1%212%22%27w%245%267%2Fz8%29%3F%5C").
101
- should.equal "q1!2\"'w$5&7/z8)?\\"
102
- end
103
-
104
- should "parse query strings correctly" do
105
- Rack::Utils.parse_query("foo=bar").
106
- should.equal "foo" => "bar"
107
- Rack::Utils.parse_query("foo=\"bar\"").
108
- should.equal "foo" => "\"bar\""
109
- Rack::Utils.parse_query("foo=bar&foo=quux").
110
- should.equal "foo" => ["bar", "quux"]
111
- Rack::Utils.parse_query("foo=1&bar=2").
112
- should.equal "foo" => "1", "bar" => "2"
113
- Rack::Utils.parse_query("my+weird+field=q1%212%22%27w%245%267%2Fz8%29%3F").
114
- should.equal "my weird field" => "q1!2\"'w$5&7/z8)?"
115
- Rack::Utils.parse_query("foo%3Dbaz=bar").should.equal "foo=baz" => "bar"
116
- Rack::Utils.parse_query("=").should.equal "" => ""
117
- Rack::Utils.parse_query("=value").should.equal "" => "value"
118
- Rack::Utils.parse_query("key=").should.equal "key" => ""
119
- Rack::Utils.parse_query("&key&").should.equal "key" => nil
120
- Rack::Utils.parse_query(";key;", ";,").should.equal "key" => nil
121
- Rack::Utils.parse_query(",key,", ";,").should.equal "key" => nil
122
- Rack::Utils.parse_query(";foo=bar,;", ";,").should.equal "foo" => "bar"
123
- Rack::Utils.parse_query(",foo=bar;,", ";,").should.equal "foo" => "bar"
124
- end
125
-
126
- should "raise an exception if the params are too deep" do
127
- len = Rack::Utils.param_depth_limit
128
-
129
- lambda {
130
- Rack::Utils.parse_nested_query("foo#{"[a]" * len}=bar")
131
- }.should.raise(RangeError)
132
-
133
- lambda {
134
- Rack::Utils.parse_nested_query("foo#{"[a]" * (len - 1)}=bar")
135
- }.should.not.raise
136
- end
137
-
138
- should "parse nested query strings correctly" do
139
- Rack::Utils.parse_nested_query("foo").
140
- should.equal "foo" => nil
141
- Rack::Utils.parse_nested_query("foo=").
142
- should.equal "foo" => ""
143
- Rack::Utils.parse_nested_query("foo=bar").
144
- should.equal "foo" => "bar"
145
- Rack::Utils.parse_nested_query("foo=\"bar\"").
146
- should.equal "foo" => "\"bar\""
147
-
148
- Rack::Utils.parse_nested_query("foo=bar&foo=quux").
149
- should.equal "foo" => "quux"
150
- Rack::Utils.parse_nested_query("foo&foo=").
151
- should.equal "foo" => ""
152
- Rack::Utils.parse_nested_query("foo=1&bar=2").
153
- should.equal "foo" => "1", "bar" => "2"
154
- Rack::Utils.parse_nested_query("&foo=1&&bar=2").
155
- should.equal "foo" => "1", "bar" => "2"
156
- Rack::Utils.parse_nested_query("foo&bar=").
157
- should.equal "foo" => nil, "bar" => ""
158
- Rack::Utils.parse_nested_query("foo=bar&baz=").
159
- should.equal "foo" => "bar", "baz" => ""
160
- Rack::Utils.parse_nested_query("my+weird+field=q1%212%22%27w%245%267%2Fz8%29%3F").
161
- should.equal "my weird field" => "q1!2\"'w$5&7/z8)?"
162
-
163
- Rack::Utils.parse_nested_query("a=b&pid%3D1234=1023").
164
- should.equal "pid=1234" => "1023", "a" => "b"
165
-
166
- Rack::Utils.parse_nested_query("foo[]").
167
- should.equal "foo" => [nil]
168
- Rack::Utils.parse_nested_query("foo[]=").
169
- should.equal "foo" => [""]
170
- Rack::Utils.parse_nested_query("foo[]=bar").
171
- should.equal "foo" => ["bar"]
172
-
173
- Rack::Utils.parse_nested_query("foo[]=1&foo[]=2").
174
- should.equal "foo" => ["1", "2"]
175
- Rack::Utils.parse_nested_query("foo=bar&baz[]=1&baz[]=2&baz[]=3").
176
- should.equal "foo" => "bar", "baz" => ["1", "2", "3"]
177
- Rack::Utils.parse_nested_query("foo[]=bar&baz[]=1&baz[]=2&baz[]=3").
178
- should.equal "foo" => ["bar"], "baz" => ["1", "2", "3"]
179
-
180
- Rack::Utils.parse_nested_query("x[y][z]=1").
181
- should.equal "x" => {"y" => {"z" => "1"}}
182
- Rack::Utils.parse_nested_query("x[y][z][]=1").
183
- should.equal "x" => {"y" => {"z" => ["1"]}}
184
- Rack::Utils.parse_nested_query("x[y][z]=1&x[y][z]=2").
185
- should.equal "x" => {"y" => {"z" => "2"}}
186
- Rack::Utils.parse_nested_query("x[y][z][]=1&x[y][z][]=2").
187
- should.equal "x" => {"y" => {"z" => ["1", "2"]}}
188
-
189
- Rack::Utils.parse_nested_query("x[y][][z]=1").
190
- should.equal "x" => {"y" => [{"z" => "1"}]}
191
- Rack::Utils.parse_nested_query("x[y][][z][]=1").
192
- should.equal "x" => {"y" => [{"z" => ["1"]}]}
193
- Rack::Utils.parse_nested_query("x[y][][z]=1&x[y][][w]=2").
194
- should.equal "x" => {"y" => [{"z" => "1", "w" => "2"}]}
195
-
196
- Rack::Utils.parse_nested_query("x[y][][v][w]=1").
197
- should.equal "x" => {"y" => [{"v" => {"w" => "1"}}]}
198
- Rack::Utils.parse_nested_query("x[y][][z]=1&x[y][][v][w]=2").
199
- should.equal "x" => {"y" => [{"z" => "1", "v" => {"w" => "2"}}]}
200
-
201
- Rack::Utils.parse_nested_query("x[y][][z]=1&x[y][][z]=2").
202
- should.equal "x" => {"y" => [{"z" => "1"}, {"z" => "2"}]}
203
- Rack::Utils.parse_nested_query("x[y][][z]=1&x[y][][w]=a&x[y][][z]=2&x[y][][w]=3").
204
- should.equal "x" => {"y" => [{"z" => "1", "w" => "a"}, {"z" => "2", "w" => "3"}]}
205
-
206
- lambda { Rack::Utils.parse_nested_query("x[y]=1&x[y]z=2") }.
207
- should.raise(TypeError).
208
- message.should.equal "expected Hash (got String) for param `y'"
209
-
210
- lambda { Rack::Utils.parse_nested_query("x[y]=1&x[]=1") }.
211
- should.raise(TypeError).
212
- message.should.match(/expected Array \(got [^)]*\) for param `x'/)
213
-
214
- lambda { Rack::Utils.parse_nested_query("x[y]=1&x[y][][w]=2") }.
215
- should.raise(TypeError).
216
- message.should.equal "expected Array (got String) for param `y'"
217
- end
218
-
219
- should "build query strings correctly" do
220
- Rack::Utils.build_query("foo" => "bar").should.be equal_query_to("foo=bar")
221
- Rack::Utils.build_query("foo" => ["bar", "quux"]).
222
- should.be equal_query_to("foo=bar&foo=quux")
223
- Rack::Utils.build_query("foo" => "1", "bar" => "2").
224
- should.be equal_query_to("foo=1&bar=2")
225
- Rack::Utils.build_query("my weird field" => "q1!2\"'w$5&7/z8)?").
226
- should.be equal_query_to("my+weird+field=q1%212%22%27w%245%267%2Fz8%29%3F")
227
- end
228
-
229
- should "build nested query strings correctly" do
230
- Rack::Utils.build_nested_query("foo" => nil).should.equal "foo"
231
- Rack::Utils.build_nested_query("foo" => "").should.equal "foo="
232
- Rack::Utils.build_nested_query("foo" => "bar").should.equal "foo=bar"
233
-
234
- Rack::Utils.build_nested_query("foo" => "1", "bar" => "2").
235
- should.be equal_query_to("foo=1&bar=2")
236
- Rack::Utils.build_nested_query("my weird field" => "q1!2\"'w$5&7/z8)?").
237
- should.be equal_query_to("my+weird+field=q1%212%22%27w%245%267%2Fz8%29%3F")
238
-
239
- Rack::Utils.build_nested_query("foo" => [nil]).
240
- should.equal "foo[]"
241
- Rack::Utils.build_nested_query("foo" => [""]).
242
- should.equal "foo[]="
243
- Rack::Utils.build_nested_query("foo" => ["bar"]).
244
- should.equal "foo[]=bar"
245
-
246
- # The ordering of the output query string is unpredictable with 1.8's
247
- # unordered hash. Test that build_nested_query performs the inverse
248
- # function of parse_nested_query.
249
- [{"foo" => nil, "bar" => ""},
250
- {"foo" => "bar", "baz" => ""},
251
- {"foo" => ["1", "2"]},
252
- {"foo" => "bar", "baz" => ["1", "2", "3"]},
253
- {"foo" => ["bar"], "baz" => ["1", "2", "3"]},
254
- {"foo" => ["1", "2"]},
255
- {"foo" => "bar", "baz" => ["1", "2", "3"]},
256
- {"x" => {"y" => {"z" => "1"}}},
257
- {"x" => {"y" => {"z" => ["1"]}}},
258
- {"x" => {"y" => {"z" => ["1", "2"]}}},
259
- {"x" => {"y" => [{"z" => "1"}]}},
260
- {"x" => {"y" => [{"z" => ["1"]}]}},
261
- {"x" => {"y" => [{"z" => "1", "w" => "2"}]}},
262
- {"x" => {"y" => [{"v" => {"w" => "1"}}]}},
263
- {"x" => {"y" => [{"z" => "1", "v" => {"w" => "2"}}]}},
264
- {"x" => {"y" => [{"z" => "1"}, {"z" => "2"}]}},
265
- {"x" => {"y" => [{"z" => "1", "w" => "a"}, {"z" => "2", "w" => "3"}]}}
266
- ].each { |params|
267
- qs = Rack::Utils.build_nested_query(params)
268
- Rack::Utils.parse_nested_query(qs).should.equal params
269
- }
270
-
271
- lambda { Rack::Utils.build_nested_query("foo=bar") }.
272
- should.raise(ArgumentError).
273
- message.should.equal "value must be a Hash"
274
- end
275
-
276
- should "parse query strings that have a non-existent value" do
277
- key = "post/2011/08/27/Deux-%22rat%C3%A9s%22-de-l-Universit"
278
- Rack::Utils.parse_query(key).should.equal Rack::Utils.unescape(key) => nil
279
- end
280
-
281
- should "build query strings without = with non-existent values" do
282
- key = "post/2011/08/27/Deux-%22rat%C3%A9s%22-de-l-Universit"
283
- key = Rack::Utils.unescape(key)
284
- Rack::Utils.build_query(key => nil).should.equal Rack::Utils.escape(key)
285
- end
286
-
287
- should "escape html entities [&><'\"/]" do
288
- Rack::Utils.escape_html("foo").should.equal "foo"
289
- Rack::Utils.escape_html("f&o").should.equal "f&amp;o"
290
- Rack::Utils.escape_html("f<o").should.equal "f&lt;o"
291
- Rack::Utils.escape_html("f>o").should.equal "f&gt;o"
292
- Rack::Utils.escape_html("f'o").should.equal "f&#x27;o"
293
- Rack::Utils.escape_html('f"o').should.equal "f&quot;o"
294
- Rack::Utils.escape_html("f/o").should.equal "f&#x2F;o"
295
- Rack::Utils.escape_html("<foo></foo>").should.equal "&lt;foo&gt;&lt;&#x2F;foo&gt;"
296
- end
297
-
298
- should "escape html entities even on MRI when it's bugged" do
299
- test_escape = lambda do
300
- kcodeu do
301
- Rack::Utils.escape_html("\300<").should.equal "\300&lt;"
302
- end
303
- end
304
-
305
- if RUBY_VERSION.to_f < 1.9
306
- test_escape.call
307
- else
308
- test_escape.should.raise(ArgumentError)
309
- end
310
- end
311
-
312
- if "".respond_to?(:encode)
313
- should "escape html entities in unicode strings" do
314
- # the following will cause warnings if the regex is poorly encoded:
315
- Rack::Utils.escape_html("☃").should.equal "☃"
316
- end
317
- end
318
-
319
- should "figure out which encodings are acceptable" do
320
- helper = lambda do |a, b|
321
- Rack::Request.new(Rack::MockRequest.env_for("", "HTTP_ACCEPT_ENCODING" => a))
322
- Rack::Utils.select_best_encoding(a, b)
323
- end
324
-
325
- helper.call(%w(), [["x", 1]]).should.equal(nil)
326
- helper.call(%w(identity), [["identity", 0.0]]).should.equal(nil)
327
- helper.call(%w(identity), [["*", 0.0]]).should.equal(nil)
328
-
329
- helper.call(%w(identity), [["compress", 1.0], ["gzip", 1.0]]).should.equal("identity")
330
-
331
- helper.call(%w(compress gzip identity), [["compress", 1.0], ["gzip", 1.0]]).should.equal("compress")
332
- helper.call(%w(compress gzip identity), [["compress", 0.5], ["gzip", 1.0]]).should.equal("gzip")
333
-
334
- helper.call(%w(foo bar identity), []).should.equal("identity")
335
- helper.call(%w(foo bar identity), [["*", 1.0]]).should.equal("foo")
336
- helper.call(%w(foo bar identity), [["*", 1.0], ["foo", 0.9]]).should.equal("bar")
337
-
338
- helper.call(%w(foo bar identity), [["foo", 0], ["bar", 0]]).should.equal("identity")
339
- helper.call(%w(foo bar baz identity), [["*", 0], ["identity", 0.1]]).should.equal("identity")
340
- end
341
-
342
- should "return the bytesize of String" do
343
- Rack::Utils.bytesize("FOO\xE2\x82\xAC").should.equal 6
344
- end
345
-
346
- should "should perform constant time string comparison" do
347
- Rack::Utils.secure_compare('a', 'a').should.equal true
348
- Rack::Utils.secure_compare('a', 'b').should.equal false
349
- end
350
-
351
- should "return status code for integer" do
352
- Rack::Utils.status_code(200).should.equal 200
353
- end
354
-
355
- should "return status code for string" do
356
- Rack::Utils.status_code("200").should.equal 200
357
- end
358
-
359
- should "return status code for symbol" do
360
- Rack::Utils.status_code(:ok).should.equal 200
361
- end
362
- end
363
-
364
- describe Rack::Utils, "byte_range" do
365
- should "ignore missing or syntactically invalid byte ranges" do
366
- Rack::Utils.byte_ranges({},500).should.equal nil
367
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "foobar"},500).should.equal nil
368
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "furlongs=123-456"},500).should.equal nil
369
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes="},500).should.equal nil
370
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=-"},500).should.equal nil
371
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=123,456"},500).should.equal nil
372
- # A range of non-positive length is syntactically invalid and ignored:
373
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=456-123"},500).should.equal nil
374
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=456-455"},500).should.equal nil
375
- end
376
-
377
- should "parse simple byte ranges" do
378
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=123-456"},500).should.equal [(123..456)]
379
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=123-"},500).should.equal [(123..499)]
380
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=-100"},500).should.equal [(400..499)]
381
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=0-0"},500).should.equal [(0..0)]
382
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=499-499"},500).should.equal [(499..499)]
383
- end
384
-
385
- should "parse several byte ranges" do
386
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=500-600,601-999"},1000).should.equal [(500..600),(601..999)]
387
- end
388
-
389
- should "truncate byte ranges" do
390
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=123-999"},500).should.equal [(123..499)]
391
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=600-999"},500).should.equal []
392
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=-999"},500).should.equal [(0..499)]
393
- end
394
-
395
- should "ignore unsatisfiable byte ranges" do
396
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=500-501"},500).should.equal []
397
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=500-"},500).should.equal []
398
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=999-"},500).should.equal []
399
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=-0"},500).should.equal []
400
- end
401
-
402
- should "handle byte ranges of empty files" do
403
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=123-456"},0).should.equal []
404
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=0-"},0).should.equal []
405
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=-100"},0).should.equal []
406
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=0-0"},0).should.equal []
407
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=-0"},0).should.equal []
408
- end
409
- end
410
-
411
- describe Rack::Utils::HeaderHash do
412
- should "retain header case" do
413
- h = Rack::Utils::HeaderHash.new("Content-MD5" => "d5ff4e2a0 ...")
414
- h['ETag'] = 'Boo!'
415
- h.to_hash.should.equal "Content-MD5" => "d5ff4e2a0 ...", "ETag" => 'Boo!'
416
- end
417
-
418
- should "check existence of keys case insensitively" do
419
- h = Rack::Utils::HeaderHash.new("Content-MD5" => "d5ff4e2a0 ...")
420
- h.should.include 'content-md5'
421
- h.should.not.include 'ETag'
422
- end
423
-
424
- should "merge case-insensitively" do
425
- h = Rack::Utils::HeaderHash.new("ETag" => 'HELLO', "content-length" => '123')
426
- merged = h.merge("Etag" => 'WORLD', 'Content-Length' => '321', "Foo" => 'BAR')
427
- merged.should.equal "Etag"=>'WORLD', "Content-Length"=>'321', "Foo"=>'BAR'
428
- end
429
-
430
- should "overwrite case insensitively and assume the new key's case" do
431
- h = Rack::Utils::HeaderHash.new("Foo-Bar" => "baz")
432
- h["foo-bar"] = "bizzle"
433
- h["FOO-BAR"].should.equal "bizzle"
434
- h.length.should.equal 1
435
- h.to_hash.should.equal "foo-bar" => "bizzle"
436
- end
437
-
438
- should "be converted to real Hash" do
439
- h = Rack::Utils::HeaderHash.new("foo" => "bar")
440
- h.to_hash.should.be.instance_of Hash
441
- end
442
-
443
- should "convert Array values to Strings when converting to Hash" do
444
- h = Rack::Utils::HeaderHash.new("foo" => ["bar", "baz"])
445
- h.to_hash.should.equal({ "foo" => "bar\nbaz" })
446
- end
447
-
448
- should "replace hashes correctly" do
449
- h = Rack::Utils::HeaderHash.new("Foo-Bar" => "baz")
450
- j = {"foo" => "bar"}
451
- h.replace(j)
452
- h["foo"].should.equal "bar"
453
- end
454
-
455
- should "be able to delete the given key case-sensitively" do
456
- h = Rack::Utils::HeaderHash.new("foo" => "bar")
457
- h.delete("foo")
458
- h["foo"].should.be.nil
459
- h["FOO"].should.be.nil
460
- end
461
-
462
- should "be able to delete the given key case-insensitively" do
463
- h = Rack::Utils::HeaderHash.new("foo" => "bar")
464
- h.delete("FOO")
465
- h["foo"].should.be.nil
466
- h["FOO"].should.be.nil
467
- end
468
-
469
- should "return the deleted value when #delete is called on an existing key" do
470
- h = Rack::Utils::HeaderHash.new("foo" => "bar")
471
- h.delete("Foo").should.equal("bar")
472
- end
473
-
474
- should "return nil when #delete is called on a non-existant key" do
475
- h = Rack::Utils::HeaderHash.new("foo" => "bar")
476
- h.delete("Hello").should.be.nil
477
- end
478
-
479
- should "avoid unnecessary object creation if possible" do
480
- a = Rack::Utils::HeaderHash.new("foo" => "bar")
481
- b = Rack::Utils::HeaderHash.new(a)
482
- b.object_id.should.equal(a.object_id)
483
- b.should.equal(a)
484
- end
485
-
486
- should "convert Array values to Strings when responding to #each" do
487
- h = Rack::Utils::HeaderHash.new("foo" => ["bar", "baz"])
488
- h.each do |k,v|
489
- k.should.equal("foo")
490
- v.should.equal("bar\nbaz")
491
- end
492
- end
493
-
494
- should "not create headers out of thin air" do
495
- h = Rack::Utils::HeaderHash.new
496
- h['foo']
497
- h['foo'].should.be.nil
498
- h.should.not.include 'foo'
499
- end
500
- end
501
-
502
- describe Rack::Utils::Context do
503
- class ContextTest
504
- attr_reader :app
505
- def initialize app; @app=app; end
506
- def call env; context env; end
507
- def context env, app=@app; app.call(env); end
508
- end
509
- test_target1 = proc{|e| e.to_s+' world' }
510
- test_target2 = proc{|e| e.to_i+2 }
511
- test_target3 = proc{|e| nil }
512
- test_target4 = proc{|e| [200,{'Content-Type'=>'text/plain', 'Content-Length'=>'0'},['']] }
513
- test_app = ContextTest.new test_target4
514
-
515
- should "set context correctly" do
516
- test_app.app.should.equal test_target4
517
- c1 = Rack::Utils::Context.new(test_app, test_target1)
518
- c1.for.should.equal test_app
519
- c1.app.should.equal test_target1
520
- c2 = Rack::Utils::Context.new(test_app, test_target2)
521
- c2.for.should.equal test_app
522
- c2.app.should.equal test_target2
523
- end
524
-
525
- should "alter app on recontexting" do
526
- c1 = Rack::Utils::Context.new(test_app, test_target1)
527
- c2 = c1.recontext(test_target2)
528
- c2.for.should.equal test_app
529
- c2.app.should.equal test_target2
530
- c3 = c2.recontext(test_target3)
531
- c3.for.should.equal test_app
532
- c3.app.should.equal test_target3
533
- end
534
-
535
- should "run different apps" do
536
- c1 = Rack::Utils::Context.new test_app, test_target1
537
- c2 = c1.recontext test_target2
538
- c3 = c2.recontext test_target3
539
- c4 = c3.recontext test_target4
540
- a4 = Rack::Lint.new c4
541
- a5 = Rack::Lint.new test_app
542
- r1 = c1.call('hello')
543
- r1.should.equal 'hello world'
544
- r2 = c2.call(2)
545
- r2.should.equal 4
546
- r3 = c3.call(:misc_symbol)
547
- r3.should.be.nil
548
- r4 = Rack::MockRequest.new(a4).get('/')
549
- r4.status.should.equal 200
550
- r5 = Rack::MockRequest.new(a5).get('/')
551
- r5.status.should.equal 200
552
- r4.body.should.equal r5.body
553
- end
554
- end