rack 2.0.9.4 → 2.1.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/{HISTORY.md → CHANGELOG.md} +214 -164
- data/{COPYING → MIT-LICENSE} +4 -2
- data/README.rdoc +79 -133
- data/Rakefile +25 -18
- data/SPEC +9 -9
- 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 +2 -0
- data/lib/rack/auth/basic.rb +4 -1
- data/lib/rack/auth/digest/md5.rb +9 -7
- 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 +2 -0
- data/lib/rack/body_proxy.rb +3 -6
- data/lib/rack/builder.rb +38 -15
- data/lib/rack/cascade.rb +6 -5
- data/lib/rack/chunked.rb +29 -6
- data/lib/rack/common_logger.rb +9 -11
- data/lib/rack/conditional_get.rb +3 -1
- data/lib/rack/config.rb +2 -0
- data/lib/rack/content_length.rb +3 -1
- data/lib/rack/content_type.rb +3 -1
- data/lib/rack/core_ext/regexp.rb +14 -0
- data/lib/rack/deflater.rb +28 -17
- data/lib/rack/directory.rb +17 -14
- data/lib/rack/etag.rb +3 -1
- data/lib/rack/events.rb +5 -3
- data/lib/rack/file.rb +5 -173
- data/lib/rack/files.rb +178 -0
- data/lib/rack/handler/cgi.rb +3 -1
- data/lib/rack/handler/fastcgi.rb +4 -2
- data/lib/rack/handler/lsws.rb +3 -1
- data/lib/rack/handler/scgi.rb +9 -6
- data/lib/rack/handler/thin.rb +3 -1
- data/lib/rack/handler/webrick.rb +4 -2
- data/lib/rack/handler.rb +7 -2
- data/lib/rack/head.rb +2 -0
- data/lib/rack/lint.rb +15 -12
- data/lib/rack/lobster.rb +7 -5
- data/lib/rack/lock.rb +2 -0
- 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 +74 -15
- data/lib/rack/multipart/generator.rb +6 -7
- data/lib/rack/multipart/parser.rb +55 -62
- data/lib/rack/multipart/uploaded_file.rb +2 -0
- data/lib/rack/multipart.rb +6 -3
- data/lib/rack/null_logger.rb +2 -0
- data/lib/rack/query_parser.rb +51 -25
- data/lib/rack/recursive.rb +7 -5
- data/lib/rack/reloader.rb +10 -4
- data/lib/rack/request.rb +79 -26
- data/lib/rack/response.rb +71 -31
- data/lib/rack/rewindable_input.rb +4 -2
- data/lib/rack/runtime.rb +4 -2
- data/lib/rack/sendfile.rb +15 -8
- data/lib/rack/server.rb +88 -16
- data/lib/rack/session/abstract/id.rb +40 -22
- data/lib/rack/session/cookie.rb +10 -9
- data/lib/rack/session/memcache.rb +4 -93
- data/lib/rack/session/pool.rb +4 -2
- data/lib/rack/show_exceptions.rb +15 -9
- data/lib/rack/show_status.rb +4 -2
- data/lib/rack/static.rb +15 -10
- data/lib/rack/tempfile_reaper.rb +2 -0
- data/lib/rack/urlmap.rb +11 -2
- data/lib/rack/utils.rb +64 -93
- data/lib/rack.rb +63 -60
- data/rack.gemspec +17 -7
- metadata +33 -175
- 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_body_proxy.rb
DELETED
@@ -1,85 +0,0 @@
|
|
1
|
-
require 'minitest/autorun'
|
2
|
-
require 'rack/body_proxy'
|
3
|
-
require 'stringio'
|
4
|
-
|
5
|
-
describe Rack::BodyProxy do
|
6
|
-
it 'call each on the wrapped body' do
|
7
|
-
called = false
|
8
|
-
proxy = Rack::BodyProxy.new(['foo']) { }
|
9
|
-
proxy.each do |str|
|
10
|
-
called = true
|
11
|
-
str.must_equal 'foo'
|
12
|
-
end
|
13
|
-
called.must_equal true
|
14
|
-
end
|
15
|
-
|
16
|
-
it 'call close on the wrapped body' do
|
17
|
-
body = StringIO.new
|
18
|
-
proxy = Rack::BodyProxy.new(body) { }
|
19
|
-
proxy.close
|
20
|
-
body.must_be :closed?
|
21
|
-
end
|
22
|
-
|
23
|
-
it 'only call close on the wrapped body if it responds to close' do
|
24
|
-
body = []
|
25
|
-
proxy = Rack::BodyProxy.new(body) { }
|
26
|
-
proxy.close.must_be_nil
|
27
|
-
end
|
28
|
-
|
29
|
-
it 'call the passed block on close' do
|
30
|
-
called = false
|
31
|
-
proxy = Rack::BodyProxy.new([]) { called = true }
|
32
|
-
called.must_equal false
|
33
|
-
proxy.close
|
34
|
-
called.must_equal true
|
35
|
-
end
|
36
|
-
|
37
|
-
it 'call the passed block on close even if there is an exception' do
|
38
|
-
object = Object.new
|
39
|
-
def object.close() raise "No!" end
|
40
|
-
called = false
|
41
|
-
|
42
|
-
begin
|
43
|
-
proxy = Rack::BodyProxy.new(object) { called = true }
|
44
|
-
called.must_equal false
|
45
|
-
proxy.close
|
46
|
-
rescue RuntimeError => e
|
47
|
-
end
|
48
|
-
|
49
|
-
raise "Expected exception to have been raised" unless e
|
50
|
-
called.must_equal true
|
51
|
-
end
|
52
|
-
|
53
|
-
it 'allow multiple arguments in respond_to?' do
|
54
|
-
body = []
|
55
|
-
proxy = Rack::BodyProxy.new(body) { }
|
56
|
-
proxy.respond_to?(:foo, false).must_equal false
|
57
|
-
end
|
58
|
-
|
59
|
-
it 'not respond to :to_ary' do
|
60
|
-
body = Object.new.tap { |o| def o.to_ary() end }
|
61
|
-
body.respond_to?(:to_ary).must_equal true
|
62
|
-
|
63
|
-
proxy = Rack::BodyProxy.new(body) { }
|
64
|
-
proxy.respond_to?(:to_ary).must_equal false
|
65
|
-
proxy.respond_to?("to_ary").must_equal false
|
66
|
-
end
|
67
|
-
|
68
|
-
it 'not close more than one time' do
|
69
|
-
count = 0
|
70
|
-
proxy = Rack::BodyProxy.new([]) { count += 1; raise "Block invoked more than 1 time!" if count > 1 }
|
71
|
-
2.times { proxy.close }
|
72
|
-
count.must_equal 1
|
73
|
-
end
|
74
|
-
|
75
|
-
it 'be closed when the callback is triggered' do
|
76
|
-
closed = false
|
77
|
-
proxy = Rack::BodyProxy.new([]) { closed = proxy.closed? }
|
78
|
-
proxy.close
|
79
|
-
closed.must_equal true
|
80
|
-
end
|
81
|
-
|
82
|
-
it 'provide an #each method' do
|
83
|
-
Rack::BodyProxy.method_defined?(:each).must_equal true
|
84
|
-
end
|
85
|
-
end
|
data/test/spec_builder.rb
DELETED
@@ -1,233 +0,0 @@
|
|
1
|
-
require 'minitest/autorun'
|
2
|
-
require 'rack/builder'
|
3
|
-
require 'rack/lint'
|
4
|
-
require 'rack/mock'
|
5
|
-
require 'rack/show_exceptions'
|
6
|
-
require 'rack/urlmap'
|
7
|
-
|
8
|
-
class NothingMiddleware
|
9
|
-
def initialize(app)
|
10
|
-
@app = app
|
11
|
-
end
|
12
|
-
def call(env)
|
13
|
-
@@env = env
|
14
|
-
response = @app.call(env)
|
15
|
-
response
|
16
|
-
end
|
17
|
-
def self.env
|
18
|
-
@@env
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
describe Rack::Builder do
|
23
|
-
def builder(&block)
|
24
|
-
Rack::Lint.new Rack::Builder.new(&block)
|
25
|
-
end
|
26
|
-
|
27
|
-
def builder_to_app(&block)
|
28
|
-
Rack::Lint.new Rack::Builder.new(&block).to_app
|
29
|
-
end
|
30
|
-
|
31
|
-
it "supports mapping" do
|
32
|
-
app = builder_to_app do
|
33
|
-
map '/' do |outer_env|
|
34
|
-
run lambda { |inner_env| [200, {"Content-Type" => "text/plain"}, ['root']] }
|
35
|
-
end
|
36
|
-
map '/sub' do
|
37
|
-
run lambda { |inner_env| [200, {"Content-Type" => "text/plain"}, ['sub']] }
|
38
|
-
end
|
39
|
-
end
|
40
|
-
Rack::MockRequest.new(app).get("/").body.to_s.must_equal 'root'
|
41
|
-
Rack::MockRequest.new(app).get("/sub").body.to_s.must_equal 'sub'
|
42
|
-
end
|
43
|
-
|
44
|
-
it "doesn't dupe env even when mapping" do
|
45
|
-
app = builder_to_app do
|
46
|
-
use NothingMiddleware
|
47
|
-
map '/' do |outer_env|
|
48
|
-
run lambda { |inner_env|
|
49
|
-
inner_env['new_key'] = 'new_value'
|
50
|
-
[200, {"Content-Type" => "text/plain"}, ['root']]
|
51
|
-
}
|
52
|
-
end
|
53
|
-
end
|
54
|
-
Rack::MockRequest.new(app).get("/").body.to_s.must_equal 'root'
|
55
|
-
NothingMiddleware.env['new_key'].must_equal 'new_value'
|
56
|
-
end
|
57
|
-
|
58
|
-
it "chains apps by default" do
|
59
|
-
app = builder_to_app do
|
60
|
-
use Rack::ShowExceptions
|
61
|
-
run lambda { |env| raise "bzzzt" }
|
62
|
-
end
|
63
|
-
|
64
|
-
Rack::MockRequest.new(app).get("/").must_be :server_error?
|
65
|
-
Rack::MockRequest.new(app).get("/").must_be :server_error?
|
66
|
-
Rack::MockRequest.new(app).get("/").must_be :server_error?
|
67
|
-
end
|
68
|
-
|
69
|
-
it "has implicit #to_app" do
|
70
|
-
app = builder do
|
71
|
-
use Rack::ShowExceptions
|
72
|
-
run lambda { |env| raise "bzzzt" }
|
73
|
-
end
|
74
|
-
|
75
|
-
Rack::MockRequest.new(app).get("/").must_be :server_error?
|
76
|
-
Rack::MockRequest.new(app).get("/").must_be :server_error?
|
77
|
-
Rack::MockRequest.new(app).get("/").must_be :server_error?
|
78
|
-
end
|
79
|
-
|
80
|
-
it "supports blocks on use" do
|
81
|
-
app = builder do
|
82
|
-
use Rack::ShowExceptions
|
83
|
-
use Rack::Auth::Basic do |username, password|
|
84
|
-
'secret' == password
|
85
|
-
end
|
86
|
-
|
87
|
-
run lambda { |env| [200, {"Content-Type" => "text/plain"}, ['Hi Boss']] }
|
88
|
-
end
|
89
|
-
|
90
|
-
response = Rack::MockRequest.new(app).get("/")
|
91
|
-
response.must_be :client_error?
|
92
|
-
response.status.must_equal 401
|
93
|
-
|
94
|
-
# with auth...
|
95
|
-
response = Rack::MockRequest.new(app).get("/",
|
96
|
-
'HTTP_AUTHORIZATION' => 'Basic ' + ["joe:secret"].pack("m*"))
|
97
|
-
response.status.must_equal 200
|
98
|
-
response.body.to_s.must_equal 'Hi Boss'
|
99
|
-
end
|
100
|
-
|
101
|
-
it "has explicit #to_app" do
|
102
|
-
app = builder do
|
103
|
-
use Rack::ShowExceptions
|
104
|
-
run lambda { |env| raise "bzzzt" }
|
105
|
-
end
|
106
|
-
|
107
|
-
Rack::MockRequest.new(app).get("/").must_be :server_error?
|
108
|
-
Rack::MockRequest.new(app).get("/").must_be :server_error?
|
109
|
-
Rack::MockRequest.new(app).get("/").must_be :server_error?
|
110
|
-
end
|
111
|
-
|
112
|
-
it "can mix map and run for endpoints" do
|
113
|
-
app = builder do
|
114
|
-
map '/sub' do
|
115
|
-
run lambda { |inner_env| [200, {"Content-Type" => "text/plain"}, ['sub']] }
|
116
|
-
end
|
117
|
-
run lambda { |inner_env| [200, {"Content-Type" => "text/plain"}, ['root']] }
|
118
|
-
end
|
119
|
-
|
120
|
-
Rack::MockRequest.new(app).get("/").body.to_s.must_equal 'root'
|
121
|
-
Rack::MockRequest.new(app).get("/sub").body.to_s.must_equal 'sub'
|
122
|
-
end
|
123
|
-
|
124
|
-
it "accepts middleware-only map blocks" do
|
125
|
-
app = builder do
|
126
|
-
map('/foo') { use Rack::ShowExceptions }
|
127
|
-
run lambda { |env| raise "bzzzt" }
|
128
|
-
end
|
129
|
-
|
130
|
-
proc { Rack::MockRequest.new(app).get("/") }.must_raise(RuntimeError)
|
131
|
-
Rack::MockRequest.new(app).get("/foo").must_be :server_error?
|
132
|
-
end
|
133
|
-
|
134
|
-
it "yields the generated app to a block for warmup" do
|
135
|
-
warmed_up_app = nil
|
136
|
-
|
137
|
-
app = Rack::Builder.new do
|
138
|
-
warmup { |a| warmed_up_app = a }
|
139
|
-
run lambda { |env| [200, {}, []] }
|
140
|
-
end.to_app
|
141
|
-
|
142
|
-
warmed_up_app.must_equal app
|
143
|
-
end
|
144
|
-
|
145
|
-
it "initialize apps once" do
|
146
|
-
app = builder do
|
147
|
-
class AppClass
|
148
|
-
def initialize
|
149
|
-
@called = 0
|
150
|
-
end
|
151
|
-
def call(env)
|
152
|
-
raise "bzzzt" if @called > 0
|
153
|
-
@called += 1
|
154
|
-
[200, {'Content-Type' => 'text/plain'}, ['OK']]
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
use Rack::ShowExceptions
|
159
|
-
run AppClass.new
|
160
|
-
end
|
161
|
-
|
162
|
-
Rack::MockRequest.new(app).get("/").status.must_equal 200
|
163
|
-
Rack::MockRequest.new(app).get("/").must_be :server_error?
|
164
|
-
end
|
165
|
-
|
166
|
-
it "allows use after run" do
|
167
|
-
app = builder do
|
168
|
-
run lambda { |env| raise "bzzzt" }
|
169
|
-
use Rack::ShowExceptions
|
170
|
-
end
|
171
|
-
|
172
|
-
Rack::MockRequest.new(app).get("/").must_be :server_error?
|
173
|
-
Rack::MockRequest.new(app).get("/").must_be :server_error?
|
174
|
-
Rack::MockRequest.new(app).get("/").must_be :server_error?
|
175
|
-
end
|
176
|
-
|
177
|
-
it 'complains about a missing run' do
|
178
|
-
proc do
|
179
|
-
Rack::Lint.new Rack::Builder.app { use Rack::ShowExceptions }
|
180
|
-
end.must_raise(RuntimeError)
|
181
|
-
end
|
182
|
-
|
183
|
-
describe "parse_file" do
|
184
|
-
def config_file(name)
|
185
|
-
File.join(File.dirname(__FILE__), 'builder', name)
|
186
|
-
end
|
187
|
-
|
188
|
-
it "parses commented options" do
|
189
|
-
app, options = Rack::Builder.parse_file config_file('options.ru')
|
190
|
-
options[:debug].must_equal true
|
191
|
-
options[:environment].must_equal 'test'
|
192
|
-
options[:Port].must_equal '2929'
|
193
|
-
Rack::MockRequest.new(app).get("/").body.to_s.must_equal 'OK'
|
194
|
-
end
|
195
|
-
|
196
|
-
it "removes __END__ before evaluating app" do
|
197
|
-
app, _ = Rack::Builder.parse_file config_file('end.ru')
|
198
|
-
Rack::MockRequest.new(app).get("/").body.to_s.must_equal 'OK'
|
199
|
-
end
|
200
|
-
|
201
|
-
it "supports multi-line comments" do
|
202
|
-
proc, env = Rack::Builder.parse_file(config_file('comment.ru'))
|
203
|
-
proc.must_be_kind_of Proc
|
204
|
-
env.must_equal({})
|
205
|
-
end
|
206
|
-
|
207
|
-
it "requires anything not ending in .ru" do
|
208
|
-
$: << File.dirname(__FILE__)
|
209
|
-
app, * = Rack::Builder.parse_file 'builder/anything'
|
210
|
-
Rack::MockRequest.new(app).get("/").body.to_s.must_equal 'OK'
|
211
|
-
$:.pop
|
212
|
-
end
|
213
|
-
|
214
|
-
it 'requires an_underscore_app not ending in .ru' do
|
215
|
-
$: << File.dirname(__FILE__)
|
216
|
-
app, * = Rack::Builder.parse_file 'builder/an_underscore_app'
|
217
|
-
Rack::MockRequest.new(app).get('/').body.to_s.must_equal 'OK'
|
218
|
-
$:.pop
|
219
|
-
end
|
220
|
-
|
221
|
-
it "sets __LINE__ correctly" do
|
222
|
-
app, _ = Rack::Builder.parse_file config_file('line.ru')
|
223
|
-
Rack::MockRequest.new(app).get("/").body.to_s.must_equal '1'
|
224
|
-
end
|
225
|
-
end
|
226
|
-
|
227
|
-
describe 'new_from_string' do
|
228
|
-
it "builds a rack app from string" do
|
229
|
-
app, = Rack::Builder.new_from_string "run lambda{|env| [200, {'Content-Type' => 'text/plane'}, ['OK']] }"
|
230
|
-
Rack::MockRequest.new(app).get("/").body.to_s.must_equal 'OK'
|
231
|
-
end
|
232
|
-
end
|
233
|
-
end
|
data/test/spec_cascade.rb
DELETED
@@ -1,63 +0,0 @@
|
|
1
|
-
require 'minitest/autorun'
|
2
|
-
require 'rack'
|
3
|
-
require 'rack/cascade'
|
4
|
-
require 'rack/file'
|
5
|
-
require 'rack/lint'
|
6
|
-
require 'rack/urlmap'
|
7
|
-
require 'rack/mock'
|
8
|
-
|
9
|
-
describe Rack::Cascade do
|
10
|
-
def cascade(*args)
|
11
|
-
Rack::Lint.new Rack::Cascade.new(*args)
|
12
|
-
end
|
13
|
-
|
14
|
-
docroot = File.expand_path(File.dirname(__FILE__))
|
15
|
-
app1 = Rack::File.new(docroot)
|
16
|
-
|
17
|
-
app2 = Rack::URLMap.new("/crash" => lambda { |env| raise "boom" })
|
18
|
-
|
19
|
-
app3 = Rack::URLMap.new("/foo" => lambda { |env|
|
20
|
-
[200, { "Content-Type" => "text/plain"}, [""]]})
|
21
|
-
|
22
|
-
it "dispatch onward on 404 and 405 by default" do
|
23
|
-
cascade = cascade([app1, app2, app3])
|
24
|
-
Rack::MockRequest.new(cascade).get("/cgi/test").must_be :ok?
|
25
|
-
Rack::MockRequest.new(cascade).get("/foo").must_be :ok?
|
26
|
-
Rack::MockRequest.new(cascade).get("/toobad").must_be :not_found?
|
27
|
-
Rack::MockRequest.new(cascade).get("/cgi/../..").must_be :client_error?
|
28
|
-
|
29
|
-
# Put is not allowed by Rack::File so it'll 405.
|
30
|
-
Rack::MockRequest.new(cascade).put("/foo").must_be :ok?
|
31
|
-
end
|
32
|
-
|
33
|
-
it "dispatch onward on whatever is passed" do
|
34
|
-
cascade = cascade([app1, app2, app3], [404, 403])
|
35
|
-
Rack::MockRequest.new(cascade).get("/cgi/../bla").must_be :not_found?
|
36
|
-
end
|
37
|
-
|
38
|
-
it "return 404 if empty" do
|
39
|
-
Rack::MockRequest.new(cascade([])).get('/').must_be :not_found?
|
40
|
-
end
|
41
|
-
|
42
|
-
it "append new app" do
|
43
|
-
cascade = Rack::Cascade.new([], [404, 403])
|
44
|
-
Rack::MockRequest.new(cascade).get('/').must_be :not_found?
|
45
|
-
cascade << app2
|
46
|
-
Rack::MockRequest.new(cascade).get('/cgi/test').must_be :not_found?
|
47
|
-
Rack::MockRequest.new(cascade).get('/cgi/../bla').must_be :not_found?
|
48
|
-
cascade << app1
|
49
|
-
Rack::MockRequest.new(cascade).get('/cgi/test').must_be :ok?
|
50
|
-
Rack::MockRequest.new(cascade).get('/cgi/../..').must_be :client_error?
|
51
|
-
Rack::MockRequest.new(cascade).get('/foo').must_be :not_found?
|
52
|
-
cascade << app3
|
53
|
-
Rack::MockRequest.new(cascade).get('/foo').must_be :ok?
|
54
|
-
end
|
55
|
-
|
56
|
-
it "close the body on cascade" do
|
57
|
-
body = StringIO.new
|
58
|
-
closer = lambda { |env| [404, {}, body] }
|
59
|
-
cascade = Rack::Cascade.new([closer, app3], [404])
|
60
|
-
Rack::MockRequest.new(cascade).get("/foo").must_be :ok?
|
61
|
-
body.must_be :closed?
|
62
|
-
end
|
63
|
-
end
|
data/test/spec_cgi.rb
DELETED
@@ -1,84 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
if defined? LIGHTTPD_PID
|
4
|
-
|
5
|
-
require File.expand_path('../testrequest', __FILE__)
|
6
|
-
require 'rack/handler/cgi'
|
7
|
-
|
8
|
-
describe Rack::Handler::CGI do
|
9
|
-
include TestRequest::Helpers
|
10
|
-
|
11
|
-
before do
|
12
|
-
@host = '127.0.0.1'
|
13
|
-
@port = 9203
|
14
|
-
end
|
15
|
-
|
16
|
-
if `which lighttpd` && !$?.success?
|
17
|
-
raise "lighttpd not found"
|
18
|
-
end
|
19
|
-
|
20
|
-
it "respond" do
|
21
|
-
sleep 1
|
22
|
-
GET("/test")
|
23
|
-
response.wont_be :nil?
|
24
|
-
end
|
25
|
-
|
26
|
-
it "be a lighttpd" do
|
27
|
-
GET("/test")
|
28
|
-
status.must_equal 200
|
29
|
-
response["SERVER_SOFTWARE"].must_match(/lighttpd/)
|
30
|
-
response["HTTP_VERSION"].must_equal "HTTP/1.1"
|
31
|
-
response["SERVER_PROTOCOL"].must_equal "HTTP/1.1"
|
32
|
-
response["SERVER_PORT"].must_equal @port.to_s
|
33
|
-
response["SERVER_NAME"].must_equal @host
|
34
|
-
end
|
35
|
-
|
36
|
-
it "have rack headers" do
|
37
|
-
GET("/test")
|
38
|
-
response["rack.version"].must_equal [1,3]
|
39
|
-
assert_equal false, response["rack.multithread"]
|
40
|
-
assert_equal true, response["rack.multiprocess"]
|
41
|
-
assert_equal true, response["rack.run_once"]
|
42
|
-
end
|
43
|
-
|
44
|
-
it "have CGI headers on GET" do
|
45
|
-
GET("/test")
|
46
|
-
response["REQUEST_METHOD"].must_equal "GET"
|
47
|
-
response["SCRIPT_NAME"].must_equal "/test"
|
48
|
-
response["REQUEST_PATH"].must_equal "/"
|
49
|
-
response["PATH_INFO"].must_be_nil
|
50
|
-
response["QUERY_STRING"].must_equal ""
|
51
|
-
response["test.postdata"].must_equal ""
|
52
|
-
|
53
|
-
GET("/test/foo?quux=1")
|
54
|
-
response["REQUEST_METHOD"].must_equal "GET"
|
55
|
-
response["SCRIPT_NAME"].must_equal "/test"
|
56
|
-
response["REQUEST_PATH"].must_equal "/"
|
57
|
-
response["PATH_INFO"].must_equal "/foo"
|
58
|
-
response["QUERY_STRING"].must_equal "quux=1"
|
59
|
-
end
|
60
|
-
|
61
|
-
it "have CGI headers on POST" do
|
62
|
-
POST("/test", {"rack-form-data" => "23"}, {'X-test-header' => '42'})
|
63
|
-
status.must_equal 200
|
64
|
-
response["REQUEST_METHOD"].must_equal "POST"
|
65
|
-
response["SCRIPT_NAME"].must_equal "/test"
|
66
|
-
response["REQUEST_PATH"].must_equal "/"
|
67
|
-
response["QUERY_STRING"].must_equal ""
|
68
|
-
response["HTTP_X_TEST_HEADER"].must_equal "42"
|
69
|
-
response["test.postdata"].must_equal "rack-form-data=23"
|
70
|
-
end
|
71
|
-
|
72
|
-
it "support HTTP auth" do
|
73
|
-
GET("/test", {:user => "ruth", :passwd => "secret"})
|
74
|
-
response["HTTP_AUTHORIZATION"].must_equal "Basic cnV0aDpzZWNyZXQ="
|
75
|
-
end
|
76
|
-
|
77
|
-
it "set status" do
|
78
|
-
GET("/test?secret")
|
79
|
-
status.must_equal 403
|
80
|
-
response["rack.url_scheme"].must_equal "http"
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
end # if defined? LIGHTTPD_PID
|
data/test/spec_chunked.rb
DELETED
@@ -1,103 +0,0 @@
|
|
1
|
-
require 'minitest/autorun'
|
2
|
-
require 'rack/chunked'
|
3
|
-
require 'rack/lint'
|
4
|
-
require 'rack/mock'
|
5
|
-
|
6
|
-
describe Rack::Chunked do
|
7
|
-
def chunked(app)
|
8
|
-
proc do |env|
|
9
|
-
app = Rack::Chunked.new(app)
|
10
|
-
response = Rack::Lint.new(app).call(env)
|
11
|
-
# we want to use body like an array, but it only has #each
|
12
|
-
response[2] = response[2].to_enum.to_a
|
13
|
-
response
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
before do
|
18
|
-
@env = Rack::MockRequest.
|
19
|
-
env_for('/', 'HTTP_VERSION' => '1.1', 'REQUEST_METHOD' => 'GET')
|
20
|
-
end
|
21
|
-
|
22
|
-
it 'chunk responses with no Content-Length' do
|
23
|
-
app = lambda { |env| [200, {"Content-Type" => "text/plain"}, ['Hello', ' ', 'World!']] }
|
24
|
-
response = Rack::MockResponse.new(*chunked(app).call(@env))
|
25
|
-
response.headers.wont_include 'Content-Length'
|
26
|
-
response.headers['Transfer-Encoding'].must_equal 'chunked'
|
27
|
-
response.body.must_equal "5\r\nHello\r\n1\r\n \r\n6\r\nWorld!\r\n0\r\n\r\n"
|
28
|
-
end
|
29
|
-
|
30
|
-
it 'chunks empty bodies properly' do
|
31
|
-
app = lambda { |env| [200, {"Content-Type" => "text/plain"}, []] }
|
32
|
-
response = Rack::MockResponse.new(*chunked(app).call(@env))
|
33
|
-
response.headers.wont_include 'Content-Length'
|
34
|
-
response.headers['Transfer-Encoding'].must_equal 'chunked'
|
35
|
-
response.body.must_equal "0\r\n\r\n"
|
36
|
-
end
|
37
|
-
|
38
|
-
it 'chunks encoded bodies properly' do
|
39
|
-
body = ["\uFFFEHello", " ", "World"].map {|t| t.encode("UTF-16LE") }
|
40
|
-
app = lambda { |env| [200, {"Content-Type" => "text/plain"}, body] }
|
41
|
-
response = Rack::MockResponse.new(*chunked(app).call(@env))
|
42
|
-
response.headers.wont_include 'Content-Length'
|
43
|
-
response.headers['Transfer-Encoding'].must_equal 'chunked'
|
44
|
-
response.body.encoding.to_s.must_equal "ASCII-8BIT"
|
45
|
-
response.body.must_equal "c\r\n\xFE\xFFH\x00e\x00l\x00l\x00o\x00\r\n2\r\n \x00\r\na\r\nW\x00o\x00r\x00l\x00d\x00\r\n0\r\n\r\n".force_encoding("BINARY")
|
46
|
-
response.body.must_equal "c\r\n\xFE\xFFH\x00e\x00l\x00l\x00o\x00\r\n2\r\n \x00\r\na\r\nW\x00o\x00r\x00l\x00d\x00\r\n0\r\n\r\n".force_encoding(Encoding::BINARY)
|
47
|
-
end
|
48
|
-
|
49
|
-
it 'not modify response when Content-Length header present' do
|
50
|
-
app = lambda { |env|
|
51
|
-
[200, {"Content-Type" => "text/plain", 'Content-Length'=>'12'}, ['Hello', ' ', 'World!']]
|
52
|
-
}
|
53
|
-
status, headers, body = chunked(app).call(@env)
|
54
|
-
status.must_equal 200
|
55
|
-
headers.wont_include 'Transfer-Encoding'
|
56
|
-
headers.must_include 'Content-Length'
|
57
|
-
body.join.must_equal 'Hello World!'
|
58
|
-
end
|
59
|
-
|
60
|
-
it 'not modify response when client is HTTP/1.0' do
|
61
|
-
app = lambda { |env| [200, {"Content-Type" => "text/plain"}, ['Hello', ' ', 'World!']] }
|
62
|
-
@env['HTTP_VERSION'] = 'HTTP/1.0'
|
63
|
-
status, headers, body = chunked(app).call(@env)
|
64
|
-
status.must_equal 200
|
65
|
-
headers.wont_include 'Transfer-Encoding'
|
66
|
-
body.join.must_equal 'Hello World!'
|
67
|
-
end
|
68
|
-
|
69
|
-
it 'not modify response when client is ancient, pre-HTTP/1.0' do
|
70
|
-
app = lambda { |env| [200, {"Content-Type" => "text/plain"}, ['Hello', ' ', 'World!']] }
|
71
|
-
check = lambda do
|
72
|
-
status, headers, body = chunked(app).call(@env.dup)
|
73
|
-
status.must_equal 200
|
74
|
-
headers.wont_include 'Transfer-Encoding'
|
75
|
-
body.join.must_equal 'Hello World!'
|
76
|
-
end
|
77
|
-
|
78
|
-
@env.delete('HTTP_VERSION') # unicorn will do this on pre-HTTP/1.0 requests
|
79
|
-
check.call
|
80
|
-
|
81
|
-
@env['HTTP_VERSION'] = 'HTTP/0.9' # not sure if this happens in practice
|
82
|
-
check.call
|
83
|
-
end
|
84
|
-
|
85
|
-
it 'not modify response when Transfer-Encoding header already present' do
|
86
|
-
app = lambda { |env|
|
87
|
-
[200, {"Content-Type" => "text/plain", 'Transfer-Encoding' => 'identity'}, ['Hello', ' ', 'World!']]
|
88
|
-
}
|
89
|
-
status, headers, body = chunked(app).call(@env)
|
90
|
-
status.must_equal 200
|
91
|
-
headers['Transfer-Encoding'].must_equal 'identity'
|
92
|
-
body.join.must_equal 'Hello World!'
|
93
|
-
end
|
94
|
-
|
95
|
-
[100, 204, 304].each do |status_code|
|
96
|
-
it "not modify response when status code is #{status_code}" do
|
97
|
-
app = lambda { |env| [status_code, {}, []] }
|
98
|
-
status, headers, _ = chunked(app).call(@env)
|
99
|
-
status.must_equal status_code
|
100
|
-
headers.wont_include 'Transfer-Encoding'
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
data/test/spec_common_logger.rb
DELETED
@@ -1,107 +0,0 @@
|
|
1
|
-
require 'minitest/autorun'
|
2
|
-
require 'rack/common_logger'
|
3
|
-
require 'rack/lint'
|
4
|
-
require 'rack/mock'
|
5
|
-
|
6
|
-
require 'logger'
|
7
|
-
|
8
|
-
describe Rack::CommonLogger do
|
9
|
-
obj = 'foobar'
|
10
|
-
length = obj.size
|
11
|
-
|
12
|
-
app = Rack::Lint.new lambda { |env|
|
13
|
-
[200,
|
14
|
-
{"Content-Type" => "text/html", "Content-Length" => length.to_s},
|
15
|
-
[obj]]}
|
16
|
-
app_without_length = Rack::Lint.new lambda { |env|
|
17
|
-
[200,
|
18
|
-
{"Content-Type" => "text/html"},
|
19
|
-
[]]}
|
20
|
-
app_with_zero_length = Rack::Lint.new lambda { |env|
|
21
|
-
[200,
|
22
|
-
{"Content-Type" => "text/html", "Content-Length" => "0"},
|
23
|
-
[]]}
|
24
|
-
app_without_lint = lambda { |env|
|
25
|
-
[200,
|
26
|
-
{ "content-type" => "text/html", "content-length" => length.to_s },
|
27
|
-
[obj]]}
|
28
|
-
|
29
|
-
it "log to rack.errors by default" do
|
30
|
-
res = Rack::MockRequest.new(Rack::CommonLogger.new(app)).get("/")
|
31
|
-
|
32
|
-
res.errors.wont_be :empty?
|
33
|
-
res.errors.must_match(/"GET \/ " 200 #{length} /)
|
34
|
-
end
|
35
|
-
|
36
|
-
it "log to anything with +write+" do
|
37
|
-
log = StringIO.new
|
38
|
-
Rack::MockRequest.new(Rack::CommonLogger.new(app, log)).get("/")
|
39
|
-
|
40
|
-
log.string.must_match(/"GET \/ " 200 #{length} /)
|
41
|
-
end
|
42
|
-
|
43
|
-
it "work with standartd library logger" do
|
44
|
-
logdev = StringIO.new
|
45
|
-
log = Logger.new(logdev)
|
46
|
-
Rack::MockRequest.new(Rack::CommonLogger.new(app, log)).get("/")
|
47
|
-
|
48
|
-
logdev.string.must_match(/"GET \/ " 200 #{length} /)
|
49
|
-
end
|
50
|
-
|
51
|
-
it "log - content length if header is missing" do
|
52
|
-
res = Rack::MockRequest.new(Rack::CommonLogger.new(app_without_length)).get("/")
|
53
|
-
|
54
|
-
res.errors.wont_be :empty?
|
55
|
-
res.errors.must_match(/"GET \/ " 200 - /)
|
56
|
-
end
|
57
|
-
|
58
|
-
it "log - content length if header is zero" do
|
59
|
-
res = Rack::MockRequest.new(Rack::CommonLogger.new(app_with_zero_length)).get("/")
|
60
|
-
|
61
|
-
res.errors.wont_be :empty?
|
62
|
-
res.errors.must_match(/"GET \/ " 200 - /)
|
63
|
-
end
|
64
|
-
|
65
|
-
def with_mock_time(t = 0)
|
66
|
-
mc = class << Time; self; end
|
67
|
-
mc.send :alias_method, :old_now, :now
|
68
|
-
mc.send :define_method, :now do
|
69
|
-
at(t)
|
70
|
-
end
|
71
|
-
yield
|
72
|
-
ensure
|
73
|
-
mc.send :undef_method, :now
|
74
|
-
mc.send :alias_method, :now, :old_now
|
75
|
-
end
|
76
|
-
|
77
|
-
it "log in common log format" do
|
78
|
-
log = StringIO.new
|
79
|
-
with_mock_time do
|
80
|
-
Rack::MockRequest.new(Rack::CommonLogger.new(app, log)).get("/")
|
81
|
-
end
|
82
|
-
|
83
|
-
md = /- - - \[([^\]]+)\] "(\w+) \/ " (\d{3}) \d+ ([\d\.]+)/.match(log.string)
|
84
|
-
md.wont_equal nil
|
85
|
-
time, method, status, duration = *md.captures
|
86
|
-
time.must_equal Time.at(0).strftime("%d/%b/%Y:%H:%M:%S %z")
|
87
|
-
method.must_equal "GET"
|
88
|
-
status.must_equal "200"
|
89
|
-
(0..1).must_include duration.to_f
|
90
|
-
end
|
91
|
-
|
92
|
-
it "escapes non printable characters except newline" do
|
93
|
-
logdev = StringIO.new
|
94
|
-
log = Logger.new(logdev)
|
95
|
-
Rack::MockRequest.new(Rack::CommonLogger.new(app_without_lint, log)).request("GET\b", "/hello")
|
96
|
-
|
97
|
-
logdev.string.must_match(/GET\\x8 \/hello/)
|
98
|
-
end
|
99
|
-
|
100
|
-
def length
|
101
|
-
123
|
102
|
-
end
|
103
|
-
|
104
|
-
def self.obj
|
105
|
-
"hello world"
|
106
|
-
end
|
107
|
-
end
|