rack 1.4.7 → 2.1.4
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 +5 -5
- data/CHANGELOG.md +77 -0
- data/{COPYING → MIT-LICENSE} +4 -2
- data/README.rdoc +122 -456
- data/Rakefile +32 -31
- data/SPEC +119 -29
- 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 +7 -5
- data/lib/rack/auth/abstract/request.rb +8 -6
- data/lib/rack/auth/basic.rb +5 -2
- data/lib/rack/auth/digest/md5.rb +10 -8
- 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 +4 -2
- data/lib/rack/body_proxy.rb +11 -9
- data/lib/rack/builder.rb +63 -20
- data/lib/rack/cascade.rb +10 -9
- data/lib/rack/chunked.rb +45 -11
- data/lib/rack/{commonlogger.rb → common_logger.rb} +24 -15
- data/lib/rack/{conditionalget.rb → conditional_get.rb} +20 -6
- data/lib/rack/config.rb +7 -0
- data/lib/rack/content_length.rb +12 -6
- data/lib/rack/content_type.rb +4 -2
- data/lib/rack/core_ext/regexp.rb +14 -0
- data/lib/rack/deflater.rb +73 -42
- data/lib/rack/directory.rb +77 -56
- data/lib/rack/etag.rb +25 -13
- data/lib/rack/events.rb +156 -0
- data/lib/rack/file.rb +4 -143
- data/lib/rack/files.rb +178 -0
- data/lib/rack/handler/cgi.rb +18 -17
- data/lib/rack/handler/fastcgi.rb +21 -17
- data/lib/rack/handler/lsws.rb +14 -12
- data/lib/rack/handler/scgi.rb +27 -21
- data/lib/rack/handler/thin.rb +19 -5
- data/lib/rack/handler/webrick.rb +66 -24
- data/lib/rack/handler.rb +29 -19
- data/lib/rack/head.rb +21 -14
- data/lib/rack/lint.rb +259 -65
- data/lib/rack/lobster.rb +17 -10
- data/lib/rack/lock.rb +19 -10
- data/lib/rack/logger.rb +4 -2
- data/lib/rack/media_type.rb +43 -0
- data/lib/rack/method_override.rb +52 -0
- data/lib/rack/mime.rb +43 -6
- data/lib/rack/mock.rb +109 -44
- data/lib/rack/multipart/generator.rb +11 -12
- data/lib/rack/multipart/parser.rb +302 -115
- data/lib/rack/multipart/uploaded_file.rb +4 -3
- data/lib/rack/multipart.rb +40 -9
- data/lib/rack/null_logger.rb +39 -0
- data/lib/rack/query_parser.rb +218 -0
- data/lib/rack/recursive.rb +14 -11
- data/lib/rack/reloader.rb +12 -5
- data/lib/rack/request.rb +484 -270
- data/lib/rack/response.rb +196 -77
- data/lib/rack/rewindable_input.rb +5 -14
- data/lib/rack/runtime.rb +13 -6
- data/lib/rack/sendfile.rb +44 -20
- data/lib/rack/server.rb +175 -61
- data/lib/rack/session/abstract/id.rb +276 -133
- data/lib/rack/session/cookie.rb +75 -40
- data/lib/rack/session/memcache.rb +4 -87
- data/lib/rack/session/pool.rb +24 -18
- data/lib/rack/show_exceptions.rb +392 -0
- data/lib/rack/{showstatus.rb → show_status.rb} +11 -9
- data/lib/rack/static.rb +65 -38
- data/lib/rack/tempfile_reaper.rb +24 -0
- data/lib/rack/urlmap.rb +40 -15
- data/lib/rack/utils.rb +316 -285
- data/lib/rack.rb +78 -23
- data/rack.gemspec +26 -19
- metadata +44 -209
- data/KNOWN-ISSUES +0 -30
- 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 -100
- data/lib/rack/handler/swiftiplied_mongrel.rb +0 -8
- data/lib/rack/methodoverride.rb +0 -33
- data/lib/rack/nulllogger.rb +0 -18
- data/lib/rack/showexceptions.rb +0 -378
- 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/lighttpd.errors +0 -1
- 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_with_escaped_quotes +0 -6
- data/test/multipart/filename_with_escaped_quotes_and_modification_param +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/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.rb +0 -57
- data/test/spec_auth_basic.rb +0 -81
- data/test/spec_auth_digest.rb +0 -259
- data/test/spec_body_proxy.rb +0 -69
- data/test/spec_builder.rb +0 -207
- data/test/spec_cascade.rb +0 -61
- data/test/spec_cgi.rb +0 -102
- data/test/spec_chunked.rb +0 -87
- data/test/spec_commonlogger.rb +0 -57
- data/test/spec_conditionalget.rb +0 -102
- data/test/spec_config.rb +0 -22
- data/test/spec_content_length.rb +0 -86
- data/test/spec_content_type.rb +0 -45
- data/test/spec_deflater.rb +0 -187
- data/test/spec_directory.rb +0 -88
- data/test/spec_etag.rb +0 -98
- data/test/spec_fastcgi.rb +0 -107
- data/test/spec_file.rb +0 -200
- data/test/spec_handler.rb +0 -59
- data/test/spec_head.rb +0 -48
- data/test/spec_lint.rb +0 -515
- data/test/spec_lobster.rb +0 -58
- data/test/spec_lock.rb +0 -167
- data/test/spec_logger.rb +0 -23
- data/test/spec_methodoverride.rb +0 -72
- data/test/spec_mock.rb +0 -269
- data/test/spec_mongrel.rb +0 -182
- data/test/spec_multipart.rb +0 -479
- data/test/spec_nulllogger.rb +0 -23
- data/test/spec_recursive.rb +0 -72
- data/test/spec_request.rb +0 -955
- data/test/spec_response.rb +0 -313
- data/test/spec_rewindable_input.rb +0 -118
- data/test/spec_runtime.rb +0 -49
- data/test/spec_sendfile.rb +0 -90
- data/test/spec_server.rb +0 -121
- data/test/spec_session_abstract_id.rb +0 -43
- data/test/spec_session_cookie.rb +0 -361
- data/test/spec_session_memcache.rb +0 -321
- data/test/spec_session_pool.rb +0 -209
- data/test/spec_showexceptions.rb +0 -92
- data/test/spec_showstatus.rb +0 -84
- data/test/spec_static.rb +0 -145
- data/test/spec_thin.rb +0 -86
- data/test/spec_urlmap.rb +0 -213
- data/test/spec_utils.rb +0 -554
- data/test/spec_webrick.rb +0 -143
- 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_config.rb
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
require 'rack/builder'
|
2
|
-
require 'rack/config'
|
3
|
-
require 'rack/content_length'
|
4
|
-
require 'rack/lint'
|
5
|
-
require 'rack/mock'
|
6
|
-
|
7
|
-
describe Rack::Config do
|
8
|
-
should "accept a block that modifies the environment" do
|
9
|
-
app = Rack::Builder.new do
|
10
|
-
use Rack::Lint
|
11
|
-
use Rack::Config do |env|
|
12
|
-
env['greeting'] = 'hello'
|
13
|
-
end
|
14
|
-
run lambda { |env|
|
15
|
-
[200, {'Content-Type' => 'text/plain'}, [env['greeting'] || '']]
|
16
|
-
}
|
17
|
-
end
|
18
|
-
|
19
|
-
response = Rack::MockRequest.new(app).get('/')
|
20
|
-
response.body.should.equal('hello')
|
21
|
-
end
|
22
|
-
end
|
data/test/spec_content_length.rb
DELETED
@@ -1,86 +0,0 @@
|
|
1
|
-
require 'enumerator'
|
2
|
-
require 'rack/content_length'
|
3
|
-
require 'rack/lint'
|
4
|
-
require 'rack/mock'
|
5
|
-
|
6
|
-
describe Rack::ContentLength do
|
7
|
-
::Enumerator = ::Enumerable::Enumerator unless Object.const_defined?(:Enumerator)
|
8
|
-
|
9
|
-
def content_length(app)
|
10
|
-
Rack::Lint.new Rack::ContentLength.new(app)
|
11
|
-
end
|
12
|
-
|
13
|
-
def request
|
14
|
-
Rack::MockRequest.env_for
|
15
|
-
end
|
16
|
-
|
17
|
-
should "set Content-Length on Array bodies if none is set" do
|
18
|
-
app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, ["Hello, World!"]] }
|
19
|
-
response = content_length(app).call(request)
|
20
|
-
response[1]['Content-Length'].should.equal '13'
|
21
|
-
end
|
22
|
-
|
23
|
-
should "not set Content-Length on variable length bodies" do
|
24
|
-
body = lambda { "Hello World!" }
|
25
|
-
def body.each ; yield call ; end
|
26
|
-
|
27
|
-
app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, body] }
|
28
|
-
response = content_length(app).call(request)
|
29
|
-
response[1]['Content-Length'].should.be.nil
|
30
|
-
end
|
31
|
-
|
32
|
-
should "not change Content-Length if it is already set" do
|
33
|
-
app = lambda { |env| [200, {'Content-Type' => 'text/plain', 'Content-Length' => '1'}, "Hello, World!"] }
|
34
|
-
response = content_length(app).call(request)
|
35
|
-
response[1]['Content-Length'].should.equal '1'
|
36
|
-
end
|
37
|
-
|
38
|
-
should "not set Content-Length on 304 responses" do
|
39
|
-
app = lambda { |env| [304, {}, []] }
|
40
|
-
response = content_length(app).call(request)
|
41
|
-
response[1]['Content-Length'].should.equal nil
|
42
|
-
end
|
43
|
-
|
44
|
-
should "not set Content-Length when Transfer-Encoding is chunked" do
|
45
|
-
app = lambda { |env| [200, {'Content-Type' => 'text/plain', 'Transfer-Encoding' => 'chunked'}, []] }
|
46
|
-
response = content_length(app).call(request)
|
47
|
-
response[1]['Content-Length'].should.equal nil
|
48
|
-
end
|
49
|
-
|
50
|
-
# Using "Connection: close" for this is fairly contended. It might be useful
|
51
|
-
# to have some other way to signal this.
|
52
|
-
#
|
53
|
-
# should "not force a Content-Length when Connection:close" do
|
54
|
-
# app = lambda { |env| [200, {'Connection' => 'close'}, []] }
|
55
|
-
# response = content_length(app).call({})
|
56
|
-
# response[1]['Content-Length'].should.equal nil
|
57
|
-
# end
|
58
|
-
|
59
|
-
should "close bodies that need to be closed" do
|
60
|
-
body = Struct.new(:body) do
|
61
|
-
attr_reader :closed
|
62
|
-
def each; body.join; end
|
63
|
-
def close; @closed = true; end
|
64
|
-
def to_ary; end
|
65
|
-
end.new(%w[one two three])
|
66
|
-
|
67
|
-
app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, body] }
|
68
|
-
content_length(app).call(request)
|
69
|
-
body.closed.should.equal true
|
70
|
-
end
|
71
|
-
|
72
|
-
should "support single-execute bodies" do
|
73
|
-
body = Struct.new(:body) do
|
74
|
-
def each
|
75
|
-
yield body.shift until body.empty?
|
76
|
-
end
|
77
|
-
def to_ary; end
|
78
|
-
end.new(%w[one two three])
|
79
|
-
|
80
|
-
app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, body] }
|
81
|
-
response = content_length(app).call(request)
|
82
|
-
expected = %w[one two three]
|
83
|
-
response[1]['Content-Length'].should.equal expected.join.size.to_s
|
84
|
-
Enumerator.new(response[2]).to_a.should.equal expected
|
85
|
-
end
|
86
|
-
end
|
data/test/spec_content_type.rb
DELETED
@@ -1,45 +0,0 @@
|
|
1
|
-
require 'rack/content_type'
|
2
|
-
require 'rack/lint'
|
3
|
-
require 'rack/mock'
|
4
|
-
|
5
|
-
describe Rack::ContentType do
|
6
|
-
def content_type(app, *args)
|
7
|
-
Rack::Lint.new Rack::ContentType.new(app, *args)
|
8
|
-
end
|
9
|
-
|
10
|
-
def request
|
11
|
-
Rack::MockRequest.env_for
|
12
|
-
end
|
13
|
-
|
14
|
-
should "set Content-Type to default text/html if none is set" do
|
15
|
-
app = lambda { |env| [200, {}, "Hello, World!"] }
|
16
|
-
headers = content_type(app).call(request)[1]
|
17
|
-
headers['Content-Type'].should.equal 'text/html'
|
18
|
-
end
|
19
|
-
|
20
|
-
should "set Content-Type to chosen default if none is set" do
|
21
|
-
app = lambda { |env| [200, {}, "Hello, World!"] }
|
22
|
-
headers =
|
23
|
-
content_type(app, 'application/octet-stream').call(request)[1]
|
24
|
-
headers['Content-Type'].should.equal 'application/octet-stream'
|
25
|
-
end
|
26
|
-
|
27
|
-
should "not change Content-Type if it is already set" do
|
28
|
-
app = lambda { |env| [200, {'Content-Type' => 'foo/bar'}, "Hello, World!"] }
|
29
|
-
headers = content_type(app).call(request)[1]
|
30
|
-
headers['Content-Type'].should.equal 'foo/bar'
|
31
|
-
end
|
32
|
-
|
33
|
-
should "detect Content-Type case insensitive" do
|
34
|
-
app = lambda { |env| [200, {'CONTENT-Type' => 'foo/bar'}, "Hello, World!"] }
|
35
|
-
headers = content_type(app).call(request)[1]
|
36
|
-
headers.to_a.select { |k,v| k.downcase == "content-type" }.
|
37
|
-
should.equal [["CONTENT-Type","foo/bar"]]
|
38
|
-
end
|
39
|
-
|
40
|
-
should "not set Content-Type on 304 responses" do
|
41
|
-
app = lambda { |env| [304, {}, []] }
|
42
|
-
response = content_type(app, "text/html").call(request)
|
43
|
-
response[1]['Content-Type'].should.equal nil
|
44
|
-
end
|
45
|
-
end
|
data/test/spec_deflater.rb
DELETED
@@ -1,187 +0,0 @@
|
|
1
|
-
require 'enumerator'
|
2
|
-
require 'stringio'
|
3
|
-
require 'time' # for Time#httpdate
|
4
|
-
require 'rack/deflater'
|
5
|
-
require 'rack/lint'
|
6
|
-
require 'rack/mock'
|
7
|
-
require 'zlib'
|
8
|
-
|
9
|
-
describe Rack::Deflater do
|
10
|
-
::Enumerator = ::Enumerable::Enumerator unless Object.const_defined?(:Enumerator)
|
11
|
-
|
12
|
-
def deflater(app)
|
13
|
-
Rack::Lint.new Rack::Deflater.new(app)
|
14
|
-
end
|
15
|
-
|
16
|
-
def build_response(status, body, accept_encoding, headers = {})
|
17
|
-
body = [body] if body.respond_to? :to_str
|
18
|
-
app = lambda do |env|
|
19
|
-
res = [status, {}, body]
|
20
|
-
res[1]["Content-Type"] = "text/plain" unless res[0] == 304
|
21
|
-
res
|
22
|
-
end
|
23
|
-
request = Rack::MockRequest.env_for("", headers.merge("HTTP_ACCEPT_ENCODING" => accept_encoding))
|
24
|
-
response = deflater(app).call(request)
|
25
|
-
|
26
|
-
return response
|
27
|
-
end
|
28
|
-
|
29
|
-
def inflate(buf)
|
30
|
-
inflater = Zlib::Inflate.new(-Zlib::MAX_WBITS)
|
31
|
-
inflater.inflate(buf) << inflater.finish
|
32
|
-
end
|
33
|
-
|
34
|
-
should "be able to deflate bodies that respond to each" do
|
35
|
-
body = Object.new
|
36
|
-
class << body; def each; yield("foo"); yield("bar"); end; end
|
37
|
-
|
38
|
-
response = build_response(200, body, "deflate")
|
39
|
-
|
40
|
-
response[0].should.equal(200)
|
41
|
-
response[1].should.equal({
|
42
|
-
"Content-Encoding" => "deflate",
|
43
|
-
"Vary" => "Accept-Encoding",
|
44
|
-
"Content-Type" => "text/plain"
|
45
|
-
})
|
46
|
-
buf = ''
|
47
|
-
response[2].each { |part| buf << part }
|
48
|
-
inflate(buf).should.equal("foobar")
|
49
|
-
end
|
50
|
-
|
51
|
-
should "flush deflated chunks to the client as they become ready" do
|
52
|
-
body = Object.new
|
53
|
-
class << body; def each; yield("foo"); yield("bar"); end; end
|
54
|
-
|
55
|
-
response = build_response(200, body, "deflate")
|
56
|
-
|
57
|
-
response[0].should.equal(200)
|
58
|
-
response[1].should.equal({
|
59
|
-
"Content-Encoding" => "deflate",
|
60
|
-
"Vary" => "Accept-Encoding",
|
61
|
-
"Content-Type" => "text/plain"
|
62
|
-
})
|
63
|
-
buf = []
|
64
|
-
inflater = Zlib::Inflate.new(-Zlib::MAX_WBITS)
|
65
|
-
response[2].each { |part| buf << inflater.inflate(part) }
|
66
|
-
buf << inflater.finish
|
67
|
-
buf.delete_if { |part| part.empty? }
|
68
|
-
buf.join.should.equal("foobar")
|
69
|
-
end
|
70
|
-
|
71
|
-
# TODO: This is really just a special case of the above...
|
72
|
-
should "be able to deflate String bodies" do
|
73
|
-
response = build_response(200, "Hello world!", "deflate")
|
74
|
-
|
75
|
-
response[0].should.equal(200)
|
76
|
-
response[1].should.equal({
|
77
|
-
"Content-Encoding" => "deflate",
|
78
|
-
"Vary" => "Accept-Encoding",
|
79
|
-
"Content-Type" => "text/plain"
|
80
|
-
})
|
81
|
-
buf = ''
|
82
|
-
response[2].each { |part| buf << part }
|
83
|
-
inflate(buf).should.equal("Hello world!")
|
84
|
-
end
|
85
|
-
|
86
|
-
should "be able to gzip bodies that respond to each" do
|
87
|
-
body = Object.new
|
88
|
-
class << body; def each; yield("foo"); yield("bar"); end; end
|
89
|
-
|
90
|
-
response = build_response(200, body, "gzip")
|
91
|
-
|
92
|
-
response[0].should.equal(200)
|
93
|
-
response[1].should.equal({
|
94
|
-
"Content-Encoding" => "gzip",
|
95
|
-
"Vary" => "Accept-Encoding",
|
96
|
-
"Content-Type" => "text/plain"
|
97
|
-
})
|
98
|
-
|
99
|
-
buf = ''
|
100
|
-
response[2].each { |part| buf << part }
|
101
|
-
io = StringIO.new(buf)
|
102
|
-
gz = Zlib::GzipReader.new(io)
|
103
|
-
gz.read.should.equal("foobar")
|
104
|
-
gz.close
|
105
|
-
end
|
106
|
-
|
107
|
-
should "flush gzipped chunks to the client as they become ready" do
|
108
|
-
body = Object.new
|
109
|
-
class << body; def each; yield("foo"); yield("bar"); end; end
|
110
|
-
|
111
|
-
response = build_response(200, body, "gzip")
|
112
|
-
|
113
|
-
response[0].should.equal(200)
|
114
|
-
response[1].should.equal({
|
115
|
-
"Content-Encoding" => "gzip",
|
116
|
-
"Vary" => "Accept-Encoding",
|
117
|
-
"Content-Type" => "text/plain"
|
118
|
-
})
|
119
|
-
buf = []
|
120
|
-
inflater = Zlib::Inflate.new(Zlib::MAX_WBITS + 32)
|
121
|
-
response[2].each { |part| buf << inflater.inflate(part) }
|
122
|
-
buf << inflater.finish
|
123
|
-
buf.delete_if { |part| part.empty? }
|
124
|
-
buf.join.should.equal("foobar")
|
125
|
-
end
|
126
|
-
|
127
|
-
should "be able to fallback to no deflation" do
|
128
|
-
response = build_response(200, "Hello world!", "superzip")
|
129
|
-
|
130
|
-
response[0].should.equal(200)
|
131
|
-
response[1].should.equal({ "Vary" => "Accept-Encoding", "Content-Type" => "text/plain" })
|
132
|
-
Enumerator.new(response[2]).to_a.should.equal(["Hello world!"])
|
133
|
-
end
|
134
|
-
|
135
|
-
should "be able to skip when there is no response entity body" do
|
136
|
-
response = build_response(304, [], "gzip")
|
137
|
-
|
138
|
-
response[0].should.equal(304)
|
139
|
-
response[1].should.equal({})
|
140
|
-
Enumerator.new(response[2]).to_a.should.equal([])
|
141
|
-
end
|
142
|
-
|
143
|
-
should "handle the lack of an acceptable encoding" do
|
144
|
-
response1 = build_response(200, "Hello world!", "identity;q=0", "PATH_INFO" => "/")
|
145
|
-
response1[0].should.equal(406)
|
146
|
-
response1[1].should.equal({"Content-Type" => "text/plain", "Content-Length" => "71"})
|
147
|
-
Enumerator.new(response1[2]).to_a.should.equal(["An acceptable encoding for the requested resource / could not be found."])
|
148
|
-
|
149
|
-
response2 = build_response(200, "Hello world!", "identity;q=0", "SCRIPT_NAME" => "/foo", "PATH_INFO" => "/bar")
|
150
|
-
response2[0].should.equal(406)
|
151
|
-
response2[1].should.equal({"Content-Type" => "text/plain", "Content-Length" => "78"})
|
152
|
-
Enumerator.new(response2[2]).to_a.should.equal(["An acceptable encoding for the requested resource /foo/bar could not be found."])
|
153
|
-
end
|
154
|
-
|
155
|
-
should "handle gzip response with Last-Modified header" do
|
156
|
-
last_modified = Time.now.httpdate
|
157
|
-
|
158
|
-
app = lambda { |env| [200, { "Content-Type" => "text/plain", "Last-Modified" => last_modified }, ["Hello World!"]] }
|
159
|
-
request = Rack::MockRequest.env_for("", "HTTP_ACCEPT_ENCODING" => "gzip")
|
160
|
-
response = deflater(app).call(request)
|
161
|
-
|
162
|
-
response[0].should.equal(200)
|
163
|
-
response[1].should.equal({
|
164
|
-
"Content-Encoding" => "gzip",
|
165
|
-
"Vary" => "Accept-Encoding",
|
166
|
-
"Last-Modified" => last_modified,
|
167
|
-
"Content-Type" => "text/plain"
|
168
|
-
})
|
169
|
-
|
170
|
-
buf = ''
|
171
|
-
response[2].each { |part| buf << part }
|
172
|
-
io = StringIO.new(buf)
|
173
|
-
gz = Zlib::GzipReader.new(io)
|
174
|
-
gz.read.should.equal("Hello World!")
|
175
|
-
gz.close
|
176
|
-
end
|
177
|
-
|
178
|
-
should "do nothing when no-transform Cache-Control directive present" do
|
179
|
-
app = lambda { |env| [200, {'Content-Type' => 'text/plain', 'Cache-Control' => 'no-transform'}, ['Hello World!']] }
|
180
|
-
request = Rack::MockRequest.env_for("", "HTTP_ACCEPT_ENCODING" => "gzip")
|
181
|
-
response = deflater(app).call(request)
|
182
|
-
|
183
|
-
response[0].should.equal(200)
|
184
|
-
response[1].should.not.include "Content-Encoding"
|
185
|
-
Enumerator.new(response[2]).to_a.join.should.equal("Hello World!")
|
186
|
-
end
|
187
|
-
end
|
data/test/spec_directory.rb
DELETED
@@ -1,88 +0,0 @@
|
|
1
|
-
require 'rack/directory'
|
2
|
-
require 'rack/lint'
|
3
|
-
require 'rack/mock'
|
4
|
-
|
5
|
-
describe Rack::Directory do
|
6
|
-
DOCROOT = File.expand_path(File.dirname(__FILE__)) unless defined? DOCROOT
|
7
|
-
FILE_CATCH = proc{|env| [200, {'Content-Type'=>'text/plain', "Content-Length" => "7"}, ['passed!']] }
|
8
|
-
app = Rack::Lint.new(Rack::Directory.new(DOCROOT, FILE_CATCH))
|
9
|
-
|
10
|
-
should "serve directory indices" do
|
11
|
-
res = Rack::MockRequest.new(Rack::Lint.new(app)).
|
12
|
-
get("/cgi/")
|
13
|
-
|
14
|
-
res.should.be.ok
|
15
|
-
res.should =~ /<html><head>/
|
16
|
-
end
|
17
|
-
|
18
|
-
should "pass to app if file found" do
|
19
|
-
res = Rack::MockRequest.new(Rack::Lint.new(app)).
|
20
|
-
get("/cgi/test")
|
21
|
-
|
22
|
-
res.should.be.ok
|
23
|
-
res.should =~ /passed!/
|
24
|
-
end
|
25
|
-
|
26
|
-
should "serve uri with URL encoded filenames" do
|
27
|
-
res = Rack::MockRequest.new(Rack::Lint.new(app)).
|
28
|
-
get("/%63%67%69/") # "/cgi/test"
|
29
|
-
|
30
|
-
res.should.be.ok
|
31
|
-
res.should =~ /<html><head>/
|
32
|
-
|
33
|
-
res = Rack::MockRequest.new(Rack::Lint.new(app)).
|
34
|
-
get("/cgi/%74%65%73%74") # "/cgi/test"
|
35
|
-
|
36
|
-
res.should.be.ok
|
37
|
-
res.should =~ /passed!/
|
38
|
-
end
|
39
|
-
|
40
|
-
should "not allow directory traversal" do
|
41
|
-
res = Rack::MockRequest.new(Rack::Lint.new(app)).
|
42
|
-
get("/cgi/../test")
|
43
|
-
|
44
|
-
res.should.be.forbidden
|
45
|
-
|
46
|
-
res = Rack::MockRequest.new(Rack::Lint.new(app)).
|
47
|
-
get("/cgi/%2E%2E/test")
|
48
|
-
|
49
|
-
res.should.be.forbidden
|
50
|
-
end
|
51
|
-
|
52
|
-
should "404 if it can't find the file" do
|
53
|
-
res = Rack::MockRequest.new(Rack::Lint.new(app)).
|
54
|
-
get("/cgi/blubb")
|
55
|
-
|
56
|
-
res.should.be.not_found
|
57
|
-
end
|
58
|
-
|
59
|
-
should "uri escape path parts" do # #265, properly escape file names
|
60
|
-
mr = Rack::MockRequest.new(Rack::Lint.new(app))
|
61
|
-
|
62
|
-
res = mr.get("/cgi/test%2bdirectory")
|
63
|
-
|
64
|
-
res.should.be.ok
|
65
|
-
res.body.should =~ %r[/cgi/test%2Bdirectory/test%2Bfile]
|
66
|
-
|
67
|
-
res = mr.get("/cgi/test%2bdirectory/test%2bfile")
|
68
|
-
res.should.be.ok
|
69
|
-
end
|
70
|
-
|
71
|
-
should "correctly escape script name" do
|
72
|
-
app2 = Rack::Builder.new do
|
73
|
-
map '/script-path' do
|
74
|
-
run app
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
mr = Rack::MockRequest.new(Rack::Lint.new(app2))
|
79
|
-
|
80
|
-
res = mr.get("/script-path/cgi/test%2bdirectory")
|
81
|
-
|
82
|
-
res.should.be.ok
|
83
|
-
res.body.should =~ %r[/script-path/cgi/test%2Bdirectory/test%2Bfile]
|
84
|
-
|
85
|
-
res = mr.get("/script-path/cgi/test%2bdirectory/test%2bfile")
|
86
|
-
res.should.be.ok
|
87
|
-
end
|
88
|
-
end
|
data/test/spec_etag.rb
DELETED
@@ -1,98 +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 "\"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 "\"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
|
-
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,1]
|
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
|