rack 1.6.13 → 2.2.3

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 (191) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +694 -0
  3. data/CONTRIBUTING.md +136 -0
  4. data/{COPYING → MIT-LICENSE} +4 -2
  5. data/README.rdoc +157 -163
  6. data/Rakefile +38 -32
  7. data/{SPEC → SPEC.rdoc} +41 -13
  8. data/bin/rackup +1 -0
  9. data/contrib/rack_logo.svg +164 -111
  10. data/example/lobster.ru +2 -0
  11. data/example/protectedlobster.rb +4 -2
  12. data/example/protectedlobster.ru +3 -1
  13. data/lib/rack/auth/abstract/handler.rb +3 -1
  14. data/lib/rack/auth/abstract/request.rb +6 -2
  15. data/lib/rack/auth/basic.rb +7 -4
  16. data/lib/rack/auth/digest/md5.rb +13 -11
  17. data/lib/rack/auth/digest/nonce.rb +6 -3
  18. data/lib/rack/auth/digest/params.rb +5 -4
  19. data/lib/rack/auth/digest/request.rb +6 -4
  20. data/lib/rack/body_proxy.rb +21 -15
  21. data/lib/rack/builder.rb +119 -26
  22. data/lib/rack/cascade.rb +28 -12
  23. data/lib/rack/chunked.rb +70 -22
  24. data/lib/rack/common_logger.rb +80 -0
  25. data/lib/rack/{conditionalget.rb → conditional_get.rb} +20 -16
  26. data/lib/rack/config.rb +2 -0
  27. data/lib/rack/content_length.rb +9 -8
  28. data/lib/rack/content_type.rb +5 -4
  29. data/lib/rack/core_ext/regexp.rb +14 -0
  30. data/lib/rack/deflater.rb +60 -70
  31. data/lib/rack/directory.rb +117 -85
  32. data/lib/rack/etag.rb +9 -7
  33. data/lib/rack/events.rb +153 -0
  34. data/lib/rack/file.rb +4 -149
  35. data/lib/rack/files.rb +218 -0
  36. data/lib/rack/handler/cgi.rb +17 -19
  37. data/lib/rack/handler/fastcgi.rb +17 -18
  38. data/lib/rack/handler/lsws.rb +14 -14
  39. data/lib/rack/handler/scgi.rb +22 -21
  40. data/lib/rack/handler/thin.rb +6 -3
  41. data/lib/rack/handler/webrick.rb +39 -32
  42. data/lib/rack/handler.rb +9 -26
  43. data/lib/rack/head.rb +16 -18
  44. data/lib/rack/lint.rb +110 -64
  45. data/lib/rack/lobster.rb +10 -10
  46. data/lib/rack/lock.rb +17 -11
  47. data/lib/rack/logger.rb +4 -2
  48. data/lib/rack/media_type.rb +43 -0
  49. data/lib/rack/{methodoverride.rb → method_override.rb} +10 -8
  50. data/lib/rack/mime.rb +27 -6
  51. data/lib/rack/mock.rb +124 -65
  52. data/lib/rack/multipart/generator.rb +20 -16
  53. data/lib/rack/multipart/parser.rb +273 -162
  54. data/lib/rack/multipart/uploaded_file.rb +15 -8
  55. data/lib/rack/multipart.rb +39 -8
  56. data/lib/rack/{nulllogger.rb → null_logger.rb} +3 -1
  57. data/lib/rack/query_parser.rb +217 -0
  58. data/lib/rack/recursive.rb +11 -9
  59. data/lib/rack/reloader.rb +8 -4
  60. data/lib/rack/request.rb +553 -305
  61. data/lib/rack/response.rb +244 -88
  62. data/lib/rack/rewindable_input.rb +5 -15
  63. data/lib/rack/runtime.rb +12 -18
  64. data/lib/rack/sendfile.rb +17 -15
  65. data/lib/rack/server.rb +125 -47
  66. data/lib/rack/session/abstract/id.rb +141 -93
  67. data/lib/rack/session/cookie.rb +35 -29
  68. data/lib/rack/session/memcache.rb +4 -93
  69. data/lib/rack/session/pool.rb +13 -11
  70. data/lib/rack/show_exceptions.rb +390 -0
  71. data/lib/rack/{showstatus.rb → show_status.rb} +12 -12
  72. data/lib/rack/static.rb +48 -11
  73. data/lib/rack/tempfile_reaper.rb +3 -3
  74. data/lib/rack/urlmap.rb +26 -19
  75. data/lib/rack/utils.rb +212 -294
  76. data/lib/rack/version.rb +29 -0
  77. data/lib/rack.rb +76 -33
  78. data/rack.gemspec +43 -30
  79. metadata +65 -187
  80. data/HISTORY.md +0 -375
  81. data/KNOWN-ISSUES +0 -44
  82. data/lib/rack/backports/uri/common_18.rb +0 -56
  83. data/lib/rack/backports/uri/common_192.rb +0 -52
  84. data/lib/rack/backports/uri/common_193.rb +0 -29
  85. data/lib/rack/commonlogger.rb +0 -72
  86. data/lib/rack/handler/evented_mongrel.rb +0 -8
  87. data/lib/rack/handler/mongrel.rb +0 -106
  88. data/lib/rack/handler/swiftiplied_mongrel.rb +0 -8
  89. data/lib/rack/showexceptions.rb +0 -387
  90. data/lib/rack/utils/okjson.rb +0 -600
  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 -8
  108. data/test/cgi/test.ru +0 -5
  109. data/test/gemloader.rb +0 -10
  110. data/test/multipart/bad_robots +0 -259
  111. data/test/multipart/binary +0 -0
  112. data/test/multipart/content_type_and_no_filename +0 -6
  113. data/test/multipart/empty +0 -10
  114. data/test/multipart/fail_16384_nofile +0 -814
  115. data/test/multipart/file1.txt +0 -1
  116. data/test/multipart/filename_and_modification_param +0 -7
  117. data/test/multipart/filename_and_no_name +0 -6
  118. data/test/multipart/filename_with_escaped_quotes +0 -6
  119. data/test/multipart/filename_with_escaped_quotes_and_modification_param +0 -7
  120. data/test/multipart/filename_with_null_byte +0 -7
  121. data/test/multipart/filename_with_percent_escaped_quotes +0 -6
  122. data/test/multipart/filename_with_unescaped_percentages +0 -6
  123. data/test/multipart/filename_with_unescaped_percentages2 +0 -6
  124. data/test/multipart/filename_with_unescaped_percentages3 +0 -6
  125. data/test/multipart/filename_with_unescaped_quotes +0 -6
  126. data/test/multipart/ie +0 -6
  127. data/test/multipart/invalid_character +0 -6
  128. data/test/multipart/mixed_files +0 -21
  129. data/test/multipart/nested +0 -10
  130. data/test/multipart/none +0 -9
  131. data/test/multipart/semicolon +0 -6
  132. data/test/multipart/text +0 -15
  133. data/test/multipart/three_files_three_fields +0 -31
  134. data/test/multipart/webkit +0 -32
  135. data/test/rackup/config.ru +0 -31
  136. data/test/registering_handler/rack/handler/registering_myself.rb +0 -8
  137. data/test/spec_auth_basic.rb +0 -81
  138. data/test/spec_auth_digest.rb +0 -259
  139. data/test/spec_body_proxy.rb +0 -85
  140. data/test/spec_builder.rb +0 -223
  141. data/test/spec_cascade.rb +0 -61
  142. data/test/spec_cgi.rb +0 -102
  143. data/test/spec_chunked.rb +0 -101
  144. data/test/spec_commonlogger.rb +0 -93
  145. data/test/spec_conditionalget.rb +0 -102
  146. data/test/spec_config.rb +0 -22
  147. data/test/spec_content_length.rb +0 -85
  148. data/test/spec_content_type.rb +0 -45
  149. data/test/spec_deflater.rb +0 -339
  150. data/test/spec_directory.rb +0 -88
  151. data/test/spec_etag.rb +0 -107
  152. data/test/spec_fastcgi.rb +0 -107
  153. data/test/spec_file.rb +0 -221
  154. data/test/spec_handler.rb +0 -72
  155. data/test/spec_head.rb +0 -45
  156. data/test/spec_lint.rb +0 -550
  157. data/test/spec_lobster.rb +0 -58
  158. data/test/spec_lock.rb +0 -164
  159. data/test/spec_logger.rb +0 -23
  160. data/test/spec_methodoverride.rb +0 -111
  161. data/test/spec_mime.rb +0 -51
  162. data/test/spec_mock.rb +0 -297
  163. data/test/spec_mongrel.rb +0 -182
  164. data/test/spec_multipart.rb +0 -600
  165. data/test/spec_nulllogger.rb +0 -20
  166. data/test/spec_recursive.rb +0 -72
  167. data/test/spec_request.rb +0 -1232
  168. data/test/spec_response.rb +0 -407
  169. data/test/spec_rewindable_input.rb +0 -118
  170. data/test/spec_runtime.rb +0 -49
  171. data/test/spec_sendfile.rb +0 -130
  172. data/test/spec_server.rb +0 -167
  173. data/test/spec_session_abstract_id.rb +0 -53
  174. data/test/spec_session_cookie.rb +0 -410
  175. data/test/spec_session_memcache.rb +0 -358
  176. data/test/spec_session_persisted_secure_secure_session_hash.rb +0 -73
  177. data/test/spec_session_pool.rb +0 -246
  178. data/test/spec_showexceptions.rb +0 -98
  179. data/test/spec_showstatus.rb +0 -103
  180. data/test/spec_static.rb +0 -145
  181. data/test/spec_tempfile_reaper.rb +0 -63
  182. data/test/spec_thin.rb +0 -91
  183. data/test/spec_urlmap.rb +0 -236
  184. data/test/spec_utils.rb +0 -647
  185. data/test/spec_version.rb +0 -17
  186. data/test/spec_webrick.rb +0 -184
  187. data/test/static/another/index.html +0 -1
  188. data/test/static/index.html +0 -1
  189. data/test/testrequest.rb +0 -78
  190. data/test/unregistered_handler/rack/handler/unregistered.rb +0 -7
  191. data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +0 -7
data/test/spec_utils.rb DELETED
@@ -1,647 +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 "not create infinite loops with cycle structures" do
127
- ex = { "foo" => nil }
128
- ex["foo"] = ex
129
-
130
- params = Rack::Utils::KeySpaceConstrainedParams.new
131
- params['foo'] = params
132
- lambda {
133
- params.to_params_hash.to_s.should.equal ex.to_s
134
- }.should.not.raise
135
- end
136
-
137
- should "raise an exception if the params are too deep" do
138
- len = Rack::Utils.param_depth_limit
139
-
140
- lambda {
141
- Rack::Utils.parse_nested_query("foo#{"[a]" * len}=bar")
142
- }.should.raise(RangeError)
143
-
144
- lambda {
145
- Rack::Utils.parse_nested_query("foo#{"[a]" * (len - 1)}=bar")
146
- }.should.not.raise
147
- end
148
-
149
- should "parse nested query strings correctly" do
150
- Rack::Utils.parse_nested_query("foo").
151
- should.equal "foo" => nil
152
- Rack::Utils.parse_nested_query("foo=").
153
- should.equal "foo" => ""
154
- Rack::Utils.parse_nested_query("foo=bar").
155
- should.equal "foo" => "bar"
156
- Rack::Utils.parse_nested_query("foo=\"bar\"").
157
- should.equal "foo" => "\"bar\""
158
-
159
- Rack::Utils.parse_nested_query("foo=bar&foo=quux").
160
- should.equal "foo" => "quux"
161
- Rack::Utils.parse_nested_query("foo&foo=").
162
- should.equal "foo" => ""
163
- Rack::Utils.parse_nested_query("foo=1&bar=2").
164
- should.equal "foo" => "1", "bar" => "2"
165
- Rack::Utils.parse_nested_query("&foo=1&&bar=2").
166
- should.equal "foo" => "1", "bar" => "2"
167
- Rack::Utils.parse_nested_query("foo&bar=").
168
- should.equal "foo" => nil, "bar" => ""
169
- Rack::Utils.parse_nested_query("foo=bar&baz=").
170
- should.equal "foo" => "bar", "baz" => ""
171
- Rack::Utils.parse_nested_query("my+weird+field=q1%212%22%27w%245%267%2Fz8%29%3F").
172
- should.equal "my weird field" => "q1!2\"'w$5&7/z8)?"
173
-
174
- Rack::Utils.parse_nested_query("a=b&pid%3D1234=1023").
175
- should.equal "pid=1234" => "1023", "a" => "b"
176
-
177
- Rack::Utils.parse_nested_query("foo[]").
178
- should.equal "foo" => [nil]
179
- Rack::Utils.parse_nested_query("foo[]=").
180
- should.equal "foo" => [""]
181
- Rack::Utils.parse_nested_query("foo[]=bar").
182
- should.equal "foo" => ["bar"]
183
- Rack::Utils.parse_nested_query("foo[]=bar&foo").
184
- should.equal "foo" => nil
185
- Rack::Utils.parse_nested_query("foo[]=bar&foo[").
186
- should.equal "foo" => ["bar"], "foo[" => nil
187
- Rack::Utils.parse_nested_query("foo[]=bar&foo[=baz").
188
- should.equal "foo" => ["bar"], "foo[" => "baz"
189
- Rack::Utils.parse_nested_query("foo[]=bar&foo[]").
190
- should.equal "foo" => ["bar", nil]
191
- Rack::Utils.parse_nested_query("foo[]=bar&foo[]=").
192
- should.equal "foo" => ["bar", ""]
193
-
194
- Rack::Utils.parse_nested_query("foo[]=1&foo[]=2").
195
- should.equal "foo" => ["1", "2"]
196
- Rack::Utils.parse_nested_query("foo=bar&baz[]=1&baz[]=2&baz[]=3").
197
- should.equal "foo" => "bar", "baz" => ["1", "2", "3"]
198
- Rack::Utils.parse_nested_query("foo[]=bar&baz[]=1&baz[]=2&baz[]=3").
199
- should.equal "foo" => ["bar"], "baz" => ["1", "2", "3"]
200
-
201
- Rack::Utils.parse_nested_query("x[y][z]=1").
202
- should.equal "x" => {"y" => {"z" => "1"}}
203
- Rack::Utils.parse_nested_query("x[y][z][]=1").
204
- should.equal "x" => {"y" => {"z" => ["1"]}}
205
- Rack::Utils.parse_nested_query("x[y][z]=1&x[y][z]=2").
206
- should.equal "x" => {"y" => {"z" => "2"}}
207
- Rack::Utils.parse_nested_query("x[y][z][]=1&x[y][z][]=2").
208
- should.equal "x" => {"y" => {"z" => ["1", "2"]}}
209
-
210
- Rack::Utils.parse_nested_query("x[y][][z]=1").
211
- should.equal "x" => {"y" => [{"z" => "1"}]}
212
- Rack::Utils.parse_nested_query("x[y][][z][]=1").
213
- should.equal "x" => {"y" => [{"z" => ["1"]}]}
214
- Rack::Utils.parse_nested_query("x[y][][z]=1&x[y][][w]=2").
215
- should.equal "x" => {"y" => [{"z" => "1", "w" => "2"}]}
216
-
217
- Rack::Utils.parse_nested_query("x[y][][v][w]=1").
218
- should.equal "x" => {"y" => [{"v" => {"w" => "1"}}]}
219
- Rack::Utils.parse_nested_query("x[y][][z]=1&x[y][][v][w]=2").
220
- should.equal "x" => {"y" => [{"z" => "1", "v" => {"w" => "2"}}]}
221
-
222
- Rack::Utils.parse_nested_query("x[y][][z]=1&x[y][][z]=2").
223
- should.equal "x" => {"y" => [{"z" => "1"}, {"z" => "2"}]}
224
- Rack::Utils.parse_nested_query("x[y][][z]=1&x[y][][w]=a&x[y][][z]=2&x[y][][w]=3").
225
- should.equal "x" => {"y" => [{"z" => "1", "w" => "a"}, {"z" => "2", "w" => "3"}]}
226
-
227
- lambda { Rack::Utils.parse_nested_query("x[y]=1&x[y]z=2") }.
228
- should.raise(Rack::Utils::ParameterTypeError).
229
- message.should.equal "expected Hash (got String) for param `y'"
230
-
231
- lambda { Rack::Utils.parse_nested_query("x[y]=1&x[]=1") }.
232
- should.raise(Rack::Utils::ParameterTypeError).
233
- message.should.match(/expected Array \(got [^)]*\) for param `x'/)
234
-
235
- lambda { Rack::Utils.parse_nested_query("x[y]=1&x[y][][w]=2") }.
236
- should.raise(Rack::Utils::ParameterTypeError).
237
- message.should.equal "expected Array (got String) for param `y'"
238
-
239
- if RUBY_VERSION.to_f > 1.9
240
- lambda { Rack::Utils.parse_nested_query("foo%81E=1") }.
241
- should.raise(Rack::Utils::InvalidParameterError).
242
- message.should.equal "invalid byte sequence in UTF-8"
243
- end
244
- end
245
-
246
- should "build query strings correctly" do
247
- Rack::Utils.build_query("foo" => "bar").should.be equal_query_to("foo=bar")
248
- Rack::Utils.build_query("foo" => ["bar", "quux"]).
249
- should.be equal_query_to("foo=bar&foo=quux")
250
- Rack::Utils.build_query("foo" => "1", "bar" => "2").
251
- should.be equal_query_to("foo=1&bar=2")
252
- Rack::Utils.build_query("my weird field" => "q1!2\"'w$5&7/z8)?").
253
- should.be equal_query_to("my+weird+field=q1%212%22%27w%245%267%2Fz8%29%3F")
254
- end
255
-
256
- should "build nested query strings correctly" do
257
- Rack::Utils.build_nested_query("foo" => nil).should.equal "foo"
258
- Rack::Utils.build_nested_query("foo" => "").should.equal "foo="
259
- Rack::Utils.build_nested_query("foo" => "bar").should.equal "foo=bar"
260
-
261
- Rack::Utils.build_nested_query("foo" => "1", "bar" => "2").
262
- should.be equal_query_to("foo=1&bar=2")
263
- Rack::Utils.build_nested_query("foo" => 1, "bar" => 2).
264
- should.be equal_query_to("foo=1&bar=2")
265
- Rack::Utils.build_nested_query("my weird field" => "q1!2\"'w$5&7/z8)?").
266
- should.be equal_query_to("my+weird+field=q1%212%22%27w%245%267%2Fz8%29%3F")
267
-
268
- Rack::Utils.build_nested_query("foo" => [nil]).
269
- should.equal "foo[]"
270
- Rack::Utils.build_nested_query("foo" => [""]).
271
- should.equal "foo[]="
272
- Rack::Utils.build_nested_query("foo" => ["bar"]).
273
- should.equal "foo[]=bar"
274
- Rack::Utils.build_nested_query('foo' => []).
275
- should.equal ''
276
- Rack::Utils.build_nested_query('foo' => {}).
277
- should.equal ''
278
- Rack::Utils.build_nested_query('foo' => 'bar', 'baz' => []).
279
- should.equal 'foo=bar'
280
- Rack::Utils.build_nested_query('foo' => 'bar', 'baz' => {}).
281
- should.equal 'foo=bar'
282
-
283
- # The ordering of the output query string is unpredictable with 1.8's
284
- # unordered hash. Test that build_nested_query performs the inverse
285
- # function of parse_nested_query.
286
- [{"foo" => nil, "bar" => ""},
287
- {"foo" => "bar", "baz" => ""},
288
- {"foo" => ["1", "2"]},
289
- {"foo" => "bar", "baz" => ["1", "2", "3"]},
290
- {"foo" => ["bar"], "baz" => ["1", "2", "3"]},
291
- {"foo" => ["1", "2"]},
292
- {"foo" => "bar", "baz" => ["1", "2", "3"]},
293
- {"x" => {"y" => {"z" => "1"}}},
294
- {"x" => {"y" => {"z" => ["1"]}}},
295
- {"x" => {"y" => {"z" => ["1", "2"]}}},
296
- {"x" => {"y" => [{"z" => "1"}]}},
297
- {"x" => {"y" => [{"z" => ["1"]}]}},
298
- {"x" => {"y" => [{"z" => "1", "w" => "2"}]}},
299
- {"x" => {"y" => [{"v" => {"w" => "1"}}]}},
300
- {"x" => {"y" => [{"z" => "1", "v" => {"w" => "2"}}]}},
301
- {"x" => {"y" => [{"z" => "1"}, {"z" => "2"}]}},
302
- {"x" => {"y" => [{"z" => "1", "w" => "a"}, {"z" => "2", "w" => "3"}]}}
303
- ].each { |params|
304
- qs = Rack::Utils.build_nested_query(params)
305
- Rack::Utils.parse_nested_query(qs).should.equal params
306
- }
307
-
308
- lambda { Rack::Utils.build_nested_query("foo=bar") }.
309
- should.raise(ArgumentError).
310
- message.should.equal "value must be a Hash"
311
- end
312
-
313
- should "parse query strings that have a non-existent value" do
314
- key = "post/2011/08/27/Deux-%22rat%C3%A9s%22-de-l-Universit"
315
- Rack::Utils.parse_query(key).should.equal Rack::Utils.unescape(key) => nil
316
- end
317
-
318
- should "build query strings without = with non-existent values" do
319
- key = "post/2011/08/27/Deux-%22rat%C3%A9s%22-de-l-Universit"
320
- key = Rack::Utils.unescape(key)
321
- Rack::Utils.build_query(key => nil).should.equal Rack::Utils.escape(key)
322
- end
323
-
324
- should "parse q-values" do
325
- # XXX handle accept-extension
326
- Rack::Utils.q_values("foo;q=0.5,bar,baz;q=0.9").should.equal [
327
- [ 'foo', 0.5 ],
328
- [ 'bar', 1.0 ],
329
- [ 'baz', 0.9 ]
330
- ]
331
- end
332
-
333
- should "select best quality match" do
334
- Rack::Utils.best_q_match("text/html", %w[text/html]).should.equal "text/html"
335
-
336
- # More specific matches are preferred
337
- Rack::Utils.best_q_match("text/*;q=0.5,text/html;q=1.0", %w[text/html]).should.equal "text/html"
338
-
339
- # Higher quality matches are preferred
340
- Rack::Utils.best_q_match("text/*;q=0.5,text/plain;q=1.0", %w[text/plain text/html]).should.equal "text/plain"
341
-
342
- # Respect requested content type
343
- Rack::Utils.best_q_match("application/json", %w[application/vnd.lotus-1-2-3 application/json]).should.equal "application/json"
344
-
345
- # All else equal, the available mimes are preferred in order
346
- Rack::Utils.best_q_match("text/*", %w[text/html text/plain]).should.equal "text/html"
347
- Rack::Utils.best_q_match("text/plain,text/html", %w[text/html text/plain]).should.equal "text/html"
348
-
349
- # When there are no matches, return nil:
350
- Rack::Utils.best_q_match("application/json", %w[text/html text/plain]).should.equal nil
351
- end
352
-
353
- should "escape html entities [&><'\"/]" do
354
- Rack::Utils.escape_html("foo").should.equal "foo"
355
- Rack::Utils.escape_html("f&o").should.equal "f&amp;o"
356
- Rack::Utils.escape_html("f<o").should.equal "f&lt;o"
357
- Rack::Utils.escape_html("f>o").should.equal "f&gt;o"
358
- Rack::Utils.escape_html("f'o").should.equal "f&#x27;o"
359
- Rack::Utils.escape_html('f"o').should.equal "f&quot;o"
360
- Rack::Utils.escape_html("f/o").should.equal "f&#x2F;o"
361
- Rack::Utils.escape_html("<foo></foo>").should.equal "&lt;foo&gt;&lt;&#x2F;foo&gt;"
362
- end
363
-
364
- should "escape html entities even on MRI when it's bugged" do
365
- test_escape = lambda do
366
- kcodeu do
367
- Rack::Utils.escape_html("\300<").should.equal "\300&lt;"
368
- end
369
- end
370
-
371
- if RUBY_VERSION.to_f < 1.9
372
- test_escape.call
373
- else
374
- test_escape.should.raise(ArgumentError)
375
- end
376
- end
377
-
378
- if "".respond_to?(:encode)
379
- should "escape html entities in unicode strings" do
380
- # the following will cause warnings if the regex is poorly encoded:
381
- Rack::Utils.escape_html("☃").should.equal "☃"
382
- end
383
- end
384
-
385
- should "figure out which encodings are acceptable" do
386
- helper = lambda do |a, b|
387
- Rack::Request.new(Rack::MockRequest.env_for("", "HTTP_ACCEPT_ENCODING" => a))
388
- Rack::Utils.select_best_encoding(a, b)
389
- end
390
-
391
- helper.call(%w(), [["x", 1]]).should.equal(nil)
392
- helper.call(%w(identity), [["identity", 0.0]]).should.equal(nil)
393
- helper.call(%w(identity), [["*", 0.0]]).should.equal(nil)
394
-
395
- helper.call(%w(identity), [["compress", 1.0], ["gzip", 1.0]]).should.equal("identity")
396
-
397
- helper.call(%w(compress gzip identity), [["compress", 1.0], ["gzip", 1.0]]).should.equal("compress")
398
- helper.call(%w(compress gzip identity), [["compress", 0.5], ["gzip", 1.0]]).should.equal("gzip")
399
-
400
- helper.call(%w(foo bar identity), []).should.equal("identity")
401
- helper.call(%w(foo bar identity), [["*", 1.0]]).should.equal("foo")
402
- helper.call(%w(foo bar identity), [["*", 1.0], ["foo", 0.9]]).should.equal("bar")
403
-
404
- helper.call(%w(foo bar identity), [["foo", 0], ["bar", 0]]).should.equal("identity")
405
- helper.call(%w(foo bar baz identity), [["*", 0], ["identity", 0.1]]).should.equal("identity")
406
- end
407
-
408
- should "return the bytesize of String" do
409
- Rack::Utils.bytesize("FOO\xE2\x82\xAC").should.equal 6
410
- end
411
-
412
- should "should perform constant time string comparison" do
413
- Rack::Utils.secure_compare('a', 'a').should.equal true
414
- Rack::Utils.secure_compare('a', 'b').should.equal false
415
- end
416
-
417
- should "return status code for integer" do
418
- Rack::Utils.status_code(200).should.equal 200
419
- end
420
-
421
- should "return status code for string" do
422
- Rack::Utils.status_code("200").should.equal 200
423
- end
424
-
425
- should "return status code for symbol" do
426
- Rack::Utils.status_code(:ok).should.equal 200
427
- end
428
-
429
- should "return rfc2822 format from rfc2822 helper" do
430
- Rack::Utils.rfc2822(Time.at(0).gmtime).should == "Thu, 01 Jan 1970 00:00:00 -0000"
431
- end
432
-
433
- should "return rfc2109 format from rfc2109 helper" do
434
- Rack::Utils.rfc2109(Time.at(0).gmtime).should == "Thu, 01-Jan-1970 00:00:00 GMT"
435
- end
436
-
437
- should "clean directory traversal" do
438
- Rack::Utils.clean_path_info("/cgi/../cgi/test").should.equal "/cgi/test"
439
- Rack::Utils.clean_path_info(".").should.empty
440
- Rack::Utils.clean_path_info("test/..").should.empty
441
- end
442
-
443
- should "clean unsafe directory traversal to safe path" do
444
- Rack::Utils.clean_path_info("/../README.rdoc").should.equal "/README.rdoc"
445
- Rack::Utils.clean_path_info("../test/spec_utils.rb").should.equal "test/spec_utils.rb"
446
- end
447
-
448
- should "not clean directory traversal with encoded periods" do
449
- Rack::Utils.clean_path_info("/%2E%2E/README").should.equal "/%2E%2E/README"
450
- end
451
-
452
- should "clean slash only paths" do
453
- Rack::Utils.clean_path_info("/").should.equal "/"
454
- end
455
- end
456
-
457
- describe Rack::Utils, "byte_range" do
458
- should "ignore missing or syntactically invalid byte ranges" do
459
- Rack::Utils.byte_ranges({},500).should.equal nil
460
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "foobar"},500).should.equal nil
461
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "furlongs=123-456"},500).should.equal nil
462
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes="},500).should.equal nil
463
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=-"},500).should.equal nil
464
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=123,456"},500).should.equal nil
465
- # A range of non-positive length is syntactically invalid and ignored:
466
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=456-123"},500).should.equal nil
467
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=456-455"},500).should.equal nil
468
- end
469
-
470
- should "parse simple byte ranges" do
471
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=123-456"},500).should.equal [(123..456)]
472
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=123-"},500).should.equal [(123..499)]
473
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=-100"},500).should.equal [(400..499)]
474
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=0-0"},500).should.equal [(0..0)]
475
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=499-499"},500).should.equal [(499..499)]
476
- end
477
-
478
- should "parse several byte ranges" do
479
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=500-600,601-999"},1000).should.equal [(500..600),(601..999)]
480
- end
481
-
482
- should "truncate byte ranges" do
483
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=123-999"},500).should.equal [(123..499)]
484
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=600-999"},500).should.equal []
485
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=-999"},500).should.equal [(0..499)]
486
- end
487
-
488
- should "ignore unsatisfiable byte ranges" do
489
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=500-501"},500).should.equal []
490
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=500-"},500).should.equal []
491
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=999-"},500).should.equal []
492
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=-0"},500).should.equal []
493
- end
494
-
495
- should "handle byte ranges of empty files" do
496
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=123-456"},0).should.equal []
497
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=0-"},0).should.equal []
498
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=-100"},0).should.equal []
499
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=0-0"},0).should.equal []
500
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=-0"},0).should.equal []
501
- end
502
- end
503
-
504
- describe Rack::Utils::HeaderHash do
505
- should "retain header case" do
506
- h = Rack::Utils::HeaderHash.new("Content-MD5" => "d5ff4e2a0 ...")
507
- h['ETag'] = 'Boo!'
508
- h.to_hash.should.equal "Content-MD5" => "d5ff4e2a0 ...", "ETag" => 'Boo!'
509
- end
510
-
511
- should "check existence of keys case insensitively" do
512
- h = Rack::Utils::HeaderHash.new("Content-MD5" => "d5ff4e2a0 ...")
513
- h.should.include 'content-md5'
514
- h.should.not.include 'ETag'
515
- end
516
-
517
- should "merge case-insensitively" do
518
- h = Rack::Utils::HeaderHash.new("ETag" => 'HELLO', "content-length" => '123')
519
- merged = h.merge("Etag" => 'WORLD', 'Content-Length' => '321', "Foo" => 'BAR')
520
- merged.should.equal "Etag"=>'WORLD', "Content-Length"=>'321', "Foo"=>'BAR'
521
- end
522
-
523
- should "overwrite case insensitively and assume the new key's case" do
524
- h = Rack::Utils::HeaderHash.new("Foo-Bar" => "baz")
525
- h["foo-bar"] = "bizzle"
526
- h["FOO-BAR"].should.equal "bizzle"
527
- h.length.should.equal 1
528
- h.to_hash.should.equal "foo-bar" => "bizzle"
529
- end
530
-
531
- should "be converted to real Hash" do
532
- h = Rack::Utils::HeaderHash.new("foo" => "bar")
533
- h.to_hash.should.be.instance_of Hash
534
- end
535
-
536
- should "convert Array values to Strings when converting to Hash" do
537
- h = Rack::Utils::HeaderHash.new("foo" => ["bar", "baz"])
538
- h.to_hash.should.equal({ "foo" => "bar\nbaz" })
539
- end
540
-
541
- should "replace hashes correctly" do
542
- h = Rack::Utils::HeaderHash.new("Foo-Bar" => "baz")
543
- j = {"foo" => "bar"}
544
- h.replace(j)
545
- h["foo"].should.equal "bar"
546
- end
547
-
548
- should "be able to delete the given key case-sensitively" do
549
- h = Rack::Utils::HeaderHash.new("foo" => "bar")
550
- h.delete("foo")
551
- h["foo"].should.be.nil
552
- h["FOO"].should.be.nil
553
- end
554
-
555
- should "be able to delete the given key case-insensitively" do
556
- h = Rack::Utils::HeaderHash.new("foo" => "bar")
557
- h.delete("FOO")
558
- h["foo"].should.be.nil
559
- h["FOO"].should.be.nil
560
- end
561
-
562
- should "return the deleted value when #delete is called on an existing key" do
563
- h = Rack::Utils::HeaderHash.new("foo" => "bar")
564
- h.delete("Foo").should.equal("bar")
565
- end
566
-
567
- should "return nil when #delete is called on a non-existant key" do
568
- h = Rack::Utils::HeaderHash.new("foo" => "bar")
569
- h.delete("Hello").should.be.nil
570
- end
571
-
572
- should "avoid unnecessary object creation if possible" do
573
- a = Rack::Utils::HeaderHash.new("foo" => "bar")
574
- b = Rack::Utils::HeaderHash.new(a)
575
- b.object_id.should.equal(a.object_id)
576
- b.should.equal(a)
577
- end
578
-
579
- should "convert Array values to Strings when responding to #each" do
580
- h = Rack::Utils::HeaderHash.new("foo" => ["bar", "baz"])
581
- h.each do |k,v|
582
- k.should.equal("foo")
583
- v.should.equal("bar\nbaz")
584
- end
585
- end
586
-
587
- should "not create headers out of thin air" do
588
- h = Rack::Utils::HeaderHash.new
589
- h['foo']
590
- h['foo'].should.be.nil
591
- h.should.not.include 'foo'
592
- end
593
- end
594
-
595
- describe Rack::Utils::Context do
596
- class ContextTest
597
- attr_reader :app
598
- def initialize app; @app=app; end
599
- def call env; context env; end
600
- def context env, app=@app; app.call(env); end
601
- end
602
- test_target1 = proc{|e| e.to_s+' world' }
603
- test_target2 = proc{|e| e.to_i+2 }
604
- test_target3 = proc{|e| nil }
605
- test_target4 = proc{|e| [200,{'Content-Type'=>'text/plain', 'Content-Length'=>'0'},['']] }
606
- test_app = ContextTest.new test_target4
607
-
608
- should "set context correctly" do
609
- test_app.app.should.equal test_target4
610
- c1 = Rack::Utils::Context.new(test_app, test_target1)
611
- c1.for.should.equal test_app
612
- c1.app.should.equal test_target1
613
- c2 = Rack::Utils::Context.new(test_app, test_target2)
614
- c2.for.should.equal test_app
615
- c2.app.should.equal test_target2
616
- end
617
-
618
- should "alter app on recontexting" do
619
- c1 = Rack::Utils::Context.new(test_app, test_target1)
620
- c2 = c1.recontext(test_target2)
621
- c2.for.should.equal test_app
622
- c2.app.should.equal test_target2
623
- c3 = c2.recontext(test_target3)
624
- c3.for.should.equal test_app
625
- c3.app.should.equal test_target3
626
- end
627
-
628
- should "run different apps" do
629
- c1 = Rack::Utils::Context.new test_app, test_target1
630
- c2 = c1.recontext test_target2
631
- c3 = c2.recontext test_target3
632
- c4 = c3.recontext test_target4
633
- a4 = Rack::Lint.new c4
634
- a5 = Rack::Lint.new test_app
635
- r1 = c1.call('hello')
636
- r1.should.equal 'hello world'
637
- r2 = c2.call(2)
638
- r2.should.equal 4
639
- r3 = c3.call(:misc_symbol)
640
- r3.should.be.nil
641
- r4 = Rack::MockRequest.new(a4).get('/')
642
- r4.status.should.equal 200
643
- r5 = Rack::MockRequest.new(a5).get('/')
644
- r5.status.should.equal 200
645
- r4.body.should.equal r5.body
646
- end
647
- end
data/test/spec_version.rb DELETED
@@ -1,17 +0,0 @@
1
- # -*- encoding: utf-8 -*-
2
- require 'rack'
3
-
4
- describe Rack do
5
- describe 'version' do
6
- it 'defaults to a hard-coded api version' do
7
- Rack.version.should.equal("1.3")
8
- end
9
- end
10
- describe 'release' do
11
- it 'matches version in .gemspec' do
12
- gemspec_path = File.join(File.dirname(File.expand_path(__FILE__)), '../rack.gemspec')
13
- gemspec = Gem::Specification.load(gemspec_path)
14
- Rack.release.split('.').take(2).should.equal gemspec.version.to_s.split('.').take(2)
15
- end
16
- end
17
- end