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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +77 -0
- data/{COPYING → MIT-LICENSE} +4 -2
- data/README.rdoc +122 -456
- data/Rakefile +32 -31
- data/SPEC +119 -29
- data/bin/rackup +1 -0
- data/contrib/rack_logo.svg +164 -111
- data/example/lobster.ru +2 -0
- data/example/protectedlobster.rb +4 -2
- data/example/protectedlobster.ru +3 -1
- data/lib/rack/auth/abstract/handler.rb +7 -5
- data/lib/rack/auth/abstract/request.rb +8 -6
- data/lib/rack/auth/basic.rb +5 -2
- data/lib/rack/auth/digest/md5.rb +10 -8
- data/lib/rack/auth/digest/nonce.rb +6 -3
- data/lib/rack/auth/digest/params.rb +5 -4
- data/lib/rack/auth/digest/request.rb +4 -2
- data/lib/rack/body_proxy.rb +11 -9
- data/lib/rack/builder.rb +63 -20
- data/lib/rack/cascade.rb +10 -9
- data/lib/rack/chunked.rb +45 -11
- data/lib/rack/{commonlogger.rb → common_logger.rb} +24 -15
- data/lib/rack/{conditionalget.rb → conditional_get.rb} +20 -6
- data/lib/rack/config.rb +7 -0
- data/lib/rack/content_length.rb +12 -6
- data/lib/rack/content_type.rb +4 -2
- data/lib/rack/core_ext/regexp.rb +14 -0
- data/lib/rack/deflater.rb +73 -42
- data/lib/rack/directory.rb +77 -56
- data/lib/rack/etag.rb +25 -13
- data/lib/rack/events.rb +156 -0
- data/lib/rack/file.rb +4 -143
- data/lib/rack/files.rb +178 -0
- data/lib/rack/handler/cgi.rb +18 -17
- data/lib/rack/handler/fastcgi.rb +21 -17
- data/lib/rack/handler/lsws.rb +14 -12
- data/lib/rack/handler/scgi.rb +27 -21
- data/lib/rack/handler/thin.rb +19 -5
- data/lib/rack/handler/webrick.rb +66 -24
- data/lib/rack/handler.rb +29 -19
- data/lib/rack/head.rb +21 -14
- data/lib/rack/lint.rb +259 -65
- data/lib/rack/lobster.rb +17 -10
- data/lib/rack/lock.rb +19 -10
- data/lib/rack/logger.rb +4 -2
- data/lib/rack/media_type.rb +43 -0
- data/lib/rack/method_override.rb +52 -0
- data/lib/rack/mime.rb +43 -6
- data/lib/rack/mock.rb +109 -44
- data/lib/rack/multipart/generator.rb +11 -12
- data/lib/rack/multipart/parser.rb +302 -115
- data/lib/rack/multipart/uploaded_file.rb +4 -3
- data/lib/rack/multipart.rb +40 -9
- data/lib/rack/null_logger.rb +39 -0
- data/lib/rack/query_parser.rb +218 -0
- data/lib/rack/recursive.rb +14 -11
- data/lib/rack/reloader.rb +12 -5
- data/lib/rack/request.rb +484 -270
- data/lib/rack/response.rb +196 -77
- data/lib/rack/rewindable_input.rb +5 -14
- data/lib/rack/runtime.rb +13 -6
- data/lib/rack/sendfile.rb +44 -20
- data/lib/rack/server.rb +175 -61
- data/lib/rack/session/abstract/id.rb +276 -133
- data/lib/rack/session/cookie.rb +75 -40
- data/lib/rack/session/memcache.rb +4 -87
- data/lib/rack/session/pool.rb +24 -18
- data/lib/rack/show_exceptions.rb +392 -0
- data/lib/rack/{showstatus.rb → show_status.rb} +11 -9
- data/lib/rack/static.rb +65 -38
- data/lib/rack/tempfile_reaper.rb +24 -0
- data/lib/rack/urlmap.rb +40 -15
- data/lib/rack/utils.rb +316 -285
- data/lib/rack.rb +78 -23
- data/rack.gemspec +26 -19
- metadata +44 -209
- data/KNOWN-ISSUES +0 -30
- data/lib/rack/backports/uri/common_18.rb +0 -56
- data/lib/rack/backports/uri/common_192.rb +0 -52
- data/lib/rack/backports/uri/common_193.rb +0 -29
- data/lib/rack/handler/evented_mongrel.rb +0 -8
- data/lib/rack/handler/mongrel.rb +0 -100
- data/lib/rack/handler/swiftiplied_mongrel.rb +0 -8
- data/lib/rack/methodoverride.rb +0 -33
- data/lib/rack/nulllogger.rb +0 -18
- data/lib/rack/showexceptions.rb +0 -378
- 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/lighttpd.errors +0 -1
- 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 -8
- data/test/cgi/test.ru +0 -5
- data/test/gemloader.rb +0 -10
- 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_with_escaped_quotes +0 -6
- data/test/multipart/filename_with_escaped_quotes_and_modification_param +0 -7
- data/test/multipart/filename_with_percent_escaped_quotes +0 -6
- 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/mixed_files +0 -21
- data/test/multipart/nested +0 -10
- data/test/multipart/none +0 -9
- data/test/multipart/semicolon +0 -6
- data/test/multipart/text +0 -15
- data/test/multipart/three_files_three_fields +0 -31
- 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.rb +0 -57
- data/test/spec_auth_basic.rb +0 -81
- data/test/spec_auth_digest.rb +0 -259
- data/test/spec_body_proxy.rb +0 -69
- data/test/spec_builder.rb +0 -207
- data/test/spec_cascade.rb +0 -61
- data/test/spec_cgi.rb +0 -102
- data/test/spec_chunked.rb +0 -87
- data/test/spec_commonlogger.rb +0 -57
- data/test/spec_conditionalget.rb +0 -102
- data/test/spec_config.rb +0 -22
- data/test/spec_content_length.rb +0 -86
- data/test/spec_content_type.rb +0 -45
- data/test/spec_deflater.rb +0 -187
- data/test/spec_directory.rb +0 -88
- data/test/spec_etag.rb +0 -98
- data/test/spec_fastcgi.rb +0 -107
- data/test/spec_file.rb +0 -200
- data/test/spec_handler.rb +0 -59
- data/test/spec_head.rb +0 -48
- data/test/spec_lint.rb +0 -515
- data/test/spec_lobster.rb +0 -58
- data/test/spec_lock.rb +0 -167
- data/test/spec_logger.rb +0 -23
- data/test/spec_methodoverride.rb +0 -72
- data/test/spec_mock.rb +0 -269
- data/test/spec_mongrel.rb +0 -182
- data/test/spec_multipart.rb +0 -479
- data/test/spec_nulllogger.rb +0 -23
- data/test/spec_recursive.rb +0 -72
- data/test/spec_request.rb +0 -955
- data/test/spec_response.rb +0 -313
- data/test/spec_rewindable_input.rb +0 -118
- data/test/spec_runtime.rb +0 -49
- data/test/spec_sendfile.rb +0 -90
- data/test/spec_server.rb +0 -121
- data/test/spec_session_abstract_id.rb +0 -43
- data/test/spec_session_cookie.rb +0 -361
- data/test/spec_session_memcache.rb +0 -321
- data/test/spec_session_pool.rb +0 -209
- data/test/spec_showexceptions.rb +0 -92
- data/test/spec_showstatus.rb +0 -84
- data/test/spec_static.rb +0 -145
- data/test/spec_thin.rb +0 -86
- data/test/spec_urlmap.rb +0 -213
- data/test/spec_utils.rb +0 -554
- data/test/spec_webrick.rb +0 -143
- data/test/static/another/index.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,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&o"
|
290
|
-
Rack::Utils.escape_html("f<o").should.equal "f<o"
|
291
|
-
Rack::Utils.escape_html("f>o").should.equal "f>o"
|
292
|
-
Rack::Utils.escape_html("f'o").should.equal "f'o"
|
293
|
-
Rack::Utils.escape_html('f"o').should.equal "f"o"
|
294
|
-
Rack::Utils.escape_html("f/o").should.equal "f/o"
|
295
|
-
Rack::Utils.escape_html("<foo></foo>").should.equal "<foo></foo>"
|
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<"
|
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
|