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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +808 -0
- data/CONTRIBUTING.md +142 -0
- data/{COPYING → MIT-LICENSE} +4 -2
- data/README.md +293 -0
- data/SPEC.rdoc +340 -0
- data/lib/rack/auth/abstract/handler.rb +6 -2
- data/lib/rack/auth/abstract/request.rb +4 -2
- data/lib/rack/auth/basic.rb +7 -4
- data/lib/rack/auth/digest/md5.rb +1 -129
- data/lib/rack/auth/digest/nonce.rb +1 -51
- data/lib/rack/auth/digest/params.rb +1 -52
- data/lib/rack/auth/digest/request.rb +1 -41
- data/lib/rack/auth/digest.rb +256 -0
- data/lib/rack/body_proxy.rb +18 -15
- data/lib/rack/builder.rb +151 -40
- data/lib/rack/cascade.rb +30 -12
- data/lib/rack/chunked.rb +74 -23
- data/lib/rack/common_logger.rb +49 -36
- data/lib/rack/conditional_get.rb +33 -26
- data/lib/rack/config.rb +2 -0
- data/lib/rack/constants.rb +63 -0
- data/lib/rack/content_length.rb +13 -16
- data/lib/rack/content_type.rb +12 -8
- data/lib/rack/deflater.rb +84 -45
- data/lib/rack/directory.rb +90 -64
- data/lib/rack/etag.rb +17 -23
- data/lib/rack/events.rb +23 -20
- data/lib/rack/file.rb +5 -172
- data/lib/rack/files.rb +216 -0
- data/lib/rack/head.rb +10 -9
- data/lib/rack/headers.rb +154 -0
- data/lib/rack/lint.rb +786 -645
- data/lib/rack/lock.rb +4 -6
- data/lib/rack/logger.rb +4 -0
- data/lib/rack/media_type.rb +10 -5
- data/lib/rack/method_override.rb +8 -2
- data/lib/rack/mime.rb +17 -1
- data/lib/rack/mock.rb +2 -195
- data/lib/rack/mock_request.rb +166 -0
- data/lib/rack/mock_response.rb +126 -0
- data/lib/rack/multipart/generator.rb +21 -15
- data/lib/rack/multipart/parser.rb +161 -118
- data/lib/rack/multipart/uploaded_file.rb +19 -7
- data/lib/rack/multipart.rb +23 -41
- data/lib/rack/null_logger.rb +11 -0
- data/lib/rack/query_parser.rb +126 -65
- data/lib/rack/recursive.rb +9 -5
- data/lib/rack/reloader.rb +6 -4
- data/lib/rack/request.rb +331 -74
- data/lib/rack/response.rb +223 -70
- data/lib/rack/rewindable_input.rb +28 -8
- data/lib/rack/runtime.rb +11 -8
- data/lib/rack/sendfile.rb +42 -33
- data/lib/rack/show_exceptions.rb +35 -18
- data/lib/rack/show_status.rb +25 -15
- data/lib/rack/static.rb +30 -18
- data/lib/rack/tempfile_reaper.rb +16 -5
- data/lib/rack/urlmap.rb +14 -6
- data/lib/rack/utils.rb +268 -260
- data/lib/rack/version.rb +34 -0
- data/lib/rack.rb +15 -92
- metadata +44 -207
- data/HISTORY.md +0 -520
- data/README.rdoc +0 -316
- data/Rakefile +0 -116
- data/SPEC +0 -263
- data/bin/rackup +0 -4
- data/contrib/rack.png +0 -0
- data/contrib/rack.svg +0 -150
- data/contrib/rack_logo.svg +0 -164
- data/contrib/rdoc.css +0 -412
- data/example/lobster.ru +0 -4
- data/example/protectedlobster.rb +0 -14
- data/example/protectedlobster.ru +0 -8
- data/lib/rack/handler/cgi.rb +0 -60
- data/lib/rack/handler/fastcgi.rb +0 -100
- data/lib/rack/handler/lsws.rb +0 -61
- data/lib/rack/handler/scgi.rb +0 -70
- data/lib/rack/handler/thin.rb +0 -36
- data/lib/rack/handler/webrick.rb +0 -120
- data/lib/rack/handler.rb +0 -99
- data/lib/rack/lobster.rb +0 -70
- data/lib/rack/server.rb +0 -395
- data/lib/rack/session/abstract/id.rb +0 -510
- data/lib/rack/session/cookie.rb +0 -204
- data/lib/rack/session/memcache.rb +0 -99
- data/lib/rack/session/pool.rb +0 -83
- data/rack.gemspec +0 -34
- data/test/builder/an_underscore_app.rb +0 -5
- data/test/builder/anything.rb +0 -5
- data/test/builder/comment.ru +0 -4
- data/test/builder/end.ru +0 -5
- data/test/builder/line.ru +0 -1
- data/test/builder/options.ru +0 -2
- data/test/cgi/assets/folder/test.js +0 -1
- data/test/cgi/assets/fonts/font.eot +0 -1
- data/test/cgi/assets/images/image.png +0 -1
- data/test/cgi/assets/index.html +0 -1
- data/test/cgi/assets/javascripts/app.js +0 -1
- data/test/cgi/assets/stylesheets/app.css +0 -1
- data/test/cgi/lighttpd.conf +0 -26
- data/test/cgi/rackup_stub.rb +0 -6
- data/test/cgi/sample_rackup.ru +0 -5
- data/test/cgi/test +0 -9
- data/test/cgi/test+directory/test+file +0 -1
- data/test/cgi/test.fcgi +0 -9
- data/test/cgi/test.gz +0 -0
- data/test/cgi/test.ru +0 -5
- data/test/gemloader.rb +0 -10
- data/test/helper.rb +0 -34
- data/test/multipart/bad_robots +0 -259
- data/test/multipart/binary +0 -0
- data/test/multipart/content_type_and_no_filename +0 -6
- data/test/multipart/empty +0 -10
- data/test/multipart/fail_16384_nofile +0 -814
- data/test/multipart/file1.txt +0 -1
- data/test/multipart/filename_and_modification_param +0 -7
- data/test/multipart/filename_and_no_name +0 -6
- data/test/multipart/filename_with_encoded_words +0 -7
- data/test/multipart/filename_with_escaped_quotes +0 -6
- data/test/multipart/filename_with_escaped_quotes_and_modification_param +0 -7
- data/test/multipart/filename_with_null_byte +0 -7
- data/test/multipart/filename_with_percent_escaped_quotes +0 -6
- data/test/multipart/filename_with_single_quote +0 -7
- data/test/multipart/filename_with_unescaped_percentages +0 -6
- data/test/multipart/filename_with_unescaped_percentages2 +0 -6
- data/test/multipart/filename_with_unescaped_percentages3 +0 -6
- data/test/multipart/filename_with_unescaped_quotes +0 -6
- data/test/multipart/ie +0 -6
- data/test/multipart/invalid_character +0 -6
- data/test/multipart/mixed_files +0 -21
- data/test/multipart/nested +0 -10
- data/test/multipart/none +0 -9
- data/test/multipart/quoted +0 -15
- data/test/multipart/rack-logo.png +0 -0
- data/test/multipart/semicolon +0 -6
- data/test/multipart/text +0 -15
- data/test/multipart/three_files_three_fields +0 -31
- data/test/multipart/unity3d_wwwform +0 -11
- data/test/multipart/webkit +0 -32
- data/test/rackup/config.ru +0 -31
- data/test/registering_handler/rack/handler/registering_myself.rb +0 -8
- data/test/spec_auth_basic.rb +0 -89
- data/test/spec_auth_digest.rb +0 -260
- data/test/spec_body_proxy.rb +0 -85
- data/test/spec_builder.rb +0 -233
- data/test/spec_cascade.rb +0 -63
- data/test/spec_cgi.rb +0 -84
- data/test/spec_chunked.rb +0 -103
- data/test/spec_common_logger.rb +0 -107
- data/test/spec_conditional_get.rb +0 -103
- data/test/spec_config.rb +0 -23
- data/test/spec_content_length.rb +0 -86
- data/test/spec_content_type.rb +0 -46
- data/test/spec_deflater.rb +0 -375
- data/test/spec_directory.rb +0 -148
- data/test/spec_etag.rb +0 -108
- data/test/spec_events.rb +0 -133
- data/test/spec_fastcgi.rb +0 -85
- data/test/spec_file.rb +0 -264
- data/test/spec_handler.rb +0 -57
- data/test/spec_head.rb +0 -46
- data/test/spec_lint.rb +0 -520
- data/test/spec_lobster.rb +0 -59
- data/test/spec_lock.rb +0 -204
- data/test/spec_logger.rb +0 -24
- data/test/spec_media_type.rb +0 -42
- data/test/spec_method_override.rb +0 -110
- data/test/spec_mime.rb +0 -51
- data/test/spec_mock.rb +0 -359
- data/test/spec_multipart.rb +0 -721
- data/test/spec_null_logger.rb +0 -21
- data/test/spec_recursive.rb +0 -75
- data/test/spec_request.rb +0 -1423
- data/test/spec_response.rb +0 -528
- data/test/spec_rewindable_input.rb +0 -128
- data/test/spec_runtime.rb +0 -50
- data/test/spec_sendfile.rb +0 -125
- data/test/spec_server.rb +0 -193
- data/test/spec_session_abstract_id.rb +0 -31
- data/test/spec_session_abstract_session_hash.rb +0 -45
- data/test/spec_session_cookie.rb +0 -442
- data/test/spec_session_memcache.rb +0 -357
- data/test/spec_session_persisted_secure_secure_session_hash.rb +0 -73
- data/test/spec_session_pool.rb +0 -247
- data/test/spec_show_exceptions.rb +0 -93
- data/test/spec_show_status.rb +0 -104
- data/test/spec_static.rb +0 -184
- data/test/spec_tempfile_reaper.rb +0 -64
- data/test/spec_thin.rb +0 -96
- data/test/spec_urlmap.rb +0 -237
- data/test/spec_utils.rb +0 -742
- data/test/spec_version.rb +0 -11
- data/test/spec_webrick.rb +0 -206
- data/test/static/another/index.html +0 -1
- data/test/static/foo.html +0 -1
- data/test/static/index.html +0 -1
- data/test/testrequest.rb +0 -78
- data/test/unregistered_handler/rack/handler/unregistered.rb +0 -7
- 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&o"
|
403
|
-
Rack::Utils.escape_html("f<o").must_equal "f<o"
|
404
|
-
Rack::Utils.escape_html("f>o").must_equal "f>o"
|
405
|
-
Rack::Utils.escape_html("f'o").must_equal "f'o"
|
406
|
-
Rack::Utils.escape_html('f"o').must_equal "f"o"
|
407
|
-
Rack::Utils.escape_html("f/o").must_equal "f/o"
|
408
|
-
Rack::Utils.escape_html("<foo></foo>").must_equal "<foo></foo>"
|
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<"
|
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
|