rack 1.6.13 → 2.0.9
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/COPYING +1 -1
- data/HISTORY.md +138 -8
- data/README.rdoc +18 -28
- data/Rakefile +6 -14
- data/SPEC +3 -3
- data/contrib/rack_logo.svg +164 -111
- data/example/protectedlobster.rb +1 -1
- data/example/protectedlobster.ru +1 -1
- data/lib/rack/auth/abstract/request.rb +5 -1
- data/lib/rack/auth/digest/params.rb +2 -3
- data/lib/rack/auth/digest/request.rb +1 -1
- data/lib/rack/body_proxy.rb +14 -9
- data/lib/rack/builder.rb +3 -3
- data/lib/rack/chunked.rb +5 -5
- data/lib/rack/{commonlogger.rb → common_logger.rb} +3 -3
- data/lib/rack/content_length.rb +2 -2
- data/lib/rack/deflater.rb +4 -39
- data/lib/rack/directory.rb +66 -54
- data/lib/rack/etag.rb +5 -4
- data/lib/rack/events.rb +154 -0
- data/lib/rack/file.rb +64 -40
- data/lib/rack/handler/cgi.rb +15 -16
- data/lib/rack/handler/fastcgi.rb +13 -14
- data/lib/rack/handler/lsws.rb +11 -11
- data/lib/rack/handler/scgi.rb +15 -15
- data/lib/rack/handler/thin.rb +3 -0
- data/lib/rack/handler/webrick.rb +24 -26
- data/lib/rack/handler.rb +3 -25
- data/lib/rack/head.rb +15 -17
- data/lib/rack/lint.rb +40 -40
- data/lib/rack/lobster.rb +1 -1
- data/lib/rack/lock.rb +15 -10
- data/lib/rack/logger.rb +2 -2
- data/lib/rack/media_type.rb +38 -0
- data/lib/rack/{methodoverride.rb → method_override.rb} +6 -6
- data/lib/rack/mime.rb +18 -5
- data/lib/rack/mock.rb +36 -54
- data/lib/rack/multipart/generator.rb +5 -5
- data/lib/rack/multipart/parser.rb +270 -157
- data/lib/rack/multipart/uploaded_file.rb +1 -2
- data/lib/rack/multipart.rb +35 -6
- data/lib/rack/{nulllogger.rb → null_logger.rb} +1 -1
- data/lib/rack/query_parser.rb +192 -0
- data/lib/rack/recursive.rb +8 -8
- data/lib/rack/request.rb +394 -305
- data/lib/rack/response.rb +130 -57
- data/lib/rack/rewindable_input.rb +1 -12
- data/lib/rack/runtime.rb +10 -18
- data/lib/rack/sendfile.rb +5 -7
- data/lib/rack/server.rb +30 -23
- data/lib/rack/session/abstract/id.rb +110 -75
- data/lib/rack/session/cookie.rb +24 -17
- data/lib/rack/session/memcache.rb +9 -9
- data/lib/rack/session/pool.rb +8 -8
- data/lib/rack/show_exceptions.rb +386 -0
- data/lib/rack/{showstatus.rb → show_status.rb} +3 -3
- data/lib/rack/static.rb +30 -5
- data/lib/rack/tempfile_reaper.rb +2 -2
- data/lib/rack/urlmap.rb +15 -14
- data/lib/rack/utils.rb +138 -211
- data/lib/rack.rb +70 -21
- data/rack.gemspec +10 -9
- data/test/builder/an_underscore_app.rb +5 -0
- data/test/builder/options.ru +1 -1
- data/test/cgi/test.fcgi +1 -0
- data/test/cgi/test.gz +0 -0
- data/test/helper.rb +34 -0
- data/test/multipart/filename_with_encoded_words +7 -0
- data/test/multipart/filename_with_single_quote +7 -0
- data/test/multipart/quoted +15 -0
- data/test/multipart/rack-logo.png +0 -0
- data/test/multipart/unity3d_wwwform +11 -0
- data/test/registering_handler/rack/handler/registering_myself.rb +1 -1
- data/test/spec_auth_basic.rb +27 -19
- data/test/spec_auth_digest.rb +47 -46
- data/test/spec_body_proxy.rb +27 -27
- data/test/spec_builder.rb +51 -41
- data/test/spec_cascade.rb +24 -22
- data/test/spec_cgi.rb +49 -67
- data/test/spec_chunked.rb +37 -35
- data/test/{spec_commonlogger.rb → spec_common_logger.rb} +23 -21
- data/test/{spec_conditionalget.rb → spec_conditional_get.rb} +29 -28
- data/test/spec_config.rb +3 -2
- data/test/spec_content_length.rb +18 -17
- data/test/spec_content_type.rb +13 -12
- data/test/spec_deflater.rb +85 -49
- data/test/spec_directory.rb +87 -27
- data/test/spec_etag.rb +32 -31
- data/test/spec_events.rb +133 -0
- data/test/spec_fastcgi.rb +50 -72
- data/test/spec_file.rb +120 -77
- data/test/spec_handler.rb +19 -34
- data/test/spec_head.rb +15 -14
- data/test/spec_lint.rb +164 -199
- data/test/spec_lobster.rb +24 -23
- data/test/spec_lock.rb +79 -39
- data/test/spec_logger.rb +4 -3
- data/test/spec_media_type.rb +42 -0
- data/test/{spec_methodoverride.rb → spec_method_override.rb} +34 -35
- data/test/spec_mime.rb +19 -19
- data/test/spec_mock.rb +206 -144
- data/test/spec_multipart.rb +322 -200
- data/test/{spec_nulllogger.rb → spec_null_logger.rb} +5 -4
- data/test/spec_recursive.rb +17 -14
- data/test/spec_request.rb +780 -605
- data/test/spec_response.rb +233 -112
- data/test/spec_rewindable_input.rb +50 -40
- data/test/spec_runtime.rb +11 -10
- data/test/spec_sendfile.rb +30 -35
- data/test/spec_server.rb +78 -52
- data/test/spec_session_abstract_id.rb +11 -33
- data/test/spec_session_abstract_session_hash.rb +45 -0
- data/test/spec_session_cookie.rb +99 -67
- data/test/spec_session_memcache.rb +67 -68
- data/test/spec_session_pool.rb +52 -51
- data/test/{spec_showexceptions.rb → spec_show_exceptions.rb} +23 -28
- data/test/{spec_showstatus.rb → spec_show_status.rb} +36 -35
- data/test/spec_static.rb +71 -32
- data/test/spec_tempfile_reaper.rb +11 -10
- data/test/spec_thin.rb +55 -50
- data/test/spec_urlmap.rb +79 -78
- data/test/spec_utils.rb +441 -346
- data/test/spec_version.rb +2 -8
- data/test/spec_webrick.rb +93 -71
- data/test/static/foo.html +1 -0
- data/test/testrequest.rb +1 -1
- data/test/unregistered_handler/rack/handler/unregistered.rb +1 -1
- data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +1 -1
- metadata +57 -36
- data/KNOWN-ISSUES +0 -44
- 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 -106
- data/lib/rack/handler/swiftiplied_mongrel.rb +0 -8
- data/lib/rack/showexceptions.rb +0 -387
- data/lib/rack/utils/okjson.rb +0 -600
- data/test/spec_mongrel.rb +0 -182
- /data/lib/rack/{conditionalget.rb → conditional_get.rb} +0 -0
data/test/spec_builder.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
+
require 'minitest/autorun'
|
1
2
|
require 'rack/builder'
|
2
3
|
require 'rack/lint'
|
3
4
|
require 'rack/mock'
|
4
|
-
require 'rack/
|
5
|
+
require 'rack/show_exceptions'
|
5
6
|
require 'rack/urlmap'
|
6
7
|
|
7
8
|
class NothingMiddleware
|
@@ -22,11 +23,11 @@ describe Rack::Builder do
|
|
22
23
|
def builder(&block)
|
23
24
|
Rack::Lint.new Rack::Builder.new(&block)
|
24
25
|
end
|
25
|
-
|
26
|
+
|
26
27
|
def builder_to_app(&block)
|
27
28
|
Rack::Lint.new Rack::Builder.new(&block).to_app
|
28
29
|
end
|
29
|
-
|
30
|
+
|
30
31
|
it "supports mapping" do
|
31
32
|
app = builder_to_app do
|
32
33
|
map '/' do |outer_env|
|
@@ -36,8 +37,8 @@ describe Rack::Builder do
|
|
36
37
|
run lambda { |inner_env| [200, {"Content-Type" => "text/plain"}, ['sub']] }
|
37
38
|
end
|
38
39
|
end
|
39
|
-
Rack::MockRequest.new(app).get("/").body.to_s.
|
40
|
-
Rack::MockRequest.new(app).get("/sub").body.to_s.
|
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'
|
41
42
|
end
|
42
43
|
|
43
44
|
it "doesn't dupe env even when mapping" do
|
@@ -50,8 +51,8 @@ describe Rack::Builder do
|
|
50
51
|
}
|
51
52
|
end
|
52
53
|
end
|
53
|
-
Rack::MockRequest.new(app).get("/").body.to_s.
|
54
|
-
NothingMiddleware.env['new_key'].
|
54
|
+
Rack::MockRequest.new(app).get("/").body.to_s.must_equal 'root'
|
55
|
+
NothingMiddleware.env['new_key'].must_equal 'new_value'
|
55
56
|
end
|
56
57
|
|
57
58
|
it "chains apps by default" do
|
@@ -60,9 +61,9 @@ describe Rack::Builder do
|
|
60
61
|
run lambda { |env| raise "bzzzt" }
|
61
62
|
end
|
62
63
|
|
63
|
-
Rack::MockRequest.new(app).get("/").
|
64
|
-
Rack::MockRequest.new(app).get("/").
|
65
|
-
Rack::MockRequest.new(app).get("/").
|
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?
|
66
67
|
end
|
67
68
|
|
68
69
|
it "has implicit #to_app" do
|
@@ -71,9 +72,9 @@ describe Rack::Builder do
|
|
71
72
|
run lambda { |env| raise "bzzzt" }
|
72
73
|
end
|
73
74
|
|
74
|
-
Rack::MockRequest.new(app).get("/").
|
75
|
-
Rack::MockRequest.new(app).get("/").
|
76
|
-
Rack::MockRequest.new(app).get("/").
|
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?
|
77
78
|
end
|
78
79
|
|
79
80
|
it "supports blocks on use" do
|
@@ -87,14 +88,14 @@ describe Rack::Builder do
|
|
87
88
|
end
|
88
89
|
|
89
90
|
response = Rack::MockRequest.new(app).get("/")
|
90
|
-
response.
|
91
|
-
response.status.
|
91
|
+
response.must_be :client_error?
|
92
|
+
response.status.must_equal 401
|
92
93
|
|
93
94
|
# with auth...
|
94
95
|
response = Rack::MockRequest.new(app).get("/",
|
95
96
|
'HTTP_AUTHORIZATION' => 'Basic ' + ["joe:secret"].pack("m*"))
|
96
|
-
response.status.
|
97
|
-
response.body.to_s.
|
97
|
+
response.status.must_equal 200
|
98
|
+
response.body.to_s.must_equal 'Hi Boss'
|
98
99
|
end
|
99
100
|
|
100
101
|
it "has explicit #to_app" do
|
@@ -103,9 +104,9 @@ describe Rack::Builder do
|
|
103
104
|
run lambda { |env| raise "bzzzt" }
|
104
105
|
end
|
105
106
|
|
106
|
-
Rack::MockRequest.new(app).get("/").
|
107
|
-
Rack::MockRequest.new(app).get("/").
|
108
|
-
Rack::MockRequest.new(app).get("/").
|
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?
|
109
110
|
end
|
110
111
|
|
111
112
|
it "can mix map and run for endpoints" do
|
@@ -116,8 +117,8 @@ describe Rack::Builder do
|
|
116
117
|
run lambda { |inner_env| [200, {"Content-Type" => "text/plain"}, ['root']] }
|
117
118
|
end
|
118
119
|
|
119
|
-
Rack::MockRequest.new(app).get("/").body.to_s.
|
120
|
-
Rack::MockRequest.new(app).get("/sub").body.to_s.
|
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'
|
121
122
|
end
|
122
123
|
|
123
124
|
it "accepts middleware-only map blocks" do
|
@@ -126,8 +127,8 @@ describe Rack::Builder do
|
|
126
127
|
run lambda { |env| raise "bzzzt" }
|
127
128
|
end
|
128
129
|
|
129
|
-
proc { Rack::MockRequest.new(app).get("/") }.
|
130
|
-
Rack::MockRequest.new(app).get("/foo").
|
130
|
+
proc { Rack::MockRequest.new(app).get("/") }.must_raise(RuntimeError)
|
131
|
+
Rack::MockRequest.new(app).get("/foo").must_be :server_error?
|
131
132
|
end
|
132
133
|
|
133
134
|
it "yields the generated app to a block for warmup" do
|
@@ -138,10 +139,10 @@ describe Rack::Builder do
|
|
138
139
|
run lambda { |env| [200, {}, []] }
|
139
140
|
end.to_app
|
140
141
|
|
141
|
-
warmed_up_app.
|
142
|
+
warmed_up_app.must_equal app
|
142
143
|
end
|
143
144
|
|
144
|
-
|
145
|
+
it "initialize apps once" do
|
145
146
|
app = builder do
|
146
147
|
class AppClass
|
147
148
|
def initialize
|
@@ -158,8 +159,8 @@ describe Rack::Builder do
|
|
158
159
|
run AppClass.new
|
159
160
|
end
|
160
161
|
|
161
|
-
Rack::MockRequest.new(app).get("/").status.
|
162
|
-
Rack::MockRequest.new(app).get("/").
|
162
|
+
Rack::MockRequest.new(app).get("/").status.must_equal 200
|
163
|
+
Rack::MockRequest.new(app).get("/").must_be :server_error?
|
163
164
|
end
|
164
165
|
|
165
166
|
it "allows use after run" do
|
@@ -168,15 +169,15 @@ describe Rack::Builder do
|
|
168
169
|
use Rack::ShowExceptions
|
169
170
|
end
|
170
171
|
|
171
|
-
Rack::MockRequest.new(app).get("/").
|
172
|
-
Rack::MockRequest.new(app).get("/").
|
173
|
-
Rack::MockRequest.new(app).get("/").
|
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?
|
174
175
|
end
|
175
176
|
|
176
177
|
it 'complains about a missing run' do
|
177
178
|
proc do
|
178
179
|
Rack::Lint.new Rack::Builder.app { use Rack::ShowExceptions }
|
179
|
-
end.
|
180
|
+
end.must_raise(RuntimeError)
|
180
181
|
end
|
181
182
|
|
182
183
|
describe "parse_file" do
|
@@ -186,38 +187,47 @@ describe Rack::Builder do
|
|
186
187
|
|
187
188
|
it "parses commented options" do
|
188
189
|
app, options = Rack::Builder.parse_file config_file('options.ru')
|
189
|
-
options[:debug].
|
190
|
-
|
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'
|
191
194
|
end
|
192
195
|
|
193
196
|
it "removes __END__ before evaluating app" do
|
194
197
|
app, _ = Rack::Builder.parse_file config_file('end.ru')
|
195
|
-
Rack::MockRequest.new(app).get("/").body.to_s.
|
198
|
+
Rack::MockRequest.new(app).get("/").body.to_s.must_equal 'OK'
|
196
199
|
end
|
197
200
|
|
198
201
|
it "supports multi-line comments" do
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
+
proc, env = Rack::Builder.parse_file(config_file('comment.ru'))
|
203
|
+
proc.must_be_kind_of Proc
|
204
|
+
env.must_equal({})
|
202
205
|
end
|
203
206
|
|
204
207
|
it "requires anything not ending in .ru" do
|
205
208
|
$: << File.dirname(__FILE__)
|
206
209
|
app, * = Rack::Builder.parse_file 'builder/anything'
|
207
|
-
Rack::MockRequest.new(app).get("/").body.to_s.
|
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'
|
208
218
|
$:.pop
|
209
219
|
end
|
210
220
|
|
211
221
|
it "sets __LINE__ correctly" do
|
212
222
|
app, _ = Rack::Builder.parse_file config_file('line.ru')
|
213
|
-
Rack::MockRequest.new(app).get("/").body.to_s.
|
223
|
+
Rack::MockRequest.new(app).get("/").body.to_s.must_equal '1'
|
214
224
|
end
|
215
225
|
end
|
216
226
|
|
217
227
|
describe 'new_from_string' do
|
218
228
|
it "builds a rack app from string" do
|
219
229
|
app, = Rack::Builder.new_from_string "run lambda{|env| [200, {'Content-Type' => 'text/plane'}, ['OK']] }"
|
220
|
-
Rack::MockRequest.new(app).get("/").body.to_s.
|
230
|
+
Rack::MockRequest.new(app).get("/").body.to_s.must_equal 'OK'
|
221
231
|
end
|
222
232
|
end
|
223
233
|
end
|
data/test/spec_cascade.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'rack'
|
1
3
|
require 'rack/cascade'
|
2
4
|
require 'rack/file'
|
3
5
|
require 'rack/lint'
|
@@ -8,7 +10,7 @@ describe Rack::Cascade do
|
|
8
10
|
def cascade(*args)
|
9
11
|
Rack::Lint.new Rack::Cascade.new(*args)
|
10
12
|
end
|
11
|
-
|
13
|
+
|
12
14
|
docroot = File.expand_path(File.dirname(__FILE__))
|
13
15
|
app1 = Rack::File.new(docroot)
|
14
16
|
|
@@ -17,45 +19,45 @@ describe Rack::Cascade do
|
|
17
19
|
app3 = Rack::URLMap.new("/foo" => lambda { |env|
|
18
20
|
[200, { "Content-Type" => "text/plain"}, [""]]})
|
19
21
|
|
20
|
-
|
22
|
+
it "dispatch onward on 404 and 405 by default" do
|
21
23
|
cascade = cascade([app1, app2, app3])
|
22
|
-
Rack::MockRequest.new(cascade).get("/cgi/test").
|
23
|
-
Rack::MockRequest.new(cascade).get("/foo").
|
24
|
-
Rack::MockRequest.new(cascade).get("/toobad").
|
25
|
-
Rack::MockRequest.new(cascade).get("/cgi/../..").
|
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?
|
26
28
|
|
27
29
|
# Put is not allowed by Rack::File so it'll 405.
|
28
|
-
Rack::MockRequest.new(cascade).put("/foo").
|
30
|
+
Rack::MockRequest.new(cascade).put("/foo").must_be :ok?
|
29
31
|
end
|
30
32
|
|
31
|
-
|
33
|
+
it "dispatch onward on whatever is passed" do
|
32
34
|
cascade = cascade([app1, app2, app3], [404, 403])
|
33
|
-
Rack::MockRequest.new(cascade).get("/cgi/../bla").
|
35
|
+
Rack::MockRequest.new(cascade).get("/cgi/../bla").must_be :not_found?
|
34
36
|
end
|
35
37
|
|
36
|
-
|
37
|
-
Rack::MockRequest.new(cascade([])).get('/').
|
38
|
+
it "return 404 if empty" do
|
39
|
+
Rack::MockRequest.new(cascade([])).get('/').must_be :not_found?
|
38
40
|
end
|
39
41
|
|
40
|
-
|
42
|
+
it "append new app" do
|
41
43
|
cascade = Rack::Cascade.new([], [404, 403])
|
42
|
-
Rack::MockRequest.new(cascade).get('/').
|
44
|
+
Rack::MockRequest.new(cascade).get('/').must_be :not_found?
|
43
45
|
cascade << app2
|
44
|
-
Rack::MockRequest.new(cascade).get('/cgi/test').
|
45
|
-
Rack::MockRequest.new(cascade).get('/cgi/../bla').
|
46
|
+
Rack::MockRequest.new(cascade).get('/cgi/test').must_be :not_found?
|
47
|
+
Rack::MockRequest.new(cascade).get('/cgi/../bla').must_be :not_found?
|
46
48
|
cascade << app1
|
47
|
-
Rack::MockRequest.new(cascade).get('/cgi/test').
|
48
|
-
Rack::MockRequest.new(cascade).get('/cgi/../..').
|
49
|
-
Rack::MockRequest.new(cascade).get('/foo').
|
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?
|
50
52
|
cascade << app3
|
51
|
-
Rack::MockRequest.new(cascade).get('/foo').
|
53
|
+
Rack::MockRequest.new(cascade).get('/foo').must_be :ok?
|
52
54
|
end
|
53
55
|
|
54
|
-
|
56
|
+
it "close the body on cascade" do
|
55
57
|
body = StringIO.new
|
56
58
|
closer = lambda { |env| [404, {}, body] }
|
57
59
|
cascade = Rack::Cascade.new([closer, app3], [404])
|
58
|
-
Rack::MockRequest.new(cascade).get("/foo").
|
59
|
-
body.
|
60
|
+
Rack::MockRequest.new(cascade).get("/foo").must_be :ok?
|
61
|
+
body.must_be :closed?
|
60
62
|
end
|
61
63
|
end
|
data/test/spec_cgi.rb
CHANGED
@@ -1,102 +1,84 @@
|
|
1
|
-
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
if defined? LIGHTTPD_PID
|
4
|
+
|
2
5
|
require File.expand_path('../testrequest', __FILE__)
|
3
6
|
require 'rack/handler/cgi'
|
4
7
|
|
5
8
|
describe Rack::Handler::CGI do
|
6
|
-
|
9
|
+
include TestRequest::Helpers
|
7
10
|
|
8
|
-
|
9
|
-
|
11
|
+
before do
|
12
|
+
@host = '127.0.0.1'
|
13
|
+
@port = 9203
|
14
|
+
end
|
10
15
|
|
11
16
|
if `which lighttpd` && !$?.success?
|
12
17
|
raise "lighttpd not found"
|
13
18
|
end
|
14
19
|
|
15
|
-
|
16
|
-
$pid = fork {
|
17
|
-
ENV['RACK_ENV'] = 'deployment'
|
18
|
-
ENV['RUBYLIB'] = [
|
19
|
-
File.expand_path('../../lib', __FILE__),
|
20
|
-
ENV['RUBYLIB'],
|
21
|
-
].compact.join(':')
|
22
|
-
|
23
|
-
Dir.chdir(File.expand_path("../cgi", __FILE__)) do
|
24
|
-
exec "lighttpd -D -f lighttpd.conf"
|
25
|
-
end
|
26
|
-
}
|
27
|
-
|
28
|
-
should "respond" do
|
20
|
+
it "respond" do
|
29
21
|
sleep 1
|
30
22
|
GET("/test")
|
31
|
-
response.
|
23
|
+
response.wont_be :nil?
|
32
24
|
end
|
33
25
|
|
34
|
-
|
26
|
+
it "be a lighttpd" do
|
35
27
|
GET("/test")
|
36
|
-
status.
|
37
|
-
response["SERVER_SOFTWARE"].
|
38
|
-
response["HTTP_VERSION"].
|
39
|
-
response["SERVER_PROTOCOL"].
|
40
|
-
response["SERVER_PORT"].
|
41
|
-
response["SERVER_NAME"].
|
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
|
42
34
|
end
|
43
35
|
|
44
|
-
|
36
|
+
it "have rack headers" do
|
45
37
|
GET("/test")
|
46
|
-
response["rack.version"].
|
47
|
-
response["rack.multithread"]
|
48
|
-
response["rack.multiprocess"]
|
49
|
-
response["rack.run_once"]
|
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"]
|
50
42
|
end
|
51
43
|
|
52
|
-
|
44
|
+
it "have CGI headers on GET" do
|
53
45
|
GET("/test")
|
54
|
-
response["REQUEST_METHOD"].
|
55
|
-
response["SCRIPT_NAME"].
|
56
|
-
response["REQUEST_PATH"].
|
57
|
-
response["PATH_INFO"].
|
58
|
-
response["QUERY_STRING"].
|
59
|
-
response["test.postdata"].
|
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 ""
|
60
52
|
|
61
53
|
GET("/test/foo?quux=1")
|
62
|
-
response["REQUEST_METHOD"].
|
63
|
-
response["SCRIPT_NAME"].
|
64
|
-
response["REQUEST_PATH"].
|
65
|
-
response["PATH_INFO"].
|
66
|
-
response["QUERY_STRING"].
|
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"
|
67
59
|
end
|
68
60
|
|
69
|
-
|
61
|
+
it "have CGI headers on POST" do
|
70
62
|
POST("/test", {"rack-form-data" => "23"}, {'X-test-header' => '42'})
|
71
|
-
status.
|
72
|
-
response["REQUEST_METHOD"].
|
73
|
-
response["SCRIPT_NAME"].
|
74
|
-
response["REQUEST_PATH"].
|
75
|
-
response["QUERY_STRING"].
|
76
|
-
response["HTTP_X_TEST_HEADER"].
|
77
|
-
response["test.postdata"].
|
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"
|
78
70
|
end
|
79
71
|
|
80
|
-
|
72
|
+
it "support HTTP auth" do
|
81
73
|
GET("/test", {:user => "ruth", :passwd => "secret"})
|
82
|
-
response["HTTP_AUTHORIZATION"].
|
74
|
+
response["HTTP_AUTHORIZATION"].must_equal "Basic cnV0aDpzZWNyZXQ="
|
83
75
|
end
|
84
76
|
|
85
|
-
|
77
|
+
it "set status" do
|
86
78
|
GET("/test?secret")
|
87
|
-
status.
|
88
|
-
response["rack.url_scheme"].
|
89
|
-
end
|
90
|
-
|
91
|
-
# Keep this last.
|
92
|
-
should "shutdown" do
|
93
|
-
Process.kill 15, $pid
|
94
|
-
Process.wait($pid).should == $pid
|
79
|
+
status.must_equal 403
|
80
|
+
response["rack.url_scheme"].must_equal "http"
|
95
81
|
end
|
96
82
|
end
|
97
83
|
|
98
|
-
|
99
|
-
$stderr.puts "Skipping Rack::Handler::CGI tests (lighttpd is required). Install lighttpd and try again."
|
100
|
-
rescue NotImplementedError
|
101
|
-
$stderr.puts "Your Ruby implemenation or platform does not support fork. Skipping Rack::Handler::CGI tests."
|
102
|
-
end
|
84
|
+
end # if defined? LIGHTTPD_PID
|
data/test/spec_chunked.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'minitest/autorun'
|
1
2
|
require 'rack/chunked'
|
2
3
|
require 'rack/lint'
|
3
4
|
require 'rack/mock'
|
@@ -18,59 +19,60 @@ describe Rack::Chunked do
|
|
18
19
|
env_for('/', 'HTTP_VERSION' => '1.1', 'REQUEST_METHOD' => 'GET')
|
19
20
|
end
|
20
21
|
|
21
|
-
|
22
|
+
it 'chunk responses with no Content-Length' do
|
22
23
|
app = lambda { |env| [200, {"Content-Type" => "text/plain"}, ['Hello', ' ', 'World!']] }
|
23
24
|
response = Rack::MockResponse.new(*chunked(app).call(@env))
|
24
|
-
response.headers.
|
25
|
-
response.headers['Transfer-Encoding'].
|
26
|
-
response.body.
|
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"
|
27
28
|
end
|
28
29
|
|
29
|
-
|
30
|
+
it 'chunks empty bodies properly' do
|
30
31
|
app = lambda { |env| [200, {"Content-Type" => "text/plain"}, []] }
|
31
32
|
response = Rack::MockResponse.new(*chunked(app).call(@env))
|
32
|
-
response.headers.
|
33
|
-
response.headers['Transfer-Encoding'].
|
34
|
-
response.body.
|
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"
|
35
36
|
end
|
36
37
|
|
37
|
-
|
38
|
+
it 'chunks encoded bodies properly' do
|
38
39
|
body = ["\uFFFEHello", " ", "World"].map {|t| t.encode("UTF-16LE") }
|
39
40
|
app = lambda { |env| [200, {"Content-Type" => "text/plain"}, body] }
|
40
41
|
response = Rack::MockResponse.new(*chunked(app).call(@env))
|
41
|
-
response.headers.
|
42
|
-
response.headers['Transfer-Encoding'].
|
43
|
-
response.body.encoding.to_s.
|
44
|
-
response.body.
|
45
|
-
|
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
|
46
48
|
|
47
|
-
|
49
|
+
it 'not modify response when Content-Length header present' do
|
48
50
|
app = lambda { |env|
|
49
51
|
[200, {"Content-Type" => "text/plain", 'Content-Length'=>'12'}, ['Hello', ' ', 'World!']]
|
50
52
|
}
|
51
53
|
status, headers, body = chunked(app).call(@env)
|
52
|
-
status.
|
53
|
-
headers.
|
54
|
-
headers.
|
55
|
-
body.join.
|
54
|
+
status.must_equal 200
|
55
|
+
headers.wont_include 'Transfer-Encoding'
|
56
|
+
headers.must_include 'Content-Length'
|
57
|
+
body.join.must_equal 'Hello World!'
|
56
58
|
end
|
57
59
|
|
58
|
-
|
60
|
+
it 'not modify response when client is HTTP/1.0' do
|
59
61
|
app = lambda { |env| [200, {"Content-Type" => "text/plain"}, ['Hello', ' ', 'World!']] }
|
60
62
|
@env['HTTP_VERSION'] = 'HTTP/1.0'
|
61
63
|
status, headers, body = chunked(app).call(@env)
|
62
|
-
status.
|
63
|
-
headers.
|
64
|
-
body.join.
|
64
|
+
status.must_equal 200
|
65
|
+
headers.wont_include 'Transfer-Encoding'
|
66
|
+
body.join.must_equal 'Hello World!'
|
65
67
|
end
|
66
68
|
|
67
|
-
|
69
|
+
it 'not modify response when client is ancient, pre-HTTP/1.0' do
|
68
70
|
app = lambda { |env| [200, {"Content-Type" => "text/plain"}, ['Hello', ' ', 'World!']] }
|
69
71
|
check = lambda do
|
70
72
|
status, headers, body = chunked(app).call(@env.dup)
|
71
|
-
status.
|
72
|
-
headers.
|
73
|
-
body.join.
|
73
|
+
status.must_equal 200
|
74
|
+
headers.wont_include 'Transfer-Encoding'
|
75
|
+
body.join.must_equal 'Hello World!'
|
74
76
|
end
|
75
77
|
|
76
78
|
@env.delete('HTTP_VERSION') # unicorn will do this on pre-HTTP/1.0 requests
|
@@ -80,22 +82,22 @@ describe Rack::Chunked do
|
|
80
82
|
check.call
|
81
83
|
end
|
82
84
|
|
83
|
-
|
85
|
+
it 'not modify response when Transfer-Encoding header already present' do
|
84
86
|
app = lambda { |env|
|
85
87
|
[200, {"Content-Type" => "text/plain", 'Transfer-Encoding' => 'identity'}, ['Hello', ' ', 'World!']]
|
86
88
|
}
|
87
89
|
status, headers, body = chunked(app).call(@env)
|
88
|
-
status.
|
89
|
-
headers['Transfer-Encoding'].
|
90
|
-
body.join.
|
90
|
+
status.must_equal 200
|
91
|
+
headers['Transfer-Encoding'].must_equal 'identity'
|
92
|
+
body.join.must_equal 'Hello World!'
|
91
93
|
end
|
92
94
|
|
93
|
-
[100, 204,
|
94
|
-
|
95
|
+
[100, 204, 304].each do |status_code|
|
96
|
+
it "not modify response when status code is #{status_code}" do
|
95
97
|
app = lambda { |env| [status_code, {}, []] }
|
96
98
|
status, headers, _ = chunked(app).call(@env)
|
97
|
-
status.
|
98
|
-
headers.
|
99
|
+
status.must_equal status_code
|
100
|
+
headers.wont_include 'Transfer-Encoding'
|
99
101
|
end
|
100
102
|
end
|
101
103
|
end
|