rack 2.0.9.3 → 2.2.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 +675 -0
- data/CONTRIBUTING.md +136 -0
- data/{COPYING → MIT-LICENSE} +4 -2
- data/README.rdoc +152 -162
- data/Rakefile +37 -23
- data/{SPEC → SPEC.rdoc} +44 -15
- data/bin/rackup +1 -0
- data/example/lobster.ru +2 -0
- data/example/protectedlobster.rb +3 -1
- data/example/protectedlobster.ru +2 -0
- data/lib/rack/auth/abstract/handler.rb +3 -1
- data/lib/rack/auth/abstract/request.rb +1 -1
- data/lib/rack/auth/basic.rb +7 -4
- data/lib/rack/auth/digest/md5.rb +13 -11
- data/lib/rack/auth/digest/nonce.rb +6 -3
- data/lib/rack/auth/digest/params.rb +4 -2
- data/lib/rack/auth/digest/request.rb +5 -3
- data/lib/rack/body_proxy.rb +15 -14
- data/lib/rack/builder.rb +116 -23
- data/lib/rack/cascade.rb +28 -12
- data/lib/rack/chunked.rb +68 -20
- data/lib/rack/common_logger.rb +33 -28
- data/lib/rack/conditional_get.rb +20 -16
- data/lib/rack/config.rb +2 -0
- data/lib/rack/content_length.rb +8 -7
- data/lib/rack/content_type.rb +5 -4
- data/lib/rack/core_ext/regexp.rb +14 -0
- data/lib/rack/deflater.rb +59 -34
- data/lib/rack/directory.rb +84 -64
- data/lib/rack/etag.rb +5 -4
- data/lib/rack/events.rb +19 -20
- data/lib/rack/file.rb +4 -173
- data/lib/rack/files.rb +218 -0
- data/lib/rack/handler/cgi.rb +2 -3
- data/lib/rack/handler/fastcgi.rb +4 -4
- data/lib/rack/handler/lsws.rb +3 -3
- data/lib/rack/handler/scgi.rb +9 -8
- data/lib/rack/handler/thin.rb +17 -11
- data/lib/rack/handler/webrick.rb +15 -6
- data/lib/rack/handler.rb +7 -2
- data/lib/rack/head.rb +1 -1
- data/lib/rack/lint.rb +72 -26
- data/lib/rack/lobster.rb +10 -10
- data/lib/rack/lock.rb +2 -1
- data/lib/rack/logger.rb +2 -0
- data/lib/rack/media_type.rb +10 -5
- data/lib/rack/method_override.rb +4 -2
- data/lib/rack/mime.rb +9 -1
- data/lib/rack/mock.rb +97 -20
- data/lib/rack/multipart/generator.rb +17 -13
- data/lib/rack/multipart/parser.rb +58 -73
- data/lib/rack/multipart/uploaded_file.rb +15 -7
- data/lib/rack/multipart.rb +7 -4
- data/lib/rack/null_logger.rb +2 -0
- data/lib/rack/query_parser.rb +53 -28
- data/lib/rack/recursive.rb +7 -5
- data/lib/rack/reloader.rb +8 -4
- data/lib/rack/request.rb +210 -61
- data/lib/rack/response.rb +127 -44
- data/lib/rack/rewindable_input.rb +4 -3
- data/lib/rack/runtime.rb +6 -4
- data/lib/rack/sendfile.rb +13 -9
- data/lib/rack/server.rb +95 -24
- data/lib/rack/session/abstract/id.rb +33 -21
- data/lib/rack/session/cookie.rb +12 -12
- data/lib/rack/session/memcache.rb +4 -93
- data/lib/rack/session/pool.rb +5 -3
- data/lib/rack/show_exceptions.rb +17 -13
- data/lib/rack/show_status.rb +5 -5
- data/lib/rack/static.rb +23 -11
- data/lib/rack/tempfile_reaper.rb +1 -1
- data/lib/rack/urlmap.rb +12 -6
- data/lib/rack/utils.rb +105 -130
- data/lib/rack/version.rb +29 -0
- data/lib/rack.rb +67 -73
- data/rack.gemspec +40 -28
- metadata +39 -182
- data/HISTORY.md +0 -520
- 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_response.rb
DELETED
@@ -1,528 +0,0 @@
|
|
1
|
-
require 'minitest/autorun'
|
2
|
-
require 'rack'
|
3
|
-
require 'rack/response'
|
4
|
-
require 'stringio'
|
5
|
-
|
6
|
-
describe Rack::Response do
|
7
|
-
it 'has cache-control methods' do
|
8
|
-
response = Rack::Response.new
|
9
|
-
cc = 'foo'
|
10
|
-
response.cache_control = cc
|
11
|
-
assert_equal cc, response.cache_control
|
12
|
-
assert_equal cc, response.to_a[2]['Cache-Control']
|
13
|
-
end
|
14
|
-
|
15
|
-
it 'has an etag method' do
|
16
|
-
response = Rack::Response.new
|
17
|
-
etag = 'foo'
|
18
|
-
response.etag = etag
|
19
|
-
assert_equal etag, response.etag
|
20
|
-
assert_equal etag, response.to_a[2]['ETag']
|
21
|
-
end
|
22
|
-
|
23
|
-
it "have sensible default values" do
|
24
|
-
response = Rack::Response.new
|
25
|
-
status, header, body = response.finish
|
26
|
-
status.must_equal 200
|
27
|
-
header.must_equal({})
|
28
|
-
body.each { |part|
|
29
|
-
part.must_equal ""
|
30
|
-
}
|
31
|
-
|
32
|
-
response = Rack::Response.new
|
33
|
-
status, header, body = *response
|
34
|
-
status.must_equal 200
|
35
|
-
header.must_equal({})
|
36
|
-
body.each { |part|
|
37
|
-
part.must_equal ""
|
38
|
-
}
|
39
|
-
end
|
40
|
-
|
41
|
-
it "can be written to" do
|
42
|
-
response = Rack::Response.new
|
43
|
-
|
44
|
-
_, _, body = response.finish do
|
45
|
-
response.write "foo"
|
46
|
-
response.write "bar"
|
47
|
-
response.write "baz"
|
48
|
-
end
|
49
|
-
|
50
|
-
parts = []
|
51
|
-
body.each { |part| parts << part }
|
52
|
-
|
53
|
-
parts.must_equal ["foo", "bar", "baz"]
|
54
|
-
end
|
55
|
-
|
56
|
-
it "can set and read headers" do
|
57
|
-
response = Rack::Response.new
|
58
|
-
response["Content-Type"].must_be_nil
|
59
|
-
response["Content-Type"] = "text/plain"
|
60
|
-
response["Content-Type"].must_equal "text/plain"
|
61
|
-
end
|
62
|
-
|
63
|
-
it "can override the initial Content-Type with a different case" do
|
64
|
-
response = Rack::Response.new("", 200, "content-type" => "text/plain")
|
65
|
-
response["Content-Type"].must_equal "text/plain"
|
66
|
-
end
|
67
|
-
|
68
|
-
it "can set cookies" do
|
69
|
-
response = Rack::Response.new
|
70
|
-
|
71
|
-
response.set_cookie "foo", "bar"
|
72
|
-
response["Set-Cookie"].must_equal "foo=bar"
|
73
|
-
response.set_cookie "foo2", "bar2"
|
74
|
-
response["Set-Cookie"].must_equal ["foo=bar", "foo2=bar2"].join("\n")
|
75
|
-
response.set_cookie "foo3", "bar3"
|
76
|
-
response["Set-Cookie"].must_equal ["foo=bar", "foo2=bar2", "foo3=bar3"].join("\n")
|
77
|
-
end
|
78
|
-
|
79
|
-
it "can set cookies with the same name for multiple domains" do
|
80
|
-
response = Rack::Response.new
|
81
|
-
response.set_cookie "foo", {:value => "bar", :domain => "sample.example.com"}
|
82
|
-
response.set_cookie "foo", {:value => "bar", :domain => ".example.com"}
|
83
|
-
response["Set-Cookie"].must_equal ["foo=bar; domain=sample.example.com", "foo=bar; domain=.example.com"].join("\n")
|
84
|
-
end
|
85
|
-
|
86
|
-
it "formats the Cookie expiration date accordingly to RFC 6265" do
|
87
|
-
response = Rack::Response.new
|
88
|
-
|
89
|
-
response.set_cookie "foo", {:value => "bar", :expires => Time.now+10}
|
90
|
-
response["Set-Cookie"].must_match(
|
91
|
-
/expires=..., \d\d ... \d\d\d\d \d\d:\d\d:\d\d .../)
|
92
|
-
end
|
93
|
-
|
94
|
-
it "can set secure cookies" do
|
95
|
-
response = Rack::Response.new
|
96
|
-
response.set_cookie "foo", {:value => "bar", :secure => true}
|
97
|
-
response["Set-Cookie"].must_equal "foo=bar; secure"
|
98
|
-
end
|
99
|
-
|
100
|
-
it "can set http only cookies" do
|
101
|
-
response = Rack::Response.new
|
102
|
-
response.set_cookie "foo", {:value => "bar", :httponly => true}
|
103
|
-
response["Set-Cookie"].must_equal "foo=bar; HttpOnly"
|
104
|
-
end
|
105
|
-
|
106
|
-
it "can set http only cookies with :http_only" do
|
107
|
-
response = Rack::Response.new
|
108
|
-
response.set_cookie "foo", {:value => "bar", :http_only => true}
|
109
|
-
response["Set-Cookie"].must_equal "foo=bar; HttpOnly"
|
110
|
-
end
|
111
|
-
|
112
|
-
it "can set prefers :httponly for http only cookie setting when :httponly and :http_only provided" do
|
113
|
-
response = Rack::Response.new
|
114
|
-
response.set_cookie "foo", {:value => "bar", :httponly => false, :http_only => true}
|
115
|
-
response["Set-Cookie"].must_equal "foo=bar"
|
116
|
-
end
|
117
|
-
|
118
|
-
it "can set SameSite cookies with symbol value :none" do
|
119
|
-
response = Rack::Response.new
|
120
|
-
response.set_cookie "foo", { value: "bar", same_site: :none }
|
121
|
-
response["Set-Cookie"].must_equal "foo=bar; SameSite=None"
|
122
|
-
end
|
123
|
-
|
124
|
-
it "can set SameSite cookies with symbol value :None" do
|
125
|
-
response = Rack::Response.new
|
126
|
-
response.set_cookie "foo", { value: "bar", same_site: :None }
|
127
|
-
response["Set-Cookie"].must_equal "foo=bar; SameSite=None"
|
128
|
-
end
|
129
|
-
|
130
|
-
it "can set SameSite cookies with string value 'None'" do
|
131
|
-
response = Rack::Response.new
|
132
|
-
response.set_cookie "foo", { value: "bar", same_site: "None" }
|
133
|
-
response["Set-Cookie"].must_equal "foo=bar; SameSite=None"
|
134
|
-
end
|
135
|
-
|
136
|
-
it "can set SameSite cookies with symbol value :lax" do
|
137
|
-
response = Rack::Response.new
|
138
|
-
response.set_cookie "foo", {:value => "bar", :same_site => :lax}
|
139
|
-
response["Set-Cookie"].must_equal "foo=bar; SameSite=Lax"
|
140
|
-
end
|
141
|
-
|
142
|
-
it "can set SameSite cookies with symbol value :Lax" do
|
143
|
-
response = Rack::Response.new
|
144
|
-
response.set_cookie "foo", {:value => "bar", :same_site => :lax}
|
145
|
-
response["Set-Cookie"].must_equal "foo=bar; SameSite=Lax"
|
146
|
-
end
|
147
|
-
|
148
|
-
it "can set SameSite cookies with string value 'Lax'" do
|
149
|
-
response = Rack::Response.new
|
150
|
-
response.set_cookie "foo", {:value => "bar", :same_site => "Lax"}
|
151
|
-
response["Set-Cookie"].must_equal "foo=bar; SameSite=Lax"
|
152
|
-
end
|
153
|
-
|
154
|
-
it "can set SameSite cookies with boolean value true" do
|
155
|
-
response = Rack::Response.new
|
156
|
-
response.set_cookie "foo", {:value => "bar", :same_site => true}
|
157
|
-
response["Set-Cookie"].must_equal "foo=bar; SameSite=Strict"
|
158
|
-
end
|
159
|
-
|
160
|
-
it "can set SameSite cookies with symbol value :strict" do
|
161
|
-
response = Rack::Response.new
|
162
|
-
response.set_cookie "foo", {:value => "bar", :same_site => :strict}
|
163
|
-
response["Set-Cookie"].must_equal "foo=bar; SameSite=Strict"
|
164
|
-
end
|
165
|
-
|
166
|
-
it "can set SameSite cookies with symbol value :Strict" do
|
167
|
-
response = Rack::Response.new
|
168
|
-
response.set_cookie "foo", {:value => "bar", :same_site => :Strict}
|
169
|
-
response["Set-Cookie"].must_equal "foo=bar; SameSite=Strict"
|
170
|
-
end
|
171
|
-
|
172
|
-
it "can set SameSite cookies with string value 'Strict'" do
|
173
|
-
response = Rack::Response.new
|
174
|
-
response.set_cookie "foo", {:value => "bar", :same_site => "Strict"}
|
175
|
-
response["Set-Cookie"].must_equal "foo=bar; SameSite=Strict"
|
176
|
-
end
|
177
|
-
|
178
|
-
it "validates the SameSite option value" do
|
179
|
-
response = Rack::Response.new
|
180
|
-
lambda {
|
181
|
-
response.set_cookie "foo", {:value => "bar", :same_site => "Foo"}
|
182
|
-
}.must_raise(ArgumentError).
|
183
|
-
message.must_match(/Invalid SameSite value: "Foo"/)
|
184
|
-
end
|
185
|
-
|
186
|
-
it "can set SameSite cookies with symbol value" do
|
187
|
-
response = Rack::Response.new
|
188
|
-
response.set_cookie "foo", {:value => "bar", :same_site => :Strict}
|
189
|
-
response["Set-Cookie"].must_equal "foo=bar; SameSite=Strict"
|
190
|
-
end
|
191
|
-
|
192
|
-
[ nil, false ].each do |non_truthy|
|
193
|
-
it "omits SameSite attribute given a #{non_truthy.inspect} value" do
|
194
|
-
response = Rack::Response.new
|
195
|
-
response.set_cookie "foo", {:value => "bar", :same_site => non_truthy}
|
196
|
-
response["Set-Cookie"].must_equal "foo=bar"
|
197
|
-
end
|
198
|
-
end
|
199
|
-
|
200
|
-
it "can delete cookies" do
|
201
|
-
response = Rack::Response.new
|
202
|
-
response.set_cookie "foo", "bar"
|
203
|
-
response.set_cookie "foo2", "bar2"
|
204
|
-
response.delete_cookie "foo"
|
205
|
-
response["Set-Cookie"].must_equal [
|
206
|
-
"foo2=bar2",
|
207
|
-
"foo=; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 -0000"
|
208
|
-
].join("\n")
|
209
|
-
end
|
210
|
-
|
211
|
-
it "can delete cookies with the same name from multiple domains" do
|
212
|
-
response = Rack::Response.new
|
213
|
-
response.set_cookie "foo", {:value => "bar", :domain => "sample.example.com"}
|
214
|
-
response.set_cookie "foo", {:value => "bar", :domain => ".example.com"}
|
215
|
-
response["Set-Cookie"].must_equal ["foo=bar; domain=sample.example.com", "foo=bar; domain=.example.com"].join("\n")
|
216
|
-
response.delete_cookie "foo", :domain => ".example.com"
|
217
|
-
response["Set-Cookie"].must_equal ["foo=bar; domain=sample.example.com", "foo=; domain=.example.com; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 -0000"].join("\n")
|
218
|
-
response.delete_cookie "foo", :domain => "sample.example.com"
|
219
|
-
response["Set-Cookie"].must_equal ["foo=; domain=.example.com; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 -0000",
|
220
|
-
"foo=; domain=sample.example.com; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 -0000"].join("\n")
|
221
|
-
end
|
222
|
-
|
223
|
-
it "can delete cookies with the same name with different paths" do
|
224
|
-
response = Rack::Response.new
|
225
|
-
response.set_cookie "foo", {:value => "bar", :path => "/"}
|
226
|
-
response.set_cookie "foo", {:value => "bar", :path => "/path"}
|
227
|
-
response["Set-Cookie"].must_equal ["foo=bar; path=/",
|
228
|
-
"foo=bar; path=/path"].join("\n")
|
229
|
-
|
230
|
-
response.delete_cookie "foo", :path => "/path"
|
231
|
-
response["Set-Cookie"].must_equal ["foo=bar; path=/",
|
232
|
-
"foo=; path=/path; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 -0000"].join("\n")
|
233
|
-
end
|
234
|
-
|
235
|
-
it "can do redirects" do
|
236
|
-
response = Rack::Response.new
|
237
|
-
response.redirect "/foo"
|
238
|
-
status, header, body = response.finish
|
239
|
-
status.must_equal 302
|
240
|
-
header["Location"].must_equal "/foo"
|
241
|
-
|
242
|
-
response = Rack::Response.new
|
243
|
-
response.redirect "/foo", 307
|
244
|
-
status, header, body = response.finish
|
245
|
-
|
246
|
-
status.must_equal 307
|
247
|
-
end
|
248
|
-
|
249
|
-
it "has a useful constructor" do
|
250
|
-
r = Rack::Response.new("foo")
|
251
|
-
status, header, body = r.finish
|
252
|
-
str = ""; body.each { |part| str << part }
|
253
|
-
str.must_equal "foo"
|
254
|
-
|
255
|
-
r = Rack::Response.new(["foo", "bar"])
|
256
|
-
status, header, body = r.finish
|
257
|
-
str = ""; body.each { |part| str << part }
|
258
|
-
str.must_equal "foobar"
|
259
|
-
|
260
|
-
object_with_each = Object.new
|
261
|
-
def object_with_each.each
|
262
|
-
yield "foo"
|
263
|
-
yield "bar"
|
264
|
-
end
|
265
|
-
r = Rack::Response.new(object_with_each)
|
266
|
-
r.write "foo"
|
267
|
-
status, header, body = r.finish
|
268
|
-
str = ""; body.each { |part| str << part }
|
269
|
-
str.must_equal "foobarfoo"
|
270
|
-
|
271
|
-
r = Rack::Response.new([], 500)
|
272
|
-
r.status.must_equal 500
|
273
|
-
|
274
|
-
r = Rack::Response.new([], "200 OK")
|
275
|
-
r.status.must_equal 200
|
276
|
-
end
|
277
|
-
|
278
|
-
it "has a constructor that can take a block" do
|
279
|
-
r = Rack::Response.new { |res|
|
280
|
-
res.status = 404
|
281
|
-
res.write "foo"
|
282
|
-
}
|
283
|
-
status, _, body = r.finish
|
284
|
-
str = ""; body.each { |part| str << part }
|
285
|
-
str.must_equal "foo"
|
286
|
-
status.must_equal 404
|
287
|
-
end
|
288
|
-
|
289
|
-
it "doesn't return invalid responses" do
|
290
|
-
r = Rack::Response.new(["foo", "bar"], 204)
|
291
|
-
_, header, body = r.finish
|
292
|
-
str = ""; body.each { |part| str << part }
|
293
|
-
str.must_be :empty?
|
294
|
-
header["Content-Type"].must_be_nil
|
295
|
-
header['Content-Length'].must_be_nil
|
296
|
-
|
297
|
-
lambda {
|
298
|
-
Rack::Response.new(Object.new)
|
299
|
-
}.must_raise(TypeError).
|
300
|
-
message.must_match(/stringable or iterable required/)
|
301
|
-
end
|
302
|
-
|
303
|
-
it "knows if it's empty" do
|
304
|
-
r = Rack::Response.new
|
305
|
-
r.must_be :empty?
|
306
|
-
r.write "foo"
|
307
|
-
r.wont_be :empty?
|
308
|
-
|
309
|
-
r = Rack::Response.new
|
310
|
-
r.must_be :empty?
|
311
|
-
r.finish
|
312
|
-
r.must_be :empty?
|
313
|
-
|
314
|
-
r = Rack::Response.new
|
315
|
-
r.must_be :empty?
|
316
|
-
r.finish { }
|
317
|
-
r.wont_be :empty?
|
318
|
-
end
|
319
|
-
|
320
|
-
it "provide access to the HTTP status" do
|
321
|
-
res = Rack::Response.new
|
322
|
-
res.status = 200
|
323
|
-
res.must_be :successful?
|
324
|
-
res.must_be :ok?
|
325
|
-
|
326
|
-
res.status = 201
|
327
|
-
res.must_be :successful?
|
328
|
-
res.must_be :created?
|
329
|
-
|
330
|
-
res.status = 202
|
331
|
-
res.must_be :successful?
|
332
|
-
res.must_be :accepted?
|
333
|
-
|
334
|
-
res.status = 204
|
335
|
-
res.must_be :successful?
|
336
|
-
res.must_be :no_content?
|
337
|
-
|
338
|
-
res.status = 301
|
339
|
-
res.must_be :redirect?
|
340
|
-
res.must_be :moved_permanently?
|
341
|
-
|
342
|
-
res.status = 302
|
343
|
-
res.must_be :redirect?
|
344
|
-
|
345
|
-
res.status = 303
|
346
|
-
res.must_be :redirect?
|
347
|
-
|
348
|
-
res.status = 307
|
349
|
-
res.must_be :redirect?
|
350
|
-
|
351
|
-
res.status = 308
|
352
|
-
res.must_be :redirect?
|
353
|
-
|
354
|
-
res.status = 400
|
355
|
-
res.wont_be :successful?
|
356
|
-
res.must_be :client_error?
|
357
|
-
res.must_be :bad_request?
|
358
|
-
|
359
|
-
res.status = 401
|
360
|
-
res.wont_be :successful?
|
361
|
-
res.must_be :client_error?
|
362
|
-
res.must_be :unauthorized?
|
363
|
-
|
364
|
-
res.status = 404
|
365
|
-
res.wont_be :successful?
|
366
|
-
res.must_be :client_error?
|
367
|
-
res.must_be :not_found?
|
368
|
-
|
369
|
-
res.status = 405
|
370
|
-
res.wont_be :successful?
|
371
|
-
res.must_be :client_error?
|
372
|
-
res.must_be :method_not_allowed?
|
373
|
-
|
374
|
-
res.status = 412
|
375
|
-
res.wont_be :successful?
|
376
|
-
res.must_be :client_error?
|
377
|
-
res.must_be :precondition_failed?
|
378
|
-
|
379
|
-
res.status = 422
|
380
|
-
res.wont_be :successful?
|
381
|
-
res.must_be :client_error?
|
382
|
-
res.must_be :unprocessable?
|
383
|
-
|
384
|
-
res.status = 501
|
385
|
-
res.wont_be :successful?
|
386
|
-
res.must_be :server_error?
|
387
|
-
end
|
388
|
-
|
389
|
-
it "provide access to the HTTP headers" do
|
390
|
-
res = Rack::Response.new
|
391
|
-
res["Content-Type"] = "text/yaml"
|
392
|
-
|
393
|
-
res.must_include "Content-Type"
|
394
|
-
res.headers["Content-Type"].must_equal "text/yaml"
|
395
|
-
res["Content-Type"].must_equal "text/yaml"
|
396
|
-
res.content_type.must_equal "text/yaml"
|
397
|
-
res.content_length.must_be_nil
|
398
|
-
res.location.must_be_nil
|
399
|
-
end
|
400
|
-
|
401
|
-
it "does not add or change Content-Length when #finish()ing" do
|
402
|
-
res = Rack::Response.new
|
403
|
-
res.status = 200
|
404
|
-
res.finish
|
405
|
-
res.headers["Content-Length"].must_be_nil
|
406
|
-
|
407
|
-
res = Rack::Response.new
|
408
|
-
res.status = 200
|
409
|
-
res.headers["Content-Length"] = "10"
|
410
|
-
res.finish
|
411
|
-
res.headers["Content-Length"].must_equal "10"
|
412
|
-
end
|
413
|
-
|
414
|
-
it "updates Content-Length when body appended to using #write" do
|
415
|
-
res = Rack::Response.new
|
416
|
-
res.status = 200
|
417
|
-
res.headers["Content-Length"].must_be_nil
|
418
|
-
res.write "Hi"
|
419
|
-
res.headers["Content-Length"].must_equal "2"
|
420
|
-
res.write " there"
|
421
|
-
res.headers["Content-Length"].must_equal "8"
|
422
|
-
end
|
423
|
-
|
424
|
-
it "calls close on #body" do
|
425
|
-
res = Rack::Response.new
|
426
|
-
res.body = StringIO.new
|
427
|
-
res.close
|
428
|
-
res.body.must_be :closed?
|
429
|
-
end
|
430
|
-
|
431
|
-
it "calls close on #body when 204 or 304" do
|
432
|
-
res = Rack::Response.new
|
433
|
-
res.body = StringIO.new
|
434
|
-
res.finish
|
435
|
-
res.body.wont_be :closed?
|
436
|
-
|
437
|
-
res.status = 204
|
438
|
-
_, _, b = res.finish
|
439
|
-
res.body.must_be :closed?
|
440
|
-
b.wont_equal res.body
|
441
|
-
|
442
|
-
res.body = StringIO.new
|
443
|
-
res.status = 205
|
444
|
-
_, _, b = res.finish
|
445
|
-
res.body.wont_be :closed?
|
446
|
-
b.wont_equal res.body
|
447
|
-
|
448
|
-
res.body = StringIO.new
|
449
|
-
res.status = 304
|
450
|
-
_, _, b = res.finish
|
451
|
-
res.body.must_be :closed?
|
452
|
-
b.wont_equal res.body
|
453
|
-
end
|
454
|
-
|
455
|
-
it "wraps the body from #to_ary to prevent infinite loops" do
|
456
|
-
res = Rack::Response.new
|
457
|
-
res.finish.last.wont_respond_to(:to_ary)
|
458
|
-
lambda { res.finish.last.to_ary }.must_raise NoMethodError
|
459
|
-
end
|
460
|
-
end
|
461
|
-
|
462
|
-
describe Rack::Response, 'headers' do
|
463
|
-
before do
|
464
|
-
@response = Rack::Response.new([], 200, { 'Foo' => '1' })
|
465
|
-
end
|
466
|
-
|
467
|
-
it 'has_header?' do
|
468
|
-
lambda { @response.has_header? nil }.must_raise NoMethodError
|
469
|
-
|
470
|
-
@response.has_header?('Foo').must_equal true
|
471
|
-
@response.has_header?('foo').must_equal true
|
472
|
-
end
|
473
|
-
|
474
|
-
it 'get_header' do
|
475
|
-
lambda { @response.get_header nil }.must_raise NoMethodError
|
476
|
-
|
477
|
-
@response.get_header('Foo').must_equal '1'
|
478
|
-
@response.get_header('foo').must_equal '1'
|
479
|
-
end
|
480
|
-
|
481
|
-
it 'set_header' do
|
482
|
-
lambda { @response.set_header nil, '1' }.must_raise NoMethodError
|
483
|
-
|
484
|
-
@response.set_header('Foo', '2').must_equal '2'
|
485
|
-
@response.has_header?('Foo').must_equal true
|
486
|
-
@response.get_header('Foo').must_equal('2')
|
487
|
-
|
488
|
-
@response.set_header('Foo', nil).must_be_nil
|
489
|
-
@response.has_header?('Foo').must_equal true
|
490
|
-
@response.get_header('Foo').must_be_nil
|
491
|
-
end
|
492
|
-
|
493
|
-
it 'add_header' do
|
494
|
-
lambda { @response.add_header nil, '1' }.must_raise NoMethodError
|
495
|
-
|
496
|
-
# Add a value to an existing header
|
497
|
-
@response.add_header('Foo', '2').must_equal '1,2'
|
498
|
-
@response.get_header('Foo').must_equal '1,2'
|
499
|
-
|
500
|
-
# Add nil to an existing header
|
501
|
-
@response.add_header('Foo', nil).must_equal '1,2'
|
502
|
-
@response.get_header('Foo').must_equal '1,2'
|
503
|
-
|
504
|
-
# Add nil to a nonexistent header
|
505
|
-
@response.add_header('Bar', nil).must_be_nil
|
506
|
-
@response.has_header?('Bar').must_equal false
|
507
|
-
@response.get_header('Bar').must_be_nil
|
508
|
-
|
509
|
-
# Add a value to a nonexistent header
|
510
|
-
@response.add_header('Bar', '1').must_equal '1'
|
511
|
-
@response.has_header?('Bar').must_equal true
|
512
|
-
@response.get_header('Bar').must_equal '1'
|
513
|
-
end
|
514
|
-
|
515
|
-
it 'delete_header' do
|
516
|
-
lambda { @response.delete_header nil }.must_raise NoMethodError
|
517
|
-
|
518
|
-
@response.delete_header('Foo').must_equal '1'
|
519
|
-
(!!@response.has_header?('Foo')).must_equal false
|
520
|
-
|
521
|
-
@response.delete_header('Foo').must_be_nil
|
522
|
-
@response.has_header?('Foo').must_equal false
|
523
|
-
|
524
|
-
@response.set_header('Foo', 1)
|
525
|
-
@response.delete_header('foo').must_equal 1
|
526
|
-
@response.has_header?('Foo').must_equal false
|
527
|
-
end
|
528
|
-
end
|
@@ -1,128 +0,0 @@
|
|
1
|
-
require 'minitest/autorun'
|
2
|
-
require 'stringio'
|
3
|
-
require 'rack/rewindable_input'
|
4
|
-
|
5
|
-
module RewindableTest
|
6
|
-
extend Minitest::Spec::DSL
|
7
|
-
|
8
|
-
def setup
|
9
|
-
@rio = Rack::RewindableInput.new(@io)
|
10
|
-
end
|
11
|
-
|
12
|
-
class << self # HACK to get this running w/ as few changes as possible
|
13
|
-
alias_method :should, :it
|
14
|
-
end
|
15
|
-
|
16
|
-
it "be able to handle to read()" do
|
17
|
-
@rio.read.must_equal "hello world"
|
18
|
-
end
|
19
|
-
|
20
|
-
it "be able to handle to read(nil)" do
|
21
|
-
@rio.read(nil).must_equal "hello world"
|
22
|
-
end
|
23
|
-
|
24
|
-
it "be able to handle to read(length)" do
|
25
|
-
@rio.read(1).must_equal "h"
|
26
|
-
end
|
27
|
-
|
28
|
-
it "be able to handle to read(length, buffer)" do
|
29
|
-
buffer = ""
|
30
|
-
result = @rio.read(1, buffer)
|
31
|
-
result.must_equal "h"
|
32
|
-
result.object_id.must_equal buffer.object_id
|
33
|
-
end
|
34
|
-
|
35
|
-
it "be able to handle to read(nil, buffer)" do
|
36
|
-
buffer = ""
|
37
|
-
result = @rio.read(nil, buffer)
|
38
|
-
result.must_equal "hello world"
|
39
|
-
result.object_id.must_equal buffer.object_id
|
40
|
-
end
|
41
|
-
|
42
|
-
it "rewind to the beginning when #rewind is called" do
|
43
|
-
@rio.read(1)
|
44
|
-
@rio.rewind
|
45
|
-
@rio.read.must_equal "hello world"
|
46
|
-
end
|
47
|
-
|
48
|
-
it "be able to handle gets" do
|
49
|
-
@rio.gets.must_equal "hello world"
|
50
|
-
end
|
51
|
-
|
52
|
-
it "be able to handle each" do
|
53
|
-
array = []
|
54
|
-
@rio.each do |data|
|
55
|
-
array << data
|
56
|
-
end
|
57
|
-
array.must_equal ["hello world"]
|
58
|
-
end
|
59
|
-
|
60
|
-
it "not buffer into a Tempfile if no data has been read yet" do
|
61
|
-
@rio.instance_variable_get(:@rewindable_io).must_be_nil
|
62
|
-
end
|
63
|
-
|
64
|
-
it "buffer into a Tempfile when data has been consumed for the first time" do
|
65
|
-
@rio.read(1)
|
66
|
-
tempfile = @rio.instance_variable_get(:@rewindable_io)
|
67
|
-
tempfile.wont_be :nil?
|
68
|
-
@rio.read(1)
|
69
|
-
tempfile2 = @rio.instance_variable_get(:@rewindable_io)
|
70
|
-
tempfile2.path.must_equal tempfile.path
|
71
|
-
end
|
72
|
-
|
73
|
-
it "close the underlying tempfile upon calling #close" do
|
74
|
-
@rio.read(1)
|
75
|
-
tempfile = @rio.instance_variable_get(:@rewindable_io)
|
76
|
-
@rio.close
|
77
|
-
tempfile.must_be :closed?
|
78
|
-
end
|
79
|
-
|
80
|
-
it "be possible to call #close when no data has been buffered yet" do
|
81
|
-
@rio.close.must_be_nil
|
82
|
-
end
|
83
|
-
|
84
|
-
it "be possible to call #close multiple times" do
|
85
|
-
@rio.close.must_be_nil
|
86
|
-
@rio.close.must_be_nil
|
87
|
-
end
|
88
|
-
|
89
|
-
after do
|
90
|
-
@rio.close
|
91
|
-
@rio = nil
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
describe Rack::RewindableInput do
|
96
|
-
describe "given an IO object that is already rewindable" do
|
97
|
-
def setup
|
98
|
-
@io = StringIO.new("hello world")
|
99
|
-
super
|
100
|
-
end
|
101
|
-
|
102
|
-
include RewindableTest
|
103
|
-
end
|
104
|
-
|
105
|
-
describe "given an IO object that is not rewindable" do
|
106
|
-
def setup
|
107
|
-
@io = StringIO.new("hello world")
|
108
|
-
@io.instance_eval do
|
109
|
-
undef :rewind
|
110
|
-
end
|
111
|
-
super
|
112
|
-
end
|
113
|
-
|
114
|
-
include RewindableTest
|
115
|
-
end
|
116
|
-
|
117
|
-
describe "given an IO object whose rewind method raises Errno::ESPIPE" do
|
118
|
-
def setup
|
119
|
-
@io = StringIO.new("hello world")
|
120
|
-
def @io.rewind
|
121
|
-
raise Errno::ESPIPE, "You can't rewind this!"
|
122
|
-
end
|
123
|
-
super
|
124
|
-
end
|
125
|
-
|
126
|
-
include RewindableTest
|
127
|
-
end
|
128
|
-
end
|
data/test/spec_runtime.rb
DELETED
@@ -1,50 +0,0 @@
|
|
1
|
-
require 'minitest/autorun'
|
2
|
-
require 'rack/lint'
|
3
|
-
require 'rack/mock'
|
4
|
-
require 'rack/runtime'
|
5
|
-
|
6
|
-
describe Rack::Runtime do
|
7
|
-
def runtime_app(app, *args)
|
8
|
-
Rack::Lint.new Rack::Runtime.new(app, *args)
|
9
|
-
end
|
10
|
-
|
11
|
-
def request
|
12
|
-
Rack::MockRequest.env_for
|
13
|
-
end
|
14
|
-
|
15
|
-
it "sets X-Runtime is none is set" do
|
16
|
-
app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, "Hello, World!"] }
|
17
|
-
response = runtime_app(app).call(request)
|
18
|
-
response[1]['X-Runtime'].must_match(/[\d\.]+/)
|
19
|
-
end
|
20
|
-
|
21
|
-
it "doesn't set the X-Runtime if it is already set" do
|
22
|
-
app = lambda { |env| [200, {'Content-Type' => 'text/plain', "X-Runtime" => "foobar"}, "Hello, World!"] }
|
23
|
-
response = runtime_app(app).call(request)
|
24
|
-
response[1]['X-Runtime'].must_equal "foobar"
|
25
|
-
end
|
26
|
-
|
27
|
-
it "allow a suffix to be set" do
|
28
|
-
app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, "Hello, World!"] }
|
29
|
-
response = runtime_app(app, "Test").call(request)
|
30
|
-
response[1]['X-Runtime-Test'].must_match(/[\d\.]+/)
|
31
|
-
end
|
32
|
-
|
33
|
-
it "allow multiple timers to be set" do
|
34
|
-
app = lambda { |env| sleep 0.1; [200, {'Content-Type' => 'text/plain'}, "Hello, World!"] }
|
35
|
-
runtime = runtime_app(app, "App")
|
36
|
-
|
37
|
-
# wrap many times to guarantee a measurable difference
|
38
|
-
100.times do |i|
|
39
|
-
runtime = Rack::Runtime.new(runtime, i.to_s)
|
40
|
-
end
|
41
|
-
runtime = Rack::Runtime.new(runtime, "All")
|
42
|
-
|
43
|
-
response = runtime.call(request)
|
44
|
-
|
45
|
-
response[1]['X-Runtime-App'].must_match(/[\d\.]+/)
|
46
|
-
response[1]['X-Runtime-All'].must_match(/[\d\.]+/)
|
47
|
-
|
48
|
-
Float(response[1]['X-Runtime-All']).must_be :>, Float(response[1]['X-Runtime-App'])
|
49
|
-
end
|
50
|
-
end
|