rack 1.6.11 → 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 +157 -163
- data/Rakefile +38 -32
- data/{SPEC → SPEC.rdoc} +41 -13
- data/bin/rackup +1 -0
- data/contrib/rack_logo.svg +164 -111
- data/example/lobster.ru +2 -0
- data/example/protectedlobster.rb +4 -2
- data/example/protectedlobster.ru +3 -1
- data/lib/rack/auth/abstract/handler.rb +3 -1
- data/lib/rack/auth/abstract/request.rb +6 -2
- 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 +5 -4
- data/lib/rack/auth/digest/request.rb +6 -4
- data/lib/rack/body_proxy.rb +21 -15
- data/lib/rack/builder.rb +119 -26
- data/lib/rack/cascade.rb +28 -12
- data/lib/rack/chunked.rb +70 -22
- data/lib/rack/common_logger.rb +80 -0
- data/lib/rack/{conditionalget.rb → conditional_get.rb} +20 -16
- data/lib/rack/config.rb +2 -0
- data/lib/rack/content_length.rb +9 -8
- data/lib/rack/content_type.rb +5 -4
- data/lib/rack/core_ext/regexp.rb +14 -0
- data/lib/rack/deflater.rb +60 -70
- data/lib/rack/directory.rb +117 -85
- data/lib/rack/etag.rb +9 -7
- data/lib/rack/events.rb +153 -0
- data/lib/rack/file.rb +4 -149
- data/lib/rack/files.rb +218 -0
- data/lib/rack/handler/cgi.rb +17 -19
- data/lib/rack/handler/fastcgi.rb +17 -18
- data/lib/rack/handler/lsws.rb +14 -14
- data/lib/rack/handler/scgi.rb +22 -21
- data/lib/rack/handler/thin.rb +20 -11
- data/lib/rack/handler/webrick.rb +39 -32
- data/lib/rack/handler.rb +9 -26
- data/lib/rack/head.rb +16 -18
- data/lib/rack/lint.rb +110 -64
- data/lib/rack/lobster.rb +10 -10
- data/lib/rack/lock.rb +17 -11
- data/lib/rack/logger.rb +4 -2
- data/lib/rack/media_type.rb +43 -0
- data/lib/rack/{methodoverride.rb → method_override.rb} +10 -8
- data/lib/rack/mime.rb +27 -6
- data/lib/rack/mock.rb +124 -65
- data/lib/rack/multipart/generator.rb +20 -16
- data/lib/rack/multipart/parser.rb +273 -162
- data/lib/rack/multipart/uploaded_file.rb +15 -8
- data/lib/rack/multipart.rb +39 -8
- data/lib/rack/{nulllogger.rb → null_logger.rb} +3 -1
- data/lib/rack/query_parser.rb +217 -0
- data/lib/rack/recursive.rb +11 -9
- data/lib/rack/reloader.rb +8 -4
- data/lib/rack/request.rb +543 -305
- data/lib/rack/response.rb +244 -88
- data/lib/rack/rewindable_input.rb +5 -15
- data/lib/rack/runtime.rb +12 -18
- data/lib/rack/sendfile.rb +17 -15
- data/lib/rack/server.rb +125 -47
- data/lib/rack/session/abstract/id.rb +216 -93
- data/lib/rack/session/cookie.rb +47 -31
- data/lib/rack/session/memcache.rb +4 -87
- data/lib/rack/session/pool.rb +26 -17
- data/lib/rack/show_exceptions.rb +390 -0
- data/lib/rack/{showstatus.rb → show_status.rb} +8 -8
- data/lib/rack/static.rb +48 -11
- data/lib/rack/tempfile_reaper.rb +3 -3
- data/lib/rack/urlmap.rb +26 -19
- data/lib/rack/utils.rb +208 -294
- data/lib/rack/version.rb +29 -0
- data/lib/rack.rb +76 -33
- data/rack.gemspec +43 -30
- metadata +62 -183
- data/HISTORY.md +0 -375
- 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/commonlogger.rb +0 -72
- 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/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 -8
- data/test/cgi/test.ru +0 -5
- data/test/gemloader.rb +0 -10
- data/test/multipart/bad_robots +0 -259
- data/test/multipart/binary +0 -0
- data/test/multipart/content_type_and_no_filename +0 -6
- data/test/multipart/empty +0 -10
- data/test/multipart/fail_16384_nofile +0 -814
- data/test/multipart/file1.txt +0 -1
- data/test/multipart/filename_and_modification_param +0 -7
- data/test/multipart/filename_and_no_name +0 -6
- 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_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/semicolon +0 -6
- data/test/multipart/text +0 -15
- data/test/multipart/three_files_three_fields +0 -31
- data/test/multipart/webkit +0 -32
- data/test/rackup/config.ru +0 -31
- data/test/registering_handler/rack/handler/registering_myself.rb +0 -8
- data/test/spec_auth_basic.rb +0 -81
- data/test/spec_auth_digest.rb +0 -259
- data/test/spec_body_proxy.rb +0 -85
- data/test/spec_builder.rb +0 -223
- data/test/spec_cascade.rb +0 -61
- data/test/spec_cgi.rb +0 -102
- data/test/spec_chunked.rb +0 -101
- data/test/spec_commonlogger.rb +0 -93
- data/test/spec_conditionalget.rb +0 -102
- data/test/spec_config.rb +0 -22
- data/test/spec_content_length.rb +0 -85
- data/test/spec_content_type.rb +0 -45
- data/test/spec_deflater.rb +0 -339
- data/test/spec_directory.rb +0 -88
- data/test/spec_etag.rb +0 -107
- data/test/spec_fastcgi.rb +0 -107
- data/test/spec_file.rb +0 -221
- data/test/spec_handler.rb +0 -72
- data/test/spec_head.rb +0 -45
- data/test/spec_lint.rb +0 -550
- data/test/spec_lobster.rb +0 -58
- data/test/spec_lock.rb +0 -164
- data/test/spec_logger.rb +0 -23
- data/test/spec_methodoverride.rb +0 -111
- data/test/spec_mime.rb +0 -51
- data/test/spec_mock.rb +0 -297
- data/test/spec_mongrel.rb +0 -182
- data/test/spec_multipart.rb +0 -600
- data/test/spec_nulllogger.rb +0 -20
- data/test/spec_recursive.rb +0 -72
- data/test/spec_request.rb +0 -1232
- data/test/spec_response.rb +0 -407
- data/test/spec_rewindable_input.rb +0 -118
- data/test/spec_runtime.rb +0 -49
- data/test/spec_sendfile.rb +0 -130
- data/test/spec_server.rb +0 -167
- data/test/spec_session_abstract_id.rb +0 -53
- data/test/spec_session_cookie.rb +0 -410
- data/test/spec_session_memcache.rb +0 -321
- data/test/spec_session_pool.rb +0 -209
- data/test/spec_showexceptions.rb +0 -98
- data/test/spec_showstatus.rb +0 -103
- data/test/spec_static.rb +0 -145
- data/test/spec_tempfile_reaper.rb +0 -63
- data/test/spec_thin.rb +0 -91
- data/test/spec_urlmap.rb +0 -236
- data/test/spec_utils.rb +0 -647
- data/test/spec_version.rb +0 -17
- data/test/spec_webrick.rb +0 -184
- data/test/static/another/index.html +0 -1
- data/test/static/index.html +0 -1
- data/test/testrequest.rb +0 -78
- data/test/unregistered_handler/rack/handler/unregistered.rb +0 -7
- data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +0 -7
data/test/spec_etag.rb
DELETED
@@ -1,107 +0,0 @@
|
|
1
|
-
require 'rack/etag'
|
2
|
-
require 'rack/lint'
|
3
|
-
require 'rack/mock'
|
4
|
-
require 'time'
|
5
|
-
|
6
|
-
describe Rack::ETag do
|
7
|
-
def etag(app, *args)
|
8
|
-
Rack::Lint.new Rack::ETag.new(app, *args)
|
9
|
-
end
|
10
|
-
|
11
|
-
def request
|
12
|
-
Rack::MockRequest.env_for
|
13
|
-
end
|
14
|
-
|
15
|
-
def sendfile_body
|
16
|
-
res = ['Hello World']
|
17
|
-
def res.to_path ; "/tmp/hello.txt" ; end
|
18
|
-
res
|
19
|
-
end
|
20
|
-
|
21
|
-
should "set ETag if none is set if status is 200" do
|
22
|
-
app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, ["Hello, World!"]] }
|
23
|
-
response = etag(app).call(request)
|
24
|
-
response[1]['ETag'].should.equal "W/\"65a8e27d8879283831b664bd8b7f0ad4\""
|
25
|
-
end
|
26
|
-
|
27
|
-
should "set ETag if none is set if status is 201" do
|
28
|
-
app = lambda { |env| [201, {'Content-Type' => 'text/plain'}, ["Hello, World!"]] }
|
29
|
-
response = etag(app).call(request)
|
30
|
-
response[1]['ETag'].should.equal "W/\"65a8e27d8879283831b664bd8b7f0ad4\""
|
31
|
-
end
|
32
|
-
|
33
|
-
should "set Cache-Control to 'max-age=0, private, must-revalidate' (default) if none is set" do
|
34
|
-
app = lambda { |env| [201, {'Content-Type' => 'text/plain'}, ["Hello, World!"]] }
|
35
|
-
response = etag(app).call(request)
|
36
|
-
response[1]['Cache-Control'].should.equal 'max-age=0, private, must-revalidate'
|
37
|
-
end
|
38
|
-
|
39
|
-
should "set Cache-Control to chosen one if none is set" do
|
40
|
-
app = lambda { |env| [201, {'Content-Type' => 'text/plain'}, ["Hello, World!"]] }
|
41
|
-
response = etag(app, nil, 'public').call(request)
|
42
|
-
response[1]['Cache-Control'].should.equal 'public'
|
43
|
-
end
|
44
|
-
|
45
|
-
should "set a given Cache-Control even if digest could not be calculated" do
|
46
|
-
app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, []] }
|
47
|
-
response = etag(app, 'no-cache').call(request)
|
48
|
-
response[1]['Cache-Control'].should.equal 'no-cache'
|
49
|
-
end
|
50
|
-
|
51
|
-
should "not set Cache-Control if it is already set" do
|
52
|
-
app = lambda { |env| [201, {'Content-Type' => 'text/plain', 'Cache-Control' => 'public'}, ["Hello, World!"]] }
|
53
|
-
response = etag(app).call(request)
|
54
|
-
response[1]['Cache-Control'].should.equal 'public'
|
55
|
-
end
|
56
|
-
|
57
|
-
should "not set Cache-Control if directive isn't present" do
|
58
|
-
app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, ["Hello, World!"]] }
|
59
|
-
response = etag(app, nil, nil).call(request)
|
60
|
-
response[1]['Cache-Control'].should.equal nil
|
61
|
-
end
|
62
|
-
|
63
|
-
should "not change ETag if it is already set" do
|
64
|
-
app = lambda { |env| [200, {'Content-Type' => 'text/plain', 'ETag' => '"abc"'}, ["Hello, World!"]] }
|
65
|
-
response = etag(app).call(request)
|
66
|
-
response[1]['ETag'].should.equal "\"abc\""
|
67
|
-
end
|
68
|
-
|
69
|
-
should "not set ETag if body is empty" do
|
70
|
-
app = lambda { |env| [200, {'Content-Type' => 'text/plain', 'Last-Modified' => Time.now.httpdate}, []] }
|
71
|
-
response = etag(app).call(request)
|
72
|
-
response[1]['ETag'].should.be.nil
|
73
|
-
end
|
74
|
-
|
75
|
-
should "not set ETag if Last-Modified is set" do
|
76
|
-
app = lambda { |env| [200, {'Content-Type' => 'text/plain', 'Last-Modified' => Time.now.httpdate}, ["Hello, World!"]] }
|
77
|
-
response = etag(app).call(request)
|
78
|
-
response[1]['ETag'].should.be.nil
|
79
|
-
end
|
80
|
-
|
81
|
-
should "not set ETag if a sendfile_body is given" do
|
82
|
-
app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, sendfile_body] }
|
83
|
-
response = etag(app).call(request)
|
84
|
-
response[1]['ETag'].should.be.nil
|
85
|
-
end
|
86
|
-
|
87
|
-
should "not set ETag if a status is not 200 or 201" do
|
88
|
-
app = lambda { |env| [401, {'Content-Type' => 'text/plain'}, ['Access denied.']] }
|
89
|
-
response = etag(app).call(request)
|
90
|
-
response[1]['ETag'].should.be.nil
|
91
|
-
end
|
92
|
-
|
93
|
-
should "not set ETag if no-cache is given" do
|
94
|
-
app = lambda { |env| [200, {'Content-Type' => 'text/plain', 'Cache-Control' => 'no-cache, must-revalidate'}, ['Hello, World!']] }
|
95
|
-
response = etag(app).call(request)
|
96
|
-
response[1]['ETag'].should.be.nil
|
97
|
-
end
|
98
|
-
|
99
|
-
should "close the original body" do
|
100
|
-
body = StringIO.new
|
101
|
-
app = lambda { |env| [200, {}, body] }
|
102
|
-
response = etag(app).call(request)
|
103
|
-
body.should.not.be.closed
|
104
|
-
response[2].close
|
105
|
-
body.should.be.closed
|
106
|
-
end
|
107
|
-
end
|
data/test/spec_fastcgi.rb
DELETED
@@ -1,107 +0,0 @@
|
|
1
|
-
begin
|
2
|
-
require File.expand_path('../testrequest', __FILE__)
|
3
|
-
require 'rack/handler/fastcgi'
|
4
|
-
|
5
|
-
describe Rack::Handler::FastCGI do
|
6
|
-
extend TestRequest::Helpers
|
7
|
-
|
8
|
-
@host = '127.0.0.1'
|
9
|
-
@port = 9203
|
10
|
-
|
11
|
-
if `which lighttpd` && !$?.success?
|
12
|
-
raise "lighttpd not found"
|
13
|
-
end
|
14
|
-
|
15
|
-
# Keep this first.
|
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
|
29
|
-
sleep 1
|
30
|
-
GET("/test")
|
31
|
-
response.should.not.be.nil
|
32
|
-
end
|
33
|
-
|
34
|
-
should "respond via rackup server" do
|
35
|
-
GET("/sample_rackup.ru")
|
36
|
-
status.should.equal 200
|
37
|
-
end
|
38
|
-
|
39
|
-
should "be a lighttpd" do
|
40
|
-
GET("/test.fcgi")
|
41
|
-
status.should.equal 200
|
42
|
-
response["SERVER_SOFTWARE"].should =~ /lighttpd/
|
43
|
-
response["HTTP_VERSION"].should.equal "HTTP/1.1"
|
44
|
-
response["SERVER_PROTOCOL"].should.equal "HTTP/1.1"
|
45
|
-
response["SERVER_PORT"].should.equal @port.to_s
|
46
|
-
response["SERVER_NAME"].should.equal @host
|
47
|
-
end
|
48
|
-
|
49
|
-
should "have rack headers" do
|
50
|
-
GET("/test.fcgi")
|
51
|
-
response["rack.version"].should.equal [1,3]
|
52
|
-
response["rack.multithread"].should.be.false
|
53
|
-
response["rack.multiprocess"].should.be.true
|
54
|
-
response["rack.run_once"].should.be.false
|
55
|
-
end
|
56
|
-
|
57
|
-
should "have CGI headers on GET" do
|
58
|
-
GET("/test.fcgi")
|
59
|
-
response["REQUEST_METHOD"].should.equal "GET"
|
60
|
-
response["SCRIPT_NAME"].should.equal "/test.fcgi"
|
61
|
-
response["REQUEST_PATH"].should.equal "/"
|
62
|
-
response["PATH_INFO"].should.equal ""
|
63
|
-
response["QUERY_STRING"].should.equal ""
|
64
|
-
response["test.postdata"].should.equal ""
|
65
|
-
|
66
|
-
GET("/test.fcgi/foo?quux=1")
|
67
|
-
response["REQUEST_METHOD"].should.equal "GET"
|
68
|
-
response["SCRIPT_NAME"].should.equal "/test.fcgi"
|
69
|
-
response["REQUEST_PATH"].should.equal "/"
|
70
|
-
response["PATH_INFO"].should.equal "/foo"
|
71
|
-
response["QUERY_STRING"].should.equal "quux=1"
|
72
|
-
end
|
73
|
-
|
74
|
-
should "have CGI headers on POST" do
|
75
|
-
POST("/test.fcgi", {"rack-form-data" => "23"}, {'X-test-header' => '42'})
|
76
|
-
status.should.equal 200
|
77
|
-
response["REQUEST_METHOD"].should.equal "POST"
|
78
|
-
response["SCRIPT_NAME"].should.equal "/test.fcgi"
|
79
|
-
response["REQUEST_PATH"].should.equal "/"
|
80
|
-
response["QUERY_STRING"].should.equal ""
|
81
|
-
response["HTTP_X_TEST_HEADER"].should.equal "42"
|
82
|
-
response["test.postdata"].should.equal "rack-form-data=23"
|
83
|
-
end
|
84
|
-
|
85
|
-
should "support HTTP auth" do
|
86
|
-
GET("/test.fcgi", {:user => "ruth", :passwd => "secret"})
|
87
|
-
response["HTTP_AUTHORIZATION"].should.equal "Basic cnV0aDpzZWNyZXQ="
|
88
|
-
end
|
89
|
-
|
90
|
-
should "set status" do
|
91
|
-
GET("/test.fcgi?secret")
|
92
|
-
status.should.equal 403
|
93
|
-
response["rack.url_scheme"].should.equal "http"
|
94
|
-
end
|
95
|
-
|
96
|
-
# Keep this last.
|
97
|
-
should "shutdown" do
|
98
|
-
Process.kill 15, $pid
|
99
|
-
Process.wait($pid).should.equal $pid
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
rescue RuntimeError
|
104
|
-
$stderr.puts "Skipping Rack::Handler::FastCGI tests (lighttpd is required). Install lighttpd and try again."
|
105
|
-
rescue LoadError
|
106
|
-
$stderr.puts "Skipping Rack::Handler::FastCGI tests (FCGI is required). `gem install fcgi` and try again."
|
107
|
-
end
|
data/test/spec_file.rb
DELETED
@@ -1,221 +0,0 @@
|
|
1
|
-
require 'rack/file'
|
2
|
-
require 'rack/lint'
|
3
|
-
require 'rack/mock'
|
4
|
-
|
5
|
-
describe Rack::File do
|
6
|
-
DOCROOT = File.expand_path(File.dirname(__FILE__)) unless defined? DOCROOT
|
7
|
-
|
8
|
-
def file(*args)
|
9
|
-
Rack::Lint.new Rack::File.new(*args)
|
10
|
-
end
|
11
|
-
|
12
|
-
should "serve files" do
|
13
|
-
res = Rack::MockRequest.new(file(DOCROOT)).get("/cgi/test")
|
14
|
-
|
15
|
-
res.should.be.ok
|
16
|
-
res.should =~ /ruby/
|
17
|
-
end
|
18
|
-
|
19
|
-
should "set Last-Modified header" do
|
20
|
-
res = Rack::MockRequest.new(file(DOCROOT)).get("/cgi/test")
|
21
|
-
|
22
|
-
path = File.join(DOCROOT, "/cgi/test")
|
23
|
-
|
24
|
-
res.should.be.ok
|
25
|
-
res["Last-Modified"].should.equal File.mtime(path).httpdate
|
26
|
-
end
|
27
|
-
|
28
|
-
should "return 304 if file isn't modified since last serve" do
|
29
|
-
path = File.join(DOCROOT, "/cgi/test")
|
30
|
-
res = Rack::MockRequest.new(file(DOCROOT)).
|
31
|
-
get("/cgi/test", 'HTTP_IF_MODIFIED_SINCE' => File.mtime(path).httpdate)
|
32
|
-
|
33
|
-
res.status.should.equal 304
|
34
|
-
res.body.should.be.empty
|
35
|
-
end
|
36
|
-
|
37
|
-
should "return the file if it's modified since last serve" do
|
38
|
-
path = File.join(DOCROOT, "/cgi/test")
|
39
|
-
res = Rack::MockRequest.new(file(DOCROOT)).
|
40
|
-
get("/cgi/test", 'HTTP_IF_MODIFIED_SINCE' => (File.mtime(path) - 100).httpdate)
|
41
|
-
|
42
|
-
res.should.be.ok
|
43
|
-
end
|
44
|
-
|
45
|
-
should "serve files with URL encoded filenames" do
|
46
|
-
res = Rack::MockRequest.new(file(DOCROOT)).get("/cgi/%74%65%73%74") # "/cgi/test"
|
47
|
-
|
48
|
-
res.should.be.ok
|
49
|
-
res.should =~ /ruby/
|
50
|
-
end
|
51
|
-
|
52
|
-
should "allow safe directory traversal" do
|
53
|
-
req = Rack::MockRequest.new(file(DOCROOT))
|
54
|
-
|
55
|
-
res = req.get('/cgi/../cgi/test')
|
56
|
-
res.should.be.successful
|
57
|
-
|
58
|
-
res = req.get('.')
|
59
|
-
res.should.be.not_found
|
60
|
-
|
61
|
-
res = req.get("test/..")
|
62
|
-
res.should.be.not_found
|
63
|
-
end
|
64
|
-
|
65
|
-
should "not allow unsafe directory traversal" do
|
66
|
-
req = Rack::MockRequest.new(file(DOCROOT))
|
67
|
-
|
68
|
-
res = req.get("/../README.rdoc")
|
69
|
-
res.should.be.client_error
|
70
|
-
|
71
|
-
res = req.get("../test/spec_file.rb")
|
72
|
-
res.should.be.client_error
|
73
|
-
|
74
|
-
res = req.get("../README.rdoc")
|
75
|
-
res.should.be.client_error
|
76
|
-
|
77
|
-
res.should.be.not_found
|
78
|
-
end
|
79
|
-
|
80
|
-
should "allow files with .. in their name" do
|
81
|
-
req = Rack::MockRequest.new(file(DOCROOT))
|
82
|
-
res = req.get("/cgi/..test")
|
83
|
-
res.should.be.not_found
|
84
|
-
|
85
|
-
res = req.get("/cgi/test..")
|
86
|
-
res.should.be.not_found
|
87
|
-
|
88
|
-
res = req.get("/cgi../test..")
|
89
|
-
res.should.be.not_found
|
90
|
-
end
|
91
|
-
|
92
|
-
should "not allow unsafe directory traversal with encoded periods" do
|
93
|
-
res = Rack::MockRequest.new(file(DOCROOT)).get("/%2E%2E/README")
|
94
|
-
|
95
|
-
res.should.be.client_error?
|
96
|
-
res.should.be.not_found
|
97
|
-
end
|
98
|
-
|
99
|
-
should "allow safe directory traversal with encoded periods" do
|
100
|
-
res = Rack::MockRequest.new(file(DOCROOT)).get("/cgi/%2E%2E/cgi/test")
|
101
|
-
|
102
|
-
res.should.be.successful
|
103
|
-
end
|
104
|
-
|
105
|
-
should "404 if it can't find the file" do
|
106
|
-
res = Rack::MockRequest.new(file(DOCROOT)).get("/cgi/blubb")
|
107
|
-
|
108
|
-
res.should.be.not_found
|
109
|
-
end
|
110
|
-
|
111
|
-
should "detect SystemCallErrors" do
|
112
|
-
res = Rack::MockRequest.new(file(DOCROOT)).get("/cgi")
|
113
|
-
|
114
|
-
res.should.be.not_found
|
115
|
-
end
|
116
|
-
|
117
|
-
should "return bodies that respond to #to_path" do
|
118
|
-
env = Rack::MockRequest.env_for("/cgi/test")
|
119
|
-
status, _, body = Rack::File.new(DOCROOT).call(env)
|
120
|
-
|
121
|
-
path = File.join(DOCROOT, "/cgi/test")
|
122
|
-
|
123
|
-
status.should.equal 200
|
124
|
-
body.should.respond_to :to_path
|
125
|
-
body.to_path.should.equal path
|
126
|
-
end
|
127
|
-
|
128
|
-
should "return correct byte range in body" do
|
129
|
-
env = Rack::MockRequest.env_for("/cgi/test")
|
130
|
-
env["HTTP_RANGE"] = "bytes=22-33"
|
131
|
-
res = Rack::MockResponse.new(*file(DOCROOT).call(env))
|
132
|
-
|
133
|
-
res.status.should.equal 206
|
134
|
-
res["Content-Length"].should.equal "12"
|
135
|
-
res["Content-Range"].should.equal "bytes 22-33/193"
|
136
|
-
res.body.should.equal "-*- ruby -*-"
|
137
|
-
end
|
138
|
-
|
139
|
-
should "return error for unsatisfiable byte range" do
|
140
|
-
env = Rack::MockRequest.env_for("/cgi/test")
|
141
|
-
env["HTTP_RANGE"] = "bytes=1234-5678"
|
142
|
-
res = Rack::MockResponse.new(*file(DOCROOT).call(env))
|
143
|
-
|
144
|
-
res.status.should.equal 416
|
145
|
-
res["Content-Range"].should.equal "bytes */193"
|
146
|
-
end
|
147
|
-
|
148
|
-
should "support custom http headers" do
|
149
|
-
env = Rack::MockRequest.env_for("/cgi/test")
|
150
|
-
status, heads, _ = file(DOCROOT, 'Cache-Control' => 'public, max-age=38',
|
151
|
-
'Access-Control-Allow-Origin' => '*').call(env)
|
152
|
-
|
153
|
-
status.should.equal 200
|
154
|
-
heads['Cache-Control'].should.equal 'public, max-age=38'
|
155
|
-
heads['Access-Control-Allow-Origin'].should.equal '*'
|
156
|
-
end
|
157
|
-
|
158
|
-
should "support not add custom http headers if none are supplied" do
|
159
|
-
env = Rack::MockRequest.env_for("/cgi/test")
|
160
|
-
status, heads, _ = file(DOCROOT).call(env)
|
161
|
-
|
162
|
-
status.should.equal 200
|
163
|
-
heads['Cache-Control'].should.equal nil
|
164
|
-
heads['Access-Control-Allow-Origin'].should.equal nil
|
165
|
-
end
|
166
|
-
|
167
|
-
should "only support GET, HEAD, and OPTIONS requests" do
|
168
|
-
req = Rack::MockRequest.new(file(DOCROOT))
|
169
|
-
|
170
|
-
forbidden = %w[post put patch delete]
|
171
|
-
forbidden.each do |method|
|
172
|
-
res = req.send(method, "/cgi/test")
|
173
|
-
res.should.be.client_error
|
174
|
-
res.should.be.method_not_allowed
|
175
|
-
res.headers['Allow'].split(/, */).sort.should == %w(GET HEAD OPTIONS)
|
176
|
-
end
|
177
|
-
|
178
|
-
allowed = %w[get head options]
|
179
|
-
allowed.each do |method|
|
180
|
-
res = req.send(method, "/cgi/test")
|
181
|
-
res.should.be.successful
|
182
|
-
end
|
183
|
-
end
|
184
|
-
|
185
|
-
should "set Allow correctly for OPTIONS requests" do
|
186
|
-
req = Rack::MockRequest.new(file(DOCROOT))
|
187
|
-
res = req.options('/cgi/test')
|
188
|
-
res.should.be.successful
|
189
|
-
res.headers['Allow'].should.not.equal nil
|
190
|
-
res.headers['Allow'].split(/, */).sort.should == %w(GET HEAD OPTIONS)
|
191
|
-
end
|
192
|
-
|
193
|
-
should "set Content-Length correctly for HEAD requests" do
|
194
|
-
req = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT)))
|
195
|
-
res = req.head "/cgi/test"
|
196
|
-
res.should.be.successful
|
197
|
-
res['Content-Length'].should.equal "193"
|
198
|
-
end
|
199
|
-
|
200
|
-
should "default to a mime type of text/plain" do
|
201
|
-
req = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT)))
|
202
|
-
res = req.get "/cgi/test"
|
203
|
-
res.should.be.successful
|
204
|
-
res['Content-Type'].should.equal "text/plain"
|
205
|
-
end
|
206
|
-
|
207
|
-
should "allow the default mime type to be set" do
|
208
|
-
req = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT, nil, 'application/octet-stream')))
|
209
|
-
res = req.get "/cgi/test"
|
210
|
-
res.should.be.successful
|
211
|
-
res['Content-Type'].should.equal "application/octet-stream"
|
212
|
-
end
|
213
|
-
|
214
|
-
should "not set Content-Type if the mime type is not set" do
|
215
|
-
req = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT, nil, nil)))
|
216
|
-
res = req.get "/cgi/test"
|
217
|
-
res.should.be.successful
|
218
|
-
res['Content-Type'].should.equal nil
|
219
|
-
end
|
220
|
-
|
221
|
-
end
|
data/test/spec_handler.rb
DELETED
@@ -1,72 +0,0 @@
|
|
1
|
-
require 'rack/handler'
|
2
|
-
|
3
|
-
class Rack::Handler::Lobster; end
|
4
|
-
class RockLobster; end
|
5
|
-
|
6
|
-
describe Rack::Handler do
|
7
|
-
it "has registered default handlers" do
|
8
|
-
Rack::Handler.get('cgi').should.equal Rack::Handler::CGI
|
9
|
-
Rack::Handler.get('webrick').should.equal Rack::Handler::WEBrick
|
10
|
-
|
11
|
-
begin
|
12
|
-
Rack::Handler.get('fastcgi').should.equal Rack::Handler::FastCGI
|
13
|
-
rescue LoadError
|
14
|
-
end
|
15
|
-
|
16
|
-
begin
|
17
|
-
Rack::Handler.get('mongrel').should.equal Rack::Handler::Mongrel
|
18
|
-
rescue LoadError
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
should "raise LoadError if handler doesn't exist" do
|
23
|
-
lambda {
|
24
|
-
Rack::Handler.get('boom')
|
25
|
-
}.should.raise(LoadError)
|
26
|
-
end
|
27
|
-
|
28
|
-
should "raise LoadError if handler isn't nested under Rack::Handler" do
|
29
|
-
# Feature-detect whether Ruby can do non-inherited const lookups.
|
30
|
-
# If it can't, then Rack::Handler may lookup non-handler toplevel
|
31
|
-
# constants, so the best we can do is no-op here and not test it.
|
32
|
-
begin
|
33
|
-
Rack::Handler._const_get('Object', false)
|
34
|
-
rescue NameError
|
35
|
-
lambda {
|
36
|
-
Rack::Handler.get('Object')
|
37
|
-
}.should.raise(LoadError)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
should "get unregistered, but already required, handler by name" do
|
42
|
-
Rack::Handler.get('Lobster').should.equal Rack::Handler::Lobster
|
43
|
-
end
|
44
|
-
|
45
|
-
should "register custom handler" do
|
46
|
-
Rack::Handler.register('rock_lobster', 'RockLobster')
|
47
|
-
Rack::Handler.get('rock_lobster').should.equal RockLobster
|
48
|
-
end
|
49
|
-
|
50
|
-
should "not need registration for properly coded handlers even if not already required" do
|
51
|
-
begin
|
52
|
-
$LOAD_PATH.push File.expand_path('../unregistered_handler', __FILE__)
|
53
|
-
Rack::Handler.get('Unregistered').should.equal Rack::Handler::Unregistered
|
54
|
-
lambda {
|
55
|
-
Rack::Handler.get('UnRegistered')
|
56
|
-
}.should.raise LoadError
|
57
|
-
Rack::Handler.get('UnregisteredLongOne').should.equal Rack::Handler::UnregisteredLongOne
|
58
|
-
ensure
|
59
|
-
$LOAD_PATH.delete File.expand_path('../unregistered_handler', __FILE__)
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
should "allow autoloaded handlers to be registered properly while being loaded" do
|
64
|
-
path = File.expand_path('../registering_handler', __FILE__)
|
65
|
-
begin
|
66
|
-
$LOAD_PATH.push path
|
67
|
-
Rack::Handler.get('registering_myself').should.equal Rack::Handler::RegisteringMyself
|
68
|
-
ensure
|
69
|
-
$LOAD_PATH.delete path
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
data/test/spec_head.rb
DELETED
@@ -1,45 +0,0 @@
|
|
1
|
-
require 'rack/head'
|
2
|
-
require 'rack/lint'
|
3
|
-
require 'rack/mock'
|
4
|
-
|
5
|
-
describe Rack::Head do
|
6
|
-
|
7
|
-
def test_response(headers = {})
|
8
|
-
body = StringIO.new "foo"
|
9
|
-
app = lambda do |env|
|
10
|
-
[200, {"Content-type" => "test/plain", "Content-length" => "3"}, body]
|
11
|
-
end
|
12
|
-
request = Rack::MockRequest.env_for("/", headers)
|
13
|
-
response = Rack::Lint.new(Rack::Head.new(app)).call(request)
|
14
|
-
|
15
|
-
return response, body
|
16
|
-
end
|
17
|
-
|
18
|
-
should "pass GET, POST, PUT, DELETE, OPTIONS, TRACE requests" do
|
19
|
-
%w[GET POST PUT DELETE OPTIONS TRACE].each do |type|
|
20
|
-
resp, _ = test_response("REQUEST_METHOD" => type)
|
21
|
-
|
22
|
-
resp[0].should.equal(200)
|
23
|
-
resp[1].should.equal({"Content-type" => "test/plain", "Content-length" => "3"})
|
24
|
-
resp[2].to_enum.to_a.should.equal(["foo"])
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
should "remove body from HEAD requests" do
|
29
|
-
resp, _ = test_response("REQUEST_METHOD" => "HEAD")
|
30
|
-
|
31
|
-
resp[0].should.equal(200)
|
32
|
-
resp[1].should.equal({"Content-type" => "test/plain", "Content-length" => "3"})
|
33
|
-
resp[2].to_enum.to_a.should.equal([])
|
34
|
-
end
|
35
|
-
|
36
|
-
should "close the body when it is removed" do
|
37
|
-
resp, body = test_response("REQUEST_METHOD" => "HEAD")
|
38
|
-
resp[0].should.equal(200)
|
39
|
-
resp[1].should.equal({"Content-type" => "test/plain", "Content-length" => "3"})
|
40
|
-
resp[2].to_enum.to_a.should.equal([])
|
41
|
-
body.should.not.be.closed
|
42
|
-
resp[2].close
|
43
|
-
body.should.be.closed
|
44
|
-
end
|
45
|
-
end
|