kastner-rack 0.3.171
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/AUTHORS +8 -0
- data/COPYING +18 -0
- data/KNOWN-ISSUES +18 -0
- data/README +273 -0
- data/Rakefile +185 -0
- data/bin/rackup +172 -0
- data/contrib/rack_logo.svg +111 -0
- data/example/lobster.ru +4 -0
- data/example/protectedlobster.rb +14 -0
- data/example/protectedlobster.ru +8 -0
- data/lib/rack.rb +85 -0
- data/lib/rack/adapter/camping.rb +22 -0
- data/lib/rack/auth/abstract/handler.rb +28 -0
- data/lib/rack/auth/abstract/request.rb +37 -0
- data/lib/rack/auth/basic.rb +58 -0
- data/lib/rack/auth/digest/md5.rb +124 -0
- data/lib/rack/auth/digest/nonce.rb +51 -0
- data/lib/rack/auth/digest/params.rb +55 -0
- data/lib/rack/auth/digest/request.rb +40 -0
- data/lib/rack/auth/openid.rb +437 -0
- data/lib/rack/builder.rb +67 -0
- data/lib/rack/cascade.rb +36 -0
- data/lib/rack/commonlogger.rb +61 -0
- data/lib/rack/conditionalget.rb +42 -0
- data/lib/rack/deflater.rb +63 -0
- data/lib/rack/directory.rb +149 -0
- data/lib/rack/file.rb +84 -0
- data/lib/rack/handler.rb +46 -0
- data/lib/rack/handler/cgi.rb +57 -0
- data/lib/rack/handler/evented_mongrel.rb +8 -0
- data/lib/rack/handler/fastcgi.rb +86 -0
- data/lib/rack/handler/lsws.rb +52 -0
- data/lib/rack/handler/mongrel.rb +78 -0
- data/lib/rack/handler/scgi.rb +57 -0
- data/lib/rack/handler/swiftiplied_mongrel.rb +8 -0
- data/lib/rack/handler/webrick.rb +61 -0
- data/lib/rack/head.rb +19 -0
- data/lib/rack/lint.rb +463 -0
- data/lib/rack/lobster.rb +65 -0
- data/lib/rack/methodoverride.rb +21 -0
- data/lib/rack/mime.rb +204 -0
- data/lib/rack/mock.rb +160 -0
- data/lib/rack/recursive.rb +57 -0
- data/lib/rack/reloader.rb +64 -0
- data/lib/rack/request.rb +217 -0
- data/lib/rack/response.rb +171 -0
- data/lib/rack/session/abstract/id.rb +140 -0
- data/lib/rack/session/cookie.rb +89 -0
- data/lib/rack/session/memcache.rb +97 -0
- data/lib/rack/session/pool.rb +73 -0
- data/lib/rack/showexceptions.rb +348 -0
- data/lib/rack/showstatus.rb +105 -0
- data/lib/rack/static.rb +38 -0
- data/lib/rack/urlmap.rb +48 -0
- data/lib/rack/utils.rb +318 -0
- data/rack.gemspec +31 -0
- data/test/cgi/lighttpd.conf +20 -0
- data/test/cgi/test +9 -0
- data/test/cgi/test.fcgi +8 -0
- data/test/cgi/test.ru +7 -0
- data/test/spec_rack_auth_basic.rb +69 -0
- data/test/spec_rack_auth_digest.rb +169 -0
- data/test/spec_rack_auth_openid.rb +137 -0
- data/test/spec_rack_builder.rb +84 -0
- data/test/spec_rack_camping.rb +51 -0
- data/test/spec_rack_cascade.rb +50 -0
- data/test/spec_rack_cgi.rb +89 -0
- data/test/spec_rack_commonlogger.rb +32 -0
- data/test/spec_rack_conditionalget.rb +41 -0
- data/test/spec_rack_deflater.rb +70 -0
- data/test/spec_rack_directory.rb +56 -0
- data/test/spec_rack_fastcgi.rb +89 -0
- data/test/spec_rack_file.rb +57 -0
- data/test/spec_rack_handler.rb +24 -0
- data/test/spec_rack_head.rb +30 -0
- data/test/spec_rack_lint.rb +371 -0
- data/test/spec_rack_lobster.rb +45 -0
- data/test/spec_rack_methodoverride.rb +31 -0
- data/test/spec_rack_mock.rb +152 -0
- data/test/spec_rack_mongrel.rb +170 -0
- data/test/spec_rack_recursive.rb +77 -0
- data/test/spec_rack_request.rb +426 -0
- data/test/spec_rack_response.rb +173 -0
- data/test/spec_rack_session_cookie.rb +78 -0
- data/test/spec_rack_session_memcache.rb +132 -0
- data/test/spec_rack_session_pool.rb +84 -0
- data/test/spec_rack_showexceptions.rb +21 -0
- data/test/spec_rack_showstatus.rb +72 -0
- data/test/spec_rack_static.rb +37 -0
- data/test/spec_rack_urlmap.rb +175 -0
- data/test/spec_rack_utils.rb +174 -0
- data/test/spec_rack_webrick.rb +123 -0
- data/test/testrequest.rb +45 -0
- metadata +177 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
require 'test/spec'
|
|
2
|
+
|
|
3
|
+
require 'rack/builder'
|
|
4
|
+
require 'rack/mock'
|
|
5
|
+
require 'rack/showexceptions'
|
|
6
|
+
require 'rack/auth/basic'
|
|
7
|
+
|
|
8
|
+
context "Rack::Builder" do
|
|
9
|
+
specify "chains apps by default" do
|
|
10
|
+
app = Rack::Builder.new do
|
|
11
|
+
use Rack::ShowExceptions
|
|
12
|
+
run lambda { |env| raise "bzzzt" }
|
|
13
|
+
end.to_app
|
|
14
|
+
|
|
15
|
+
Rack::MockRequest.new(app).get("/").should.be.server_error
|
|
16
|
+
Rack::MockRequest.new(app).get("/").should.be.server_error
|
|
17
|
+
Rack::MockRequest.new(app).get("/").should.be.server_error
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
specify "has implicit #to_app" do
|
|
21
|
+
app = Rack::Builder.new do
|
|
22
|
+
use Rack::ShowExceptions
|
|
23
|
+
run lambda { |env| raise "bzzzt" }
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
Rack::MockRequest.new(app).get("/").should.be.server_error
|
|
27
|
+
Rack::MockRequest.new(app).get("/").should.be.server_error
|
|
28
|
+
Rack::MockRequest.new(app).get("/").should.be.server_error
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
specify "supports blocks on use" do
|
|
32
|
+
app = Rack::Builder.new do
|
|
33
|
+
use Rack::ShowExceptions
|
|
34
|
+
use Rack::Auth::Basic do |username, password|
|
|
35
|
+
'secret' == password
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
run lambda { |env| [200, {}, 'Hi Boss'] }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
response = Rack::MockRequest.new(app).get("/")
|
|
42
|
+
response.should.be.client_error
|
|
43
|
+
response.status.should.equal 401
|
|
44
|
+
|
|
45
|
+
# with auth...
|
|
46
|
+
response = Rack::MockRequest.new(app).get("/",
|
|
47
|
+
'HTTP_AUTHORIZATION' => 'Basic ' + ["joe:secret"].pack("m*"))
|
|
48
|
+
response.status.should.equal 200
|
|
49
|
+
response.body.to_s.should.equal 'Hi Boss'
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
specify "has explicit #to_app" do
|
|
53
|
+
app = Rack::Builder.app do
|
|
54
|
+
use Rack::ShowExceptions
|
|
55
|
+
run lambda { |env| raise "bzzzt" }
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
Rack::MockRequest.new(app).get("/").should.be.server_error
|
|
59
|
+
Rack::MockRequest.new(app).get("/").should.be.server_error
|
|
60
|
+
Rack::MockRequest.new(app).get("/").should.be.server_error
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
specify "apps are initialized once" do
|
|
64
|
+
class AppClass
|
|
65
|
+
def initialize
|
|
66
|
+
@called = 0
|
|
67
|
+
end
|
|
68
|
+
def call(env)
|
|
69
|
+
raise "bzzzt" if @called > 0
|
|
70
|
+
@called += 1
|
|
71
|
+
[200, {'Content-Type' => 'text/plain'}, 'OK']
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
app = Rack::Builder.new do
|
|
76
|
+
use Rack::ShowExceptions
|
|
77
|
+
run AppClass.new
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
Rack::MockRequest.new(app).get("/").status.should.equal 200
|
|
81
|
+
Rack::MockRequest.new(app).get("/").should.be.server_error
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
require 'test/spec'
|
|
2
|
+
require 'stringio'
|
|
3
|
+
require 'uri'
|
|
4
|
+
|
|
5
|
+
begin
|
|
6
|
+
require 'rack/mock'
|
|
7
|
+
|
|
8
|
+
$-w, w = nil, $-w # yuck
|
|
9
|
+
require 'camping'
|
|
10
|
+
require 'rack/adapter/camping'
|
|
11
|
+
|
|
12
|
+
Camping.goes :CampApp
|
|
13
|
+
module CampApp
|
|
14
|
+
module Controllers
|
|
15
|
+
class HW < R('/')
|
|
16
|
+
def get
|
|
17
|
+
@headers["X-Served-By"] = URI("http://rack.rubyforge.org")
|
|
18
|
+
"Camping works!"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def post
|
|
22
|
+
"Data: #{input.foo}"
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
$-w = w
|
|
28
|
+
|
|
29
|
+
context "Rack::Adapter::Camping" do
|
|
30
|
+
specify "works with GET" do
|
|
31
|
+
res = Rack::MockRequest.new(Rack::Adapter::Camping.new(CampApp)).
|
|
32
|
+
get("/")
|
|
33
|
+
|
|
34
|
+
res.should.be.ok
|
|
35
|
+
res["Content-Type"].should.equal "text/html"
|
|
36
|
+
res["X-Served-By"].should.equal "http://rack.rubyforge.org"
|
|
37
|
+
|
|
38
|
+
res.body.should.equal "Camping works!"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
specify "works with POST" do
|
|
42
|
+
res = Rack::MockRequest.new(Rack::Adapter::Camping.new(CampApp)).
|
|
43
|
+
post("/", :input => "foo=bar")
|
|
44
|
+
|
|
45
|
+
res.should.be.ok
|
|
46
|
+
res.body.should.equal "Data: bar"
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
rescue LoadError
|
|
50
|
+
$stderr.puts "Skipping Rack::Adapter::Camping tests (Camping is required). `gem install camping` and try again."
|
|
51
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
require 'test/spec'
|
|
2
|
+
|
|
3
|
+
require 'rack/cascade'
|
|
4
|
+
require 'rack/mock'
|
|
5
|
+
|
|
6
|
+
require 'rack/urlmap'
|
|
7
|
+
require 'rack/file'
|
|
8
|
+
|
|
9
|
+
context "Rack::Cascade" do
|
|
10
|
+
docroot = File.expand_path(File.dirname(__FILE__))
|
|
11
|
+
app1 = Rack::File.new(docroot)
|
|
12
|
+
|
|
13
|
+
app2 = Rack::URLMap.new("/crash" => lambda { |env| raise "boom" })
|
|
14
|
+
|
|
15
|
+
app3 = Rack::URLMap.new("/foo" => lambda { |env|
|
|
16
|
+
[200, { "Content-Type" => "text/plain"}, [""]]})
|
|
17
|
+
|
|
18
|
+
specify "should dispatch onward on 404 by default" do
|
|
19
|
+
cascade = Rack::Cascade.new([app1, app2, app3])
|
|
20
|
+
Rack::MockRequest.new(cascade).get("/cgi/test").should.be.ok
|
|
21
|
+
Rack::MockRequest.new(cascade).get("/foo").should.be.ok
|
|
22
|
+
Rack::MockRequest.new(cascade).get("/toobad").should.be.not_found
|
|
23
|
+
Rack::MockRequest.new(cascade).get("/cgi/../bla").should.be.forbidden
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
specify "should dispatch onward on whatever is passed" do
|
|
27
|
+
cascade = Rack::Cascade.new([app1, app2, app3], [404, 403])
|
|
28
|
+
Rack::MockRequest.new(cascade).get("/cgi/../bla").should.be.not_found
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
specify "should fail if empty" do
|
|
32
|
+
lambda { Rack::MockRequest.new(Rack::Cascade.new([])).get("/") }.
|
|
33
|
+
should.raise(ArgumentError)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
specify "should append new app" do
|
|
37
|
+
cascade = Rack::Cascade.new([], [404, 403])
|
|
38
|
+
lambda { Rack::MockRequest.new(cascade).get('/cgi/test') }.
|
|
39
|
+
should.raise(ArgumentError)
|
|
40
|
+
cascade << app2
|
|
41
|
+
Rack::MockRequest.new(cascade).get('/cgi/test').should.be.not_found
|
|
42
|
+
Rack::MockRequest.new(cascade).get('/cgi/../bla').should.be.not_found
|
|
43
|
+
cascade << app1
|
|
44
|
+
Rack::MockRequest.new(cascade).get('/cgi/test').should.be.ok
|
|
45
|
+
Rack::MockRequest.new(cascade).get('/cgi/../bla').should.be.forbidden
|
|
46
|
+
Rack::MockRequest.new(cascade).get('/foo').should.be.not_found
|
|
47
|
+
cascade << app3
|
|
48
|
+
Rack::MockRequest.new(cascade).get('/foo').should.be.ok
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
require 'test/spec'
|
|
2
|
+
require 'testrequest'
|
|
3
|
+
|
|
4
|
+
context "Rack::Handler::CGI" do
|
|
5
|
+
include TestRequest::Helpers
|
|
6
|
+
|
|
7
|
+
setup do
|
|
8
|
+
@host = '0.0.0.0'
|
|
9
|
+
@port = 9203
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Keep this first.
|
|
13
|
+
specify "startup" do
|
|
14
|
+
$pid = fork {
|
|
15
|
+
Dir.chdir(File.join(File.dirname(__FILE__), "..", "test", "cgi"))
|
|
16
|
+
exec "lighttpd -D -f lighttpd.conf"
|
|
17
|
+
}
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
specify "should respond" do
|
|
21
|
+
sleep 1
|
|
22
|
+
lambda {
|
|
23
|
+
GET("/test")
|
|
24
|
+
}.should.not.raise
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
specify "should be a lighttpd" do
|
|
28
|
+
GET("/test")
|
|
29
|
+
status.should.be 200
|
|
30
|
+
response["SERVER_SOFTWARE"].should =~ /lighttpd/
|
|
31
|
+
response["HTTP_VERSION"].should.equal "HTTP/1.1"
|
|
32
|
+
response["SERVER_PROTOCOL"].should.equal "HTTP/1.1"
|
|
33
|
+
response["SERVER_PORT"].should.equal @port.to_s
|
|
34
|
+
response["SERVER_NAME"].should =~ @host
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
specify "should have rack headers" do
|
|
38
|
+
GET("/test")
|
|
39
|
+
response["rack.version"].should.equal [0,1]
|
|
40
|
+
response["rack.multithread"].should.be false
|
|
41
|
+
response["rack.multiprocess"].should.be true
|
|
42
|
+
response["rack.run_once"].should.be true
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
specify "should have CGI headers on GET" do
|
|
46
|
+
GET("/test")
|
|
47
|
+
response["REQUEST_METHOD"].should.equal "GET"
|
|
48
|
+
response["SCRIPT_NAME"].should.equal "/test"
|
|
49
|
+
response["REQUEST_PATH"].should.equal "/"
|
|
50
|
+
response["PATH_INFO"].should.be.nil
|
|
51
|
+
response["QUERY_STRING"].should.equal ""
|
|
52
|
+
response["test.postdata"].should.equal ""
|
|
53
|
+
|
|
54
|
+
GET("/test/foo?quux=1")
|
|
55
|
+
response["REQUEST_METHOD"].should.equal "GET"
|
|
56
|
+
response["SCRIPT_NAME"].should.equal "/test"
|
|
57
|
+
response["REQUEST_PATH"].should.equal "/"
|
|
58
|
+
response["PATH_INFO"].should.equal "/foo"
|
|
59
|
+
response["QUERY_STRING"].should.equal "quux=1"
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
specify "should have CGI headers on POST" do
|
|
63
|
+
POST("/test", {"rack-form-data" => "23"}, {'X-test-header' => '42'})
|
|
64
|
+
status.should.equal 200
|
|
65
|
+
response["REQUEST_METHOD"].should.equal "POST"
|
|
66
|
+
response["SCRIPT_NAME"].should.equal "/test"
|
|
67
|
+
response["REQUEST_PATH"].should.equal "/"
|
|
68
|
+
response["QUERY_STRING"].should.equal ""
|
|
69
|
+
response["HTTP_X_TEST_HEADER"].should.equal "42"
|
|
70
|
+
response["test.postdata"].should.equal "rack-form-data=23"
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
specify "should support HTTP auth" do
|
|
74
|
+
GET("/test", {:user => "ruth", :passwd => "secret"})
|
|
75
|
+
response["HTTP_AUTHORIZATION"].should.equal "Basic cnV0aDpzZWNyZXQ="
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
specify "should set status" do
|
|
79
|
+
GET("/test?secret")
|
|
80
|
+
status.should.equal 403
|
|
81
|
+
response["rack.url_scheme"].should.equal "http"
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Keep this last.
|
|
85
|
+
specify "shutdown" do
|
|
86
|
+
Process.kill 15, $pid
|
|
87
|
+
Process.wait($pid).should.equal $pid
|
|
88
|
+
end
|
|
89
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
require 'test/spec'
|
|
2
|
+
require 'stringio'
|
|
3
|
+
|
|
4
|
+
require 'rack/commonlogger'
|
|
5
|
+
require 'rack/lobster'
|
|
6
|
+
require 'rack/mock'
|
|
7
|
+
|
|
8
|
+
context "Rack::CommonLogger" do
|
|
9
|
+
app = lambda { |env|
|
|
10
|
+
[200,
|
|
11
|
+
{"Content-Type" => "text/html"},
|
|
12
|
+
["foo"]]}
|
|
13
|
+
|
|
14
|
+
specify "should log to rack.errors by default" do
|
|
15
|
+
log = StringIO.new
|
|
16
|
+
res = Rack::MockRequest.new(Rack::CommonLogger.new(app)).get("/")
|
|
17
|
+
|
|
18
|
+
res.errors.should.not.be.empty
|
|
19
|
+
res.errors.should =~ /GET /
|
|
20
|
+
res.errors.should =~ / 200 / # status
|
|
21
|
+
res.errors.should =~ / 3 / # length
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
specify "should log to anything with <<" do
|
|
25
|
+
log = ""
|
|
26
|
+
res = Rack::MockRequest.new(Rack::CommonLogger.new(app, log)).get("/")
|
|
27
|
+
|
|
28
|
+
log.should =~ /GET /
|
|
29
|
+
log.should =~ / 200 / # status
|
|
30
|
+
log.should =~ / 3 / # length
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
require 'test/spec'
|
|
2
|
+
require 'time'
|
|
3
|
+
|
|
4
|
+
require 'rack/mock'
|
|
5
|
+
require 'rack/conditionalget'
|
|
6
|
+
|
|
7
|
+
context "Rack::ConditionalGet" do
|
|
8
|
+
specify "should set a 304 status and truncate body when If-Modified-Since hits" do
|
|
9
|
+
timestamp = Time.now.httpdate
|
|
10
|
+
app = Rack::ConditionalGet.new(lambda { |env|
|
|
11
|
+
[200, {'Last-Modified'=>timestamp}, 'TEST'] })
|
|
12
|
+
|
|
13
|
+
response = Rack::MockRequest.new(app).
|
|
14
|
+
get("/", 'HTTP_IF_MODIFIED_SINCE' => timestamp)
|
|
15
|
+
|
|
16
|
+
response.status.should.be == 304
|
|
17
|
+
response.body.should.be.empty
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
specify "should set a 304 status and truncate body when If-None-Match hits" do
|
|
21
|
+
app = Rack::ConditionalGet.new(lambda { |env|
|
|
22
|
+
[200, {'Etag'=>'1234'}, 'TEST'] })
|
|
23
|
+
|
|
24
|
+
response = Rack::MockRequest.new(app).
|
|
25
|
+
get("/", 'HTTP_IF_NONE_MATCH' => '1234')
|
|
26
|
+
|
|
27
|
+
response.status.should.be == 304
|
|
28
|
+
response.body.should.be.empty
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
specify "should not affect non-GET/HEAD requests" do
|
|
32
|
+
app = Rack::ConditionalGet.new(lambda { |env|
|
|
33
|
+
[200, {'Etag'=>'1234'}, 'TEST'] })
|
|
34
|
+
|
|
35
|
+
response = Rack::MockRequest.new(app).
|
|
36
|
+
post("/", 'HTTP_IF_NONE_MATCH' => '1234')
|
|
37
|
+
|
|
38
|
+
response.status.should.be == 200
|
|
39
|
+
response.body.should.be == 'TEST'
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
require 'test/spec'
|
|
2
|
+
|
|
3
|
+
require 'rack/mock'
|
|
4
|
+
require 'rack/deflater'
|
|
5
|
+
require 'stringio'
|
|
6
|
+
|
|
7
|
+
context "Rack::Deflater" do
|
|
8
|
+
def build_response(body, accept_encoding, headers = {})
|
|
9
|
+
app = lambda { |env| [200, {}, body] }
|
|
10
|
+
request = Rack::MockRequest.env_for("", headers.merge("HTTP_ACCEPT_ENCODING" => accept_encoding))
|
|
11
|
+
response = Rack::Deflater.new(app).call(request)
|
|
12
|
+
|
|
13
|
+
return response
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
specify "should be able to deflate bodies that respond to each" do
|
|
17
|
+
body = Object.new
|
|
18
|
+
class << body; def each; yield("foo"); yield("bar"); end; end
|
|
19
|
+
|
|
20
|
+
response = build_response(body, "deflate")
|
|
21
|
+
|
|
22
|
+
response[0].should.equal(200)
|
|
23
|
+
response[1].should.equal({ "Content-Encoding" => "deflate" })
|
|
24
|
+
response[2].to_s.should.equal("K\313\317OJ,\002\000")
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# TODO: This is really just a special case of the above...
|
|
28
|
+
specify "should be able to deflate String bodies" do
|
|
29
|
+
response = build_response("Hello world!", "deflate")
|
|
30
|
+
|
|
31
|
+
response[0].should.equal(200)
|
|
32
|
+
response[1].should.equal({ "Content-Encoding" => "deflate" })
|
|
33
|
+
response[2].to_s.should.equal("\363H\315\311\311W(\317/\312IQ\004\000")
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
specify "should be able to gzip bodies that respond to each" do
|
|
37
|
+
body = Object.new
|
|
38
|
+
class << body; def each; yield("foo"); yield("bar"); end; end
|
|
39
|
+
|
|
40
|
+
response = build_response(body, "gzip")
|
|
41
|
+
|
|
42
|
+
response[0].should.equal(200)
|
|
43
|
+
response[1].should.equal({ "Content-Encoding" => "gzip" })
|
|
44
|
+
|
|
45
|
+
io = StringIO.new(response[2].to_s)
|
|
46
|
+
gz = Zlib::GzipReader.new(io)
|
|
47
|
+
gz.read.should.equal("foobar")
|
|
48
|
+
gz.close
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
specify "should be able to fallback to no deflation" do
|
|
52
|
+
response = build_response("Hello world!", "superzip")
|
|
53
|
+
|
|
54
|
+
response[0].should.equal(200)
|
|
55
|
+
response[1].should.equal({})
|
|
56
|
+
response[2].should.equal("Hello world!")
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
specify "should handle the lack of an acceptable encoding" do
|
|
60
|
+
response1 = build_response("Hello world!", "identity;q=0", "PATH_INFO" => "/")
|
|
61
|
+
response1[0].should.equal(406)
|
|
62
|
+
response1[1].should.equal({"Content-Type" => "text/plain"})
|
|
63
|
+
response1[2].should.equal("An acceptable encoding for the requested resource / could not be found.")
|
|
64
|
+
|
|
65
|
+
response2 = build_response("Hello world!", "identity;q=0", "SCRIPT_NAME" => "/foo", "PATH_INFO" => "/bar")
|
|
66
|
+
response2[0].should.equal(406)
|
|
67
|
+
response2[1].should.equal({"Content-Type" => "text/plain"})
|
|
68
|
+
response2[2].should.equal("An acceptable encoding for the requested resource /foo/bar could not be found.")
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
require 'test/spec'
|
|
2
|
+
|
|
3
|
+
require 'rack/directory'
|
|
4
|
+
require 'rack/lint'
|
|
5
|
+
|
|
6
|
+
require 'rack/mock'
|
|
7
|
+
|
|
8
|
+
context "Rack::Directory" do
|
|
9
|
+
DOCROOT = File.expand_path(File.dirname(__FILE__))
|
|
10
|
+
FILE_CATCH = proc{|env| [200, {'Content-Type'=>'text/plain', "Content-Length" => "7"}, 'passed!'] }
|
|
11
|
+
app = Rack::Directory.new DOCROOT, FILE_CATCH
|
|
12
|
+
|
|
13
|
+
specify "serves directory indices" do
|
|
14
|
+
res = Rack::MockRequest.new(Rack::Lint.new(app)).
|
|
15
|
+
get("/cgi/")
|
|
16
|
+
|
|
17
|
+
res.should.be.ok
|
|
18
|
+
res.should =~ /<html><head>/
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
specify "passes to app if file found" do
|
|
22
|
+
res = Rack::MockRequest.new(Rack::Lint.new(app)).
|
|
23
|
+
get("/cgi/test")
|
|
24
|
+
|
|
25
|
+
res.should.be.ok
|
|
26
|
+
res.should =~ /passed!/
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
specify "serves uri with URL encoded filenames" do
|
|
30
|
+
res = Rack::MockRequest.new(Rack::Lint.new(app)).
|
|
31
|
+
get("/%63%67%69/") # "/cgi/test"
|
|
32
|
+
|
|
33
|
+
res.should.be.ok
|
|
34
|
+
res.should =~ /<html><head>/
|
|
35
|
+
|
|
36
|
+
res = Rack::MockRequest.new(Rack::Lint.new(app)).
|
|
37
|
+
get("/cgi/%74%65%73%74") # "/cgi/test"
|
|
38
|
+
|
|
39
|
+
res.should.be.ok
|
|
40
|
+
res.should =~ /passed!/
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
specify "does not allow directory traversal" do
|
|
44
|
+
res = Rack::MockRequest.new(Rack::Lint.new(app)).
|
|
45
|
+
get("/cgi/../test")
|
|
46
|
+
|
|
47
|
+
res.should.be.forbidden
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
specify "404s if it can't find the file" do
|
|
51
|
+
res = Rack::MockRequest.new(Rack::Lint.new(app)).
|
|
52
|
+
get("/cgi/blubb")
|
|
53
|
+
|
|
54
|
+
res.should.be.not_found
|
|
55
|
+
end
|
|
56
|
+
end
|