rack 2.0.4 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of rack might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/{HISTORY.md → CHANGELOG.md} +220 -155
- data/{COPYING → MIT-LICENSE} +4 -2
- data/README.rdoc +77 -119
- data/Rakefile +25 -18
- data/SPEC +3 -4
- data/bin/rackup +1 -0
- data/example/lobster.ru +2 -0
- data/example/protectedlobster.rb +3 -1
- data/example/protectedlobster.ru +2 -0
- data/lib/rack.rb +63 -60
- data/lib/rack/auth/abstract/handler.rb +3 -1
- data/lib/rack/auth/abstract/request.rb +2 -0
- data/lib/rack/auth/basic.rb +4 -1
- data/lib/rack/auth/digest/md5.rb +9 -7
- data/lib/rack/auth/digest/nonce.rb +6 -3
- data/lib/rack/auth/digest/params.rb +4 -2
- data/lib/rack/auth/digest/request.rb +2 -0
- data/lib/rack/body_proxy.rb +3 -6
- data/lib/rack/builder.rb +38 -15
- data/lib/rack/cascade.rb +6 -5
- data/lib/rack/chunked.rb +29 -6
- data/lib/rack/common_logger.rb +9 -8
- data/lib/rack/conditional_get.rb +3 -1
- data/lib/rack/config.rb +2 -0
- data/lib/rack/content_length.rb +3 -1
- data/lib/rack/content_type.rb +3 -1
- data/lib/rack/core_ext/regexp.rb +14 -0
- data/lib/rack/deflater.rb +28 -17
- data/lib/rack/directory.rb +17 -14
- data/lib/rack/etag.rb +3 -1
- data/lib/rack/events.rb +5 -3
- data/lib/rack/file.rb +5 -173
- data/lib/rack/files.rb +178 -0
- data/lib/rack/handler.rb +7 -2
- data/lib/rack/handler/cgi.rb +3 -1
- data/lib/rack/handler/fastcgi.rb +4 -2
- data/lib/rack/handler/lsws.rb +3 -1
- data/lib/rack/handler/scgi.rb +9 -6
- data/lib/rack/handler/thin.rb +3 -1
- data/lib/rack/handler/webrick.rb +4 -2
- data/lib/rack/head.rb +2 -0
- data/lib/rack/lint.rb +14 -11
- data/lib/rack/lobster.rb +7 -5
- data/lib/rack/lock.rb +2 -0
- data/lib/rack/logger.rb +2 -0
- data/lib/rack/media_type.rb +10 -5
- data/lib/rack/method_override.rb +9 -3
- data/lib/rack/mime.rb +9 -1
- data/lib/rack/mock.rb +74 -15
- data/lib/rack/multipart.rb +5 -3
- data/lib/rack/multipart/generator.rb +6 -7
- data/lib/rack/multipart/parser.rb +54 -51
- data/lib/rack/multipart/uploaded_file.rb +2 -0
- data/lib/rack/null_logger.rb +2 -0
- data/lib/rack/query_parser.rb +51 -25
- data/lib/rack/recursive.rb +7 -5
- data/lib/rack/reloader.rb +10 -4
- data/lib/rack/request.rb +89 -23
- data/lib/rack/response.rb +71 -31
- data/lib/rack/rewindable_input.rb +4 -2
- data/lib/rack/runtime.rb +4 -2
- data/lib/rack/sendfile.rb +15 -8
- data/lib/rack/server.rb +88 -16
- data/lib/rack/session/abstract/id.rb +104 -21
- data/lib/rack/session/cookie.rb +21 -11
- data/lib/rack/session/memcache.rb +4 -87
- data/lib/rack/session/pool.rb +17 -8
- data/lib/rack/show_exceptions.rb +16 -10
- data/lib/rack/show_status.rb +4 -2
- data/lib/rack/static.rb +15 -10
- data/lib/rack/tempfile_reaper.rb +2 -0
- data/lib/rack/urlmap.rb +11 -2
- data/lib/rack/utils.rb +55 -70
- data/rack.gemspec +19 -9
- metadata +32 -173
- data/test/builder/an_underscore_app.rb +0 -5
- data/test/builder/anything.rb +0 -5
- data/test/builder/comment.ru +0 -4
- data/test/builder/end.ru +0 -5
- data/test/builder/line.ru +0 -1
- data/test/builder/options.ru +0 -2
- data/test/cgi/assets/folder/test.js +0 -1
- data/test/cgi/assets/fonts/font.eot +0 -1
- data/test/cgi/assets/images/image.png +0 -1
- data/test/cgi/assets/index.html +0 -1
- data/test/cgi/assets/javascripts/app.js +0 -1
- data/test/cgi/assets/stylesheets/app.css +0 -1
- data/test/cgi/lighttpd.conf +0 -26
- data/test/cgi/rackup_stub.rb +0 -6
- data/test/cgi/sample_rackup.ru +0 -5
- data/test/cgi/test +0 -9
- data/test/cgi/test+directory/test+file +0 -1
- data/test/cgi/test.fcgi +0 -9
- data/test/cgi/test.gz +0 -0
- data/test/cgi/test.ru +0 -5
- data/test/gemloader.rb +0 -10
- data/test/helper.rb +0 -34
- data/test/multipart/bad_robots +0 -259
- data/test/multipart/binary +0 -0
- data/test/multipart/content_type_and_no_filename +0 -6
- data/test/multipart/empty +0 -10
- data/test/multipart/fail_16384_nofile +0 -814
- data/test/multipart/file1.txt +0 -1
- data/test/multipart/filename_and_modification_param +0 -7
- data/test/multipart/filename_and_no_name +0 -6
- data/test/multipart/filename_with_encoded_words +0 -7
- data/test/multipart/filename_with_escaped_quotes +0 -6
- data/test/multipart/filename_with_escaped_quotes_and_modification_param +0 -7
- data/test/multipart/filename_with_null_byte +0 -7
- data/test/multipart/filename_with_percent_escaped_quotes +0 -6
- data/test/multipart/filename_with_single_quote +0 -7
- data/test/multipart/filename_with_unescaped_percentages +0 -6
- data/test/multipart/filename_with_unescaped_percentages2 +0 -6
- data/test/multipart/filename_with_unescaped_percentages3 +0 -6
- data/test/multipart/filename_with_unescaped_quotes +0 -6
- data/test/multipart/ie +0 -6
- data/test/multipart/invalid_character +0 -6
- data/test/multipart/mixed_files +0 -21
- data/test/multipart/nested +0 -10
- data/test/multipart/none +0 -9
- data/test/multipart/quoted +0 -15
- data/test/multipart/rack-logo.png +0 -0
- data/test/multipart/semicolon +0 -6
- data/test/multipart/text +0 -15
- data/test/multipart/three_files_three_fields +0 -31
- data/test/multipart/unity3d_wwwform +0 -11
- data/test/multipart/webkit +0 -32
- data/test/rackup/config.ru +0 -31
- data/test/registering_handler/rack/handler/registering_myself.rb +0 -8
- data/test/spec_auth_basic.rb +0 -89
- data/test/spec_auth_digest.rb +0 -260
- data/test/spec_body_proxy.rb +0 -85
- data/test/spec_builder.rb +0 -233
- data/test/spec_cascade.rb +0 -63
- data/test/spec_cgi.rb +0 -84
- data/test/spec_chunked.rb +0 -103
- data/test/spec_common_logger.rb +0 -95
- data/test/spec_conditional_get.rb +0 -103
- data/test/spec_config.rb +0 -23
- data/test/spec_content_length.rb +0 -86
- data/test/spec_content_type.rb +0 -46
- data/test/spec_deflater.rb +0 -375
- data/test/spec_directory.rb +0 -148
- data/test/spec_etag.rb +0 -108
- data/test/spec_events.rb +0 -133
- data/test/spec_fastcgi.rb +0 -85
- data/test/spec_file.rb +0 -264
- data/test/spec_handler.rb +0 -57
- data/test/spec_head.rb +0 -46
- data/test/spec_lint.rb +0 -515
- data/test/spec_lobster.rb +0 -59
- data/test/spec_lock.rb +0 -204
- data/test/spec_logger.rb +0 -24
- data/test/spec_media_type.rb +0 -42
- data/test/spec_method_override.rb +0 -96
- data/test/spec_mime.rb +0 -51
- data/test/spec_mock.rb +0 -359
- data/test/spec_multipart.rb +0 -722
- data/test/spec_null_logger.rb +0 -21
- data/test/spec_recursive.rb +0 -75
- data/test/spec_request.rb +0 -1393
- data/test/spec_response.rb +0 -510
- data/test/spec_rewindable_input.rb +0 -128
- data/test/spec_runtime.rb +0 -50
- data/test/spec_sendfile.rb +0 -125
- data/test/spec_server.rb +0 -193
- data/test/spec_session_abstract_id.rb +0 -31
- data/test/spec_session_abstract_session_hash.rb +0 -45
- data/test/spec_session_cookie.rb +0 -442
- data/test/spec_session_memcache.rb +0 -320
- data/test/spec_session_pool.rb +0 -210
- data/test/spec_show_exceptions.rb +0 -80
- data/test/spec_show_status.rb +0 -104
- data/test/spec_static.rb +0 -184
- data/test/spec_tempfile_reaper.rb +0 -64
- data/test/spec_thin.rb +0 -96
- data/test/spec_urlmap.rb +0 -237
- data/test/spec_utils.rb +0 -742
- data/test/spec_version.rb +0 -11
- data/test/spec_webrick.rb +0 -206
- data/test/static/another/index.html +0 -1
- data/test/static/foo.html +0 -1
- data/test/static/index.html +0 -1
- data/test/testrequest.rb +0 -78
- data/test/unregistered_handler/rack/handler/unregistered.rb +0 -7
- data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +0 -7
data/test/spec_etag.rb
DELETED
@@ -1,108 +0,0 @@
|
|
1
|
-
require 'minitest/autorun'
|
2
|
-
require 'rack/etag'
|
3
|
-
require 'rack/lint'
|
4
|
-
require 'rack/mock'
|
5
|
-
require 'time'
|
6
|
-
|
7
|
-
describe Rack::ETag do
|
8
|
-
def etag(app, *args)
|
9
|
-
Rack::Lint.new Rack::ETag.new(app, *args)
|
10
|
-
end
|
11
|
-
|
12
|
-
def request
|
13
|
-
Rack::MockRequest.env_for
|
14
|
-
end
|
15
|
-
|
16
|
-
def sendfile_body
|
17
|
-
res = ['Hello World']
|
18
|
-
def res.to_path ; "/tmp/hello.txt" ; end
|
19
|
-
res
|
20
|
-
end
|
21
|
-
|
22
|
-
it "set ETag if none is set if status is 200" do
|
23
|
-
app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, ["Hello, World!"]] }
|
24
|
-
response = etag(app).call(request)
|
25
|
-
response[1]['ETag'].must_equal "W/\"dffd6021bb2bd5b0af676290809ec3a5\""
|
26
|
-
end
|
27
|
-
|
28
|
-
it "set ETag if none is set if status is 201" do
|
29
|
-
app = lambda { |env| [201, {'Content-Type' => 'text/plain'}, ["Hello, World!"]] }
|
30
|
-
response = etag(app).call(request)
|
31
|
-
response[1]['ETag'].must_equal "W/\"dffd6021bb2bd5b0af676290809ec3a5\""
|
32
|
-
end
|
33
|
-
|
34
|
-
it "set Cache-Control to 'max-age=0, private, must-revalidate' (default) if none is set" do
|
35
|
-
app = lambda { |env| [201, {'Content-Type' => 'text/plain'}, ["Hello, World!"]] }
|
36
|
-
response = etag(app).call(request)
|
37
|
-
response[1]['Cache-Control'].must_equal 'max-age=0, private, must-revalidate'
|
38
|
-
end
|
39
|
-
|
40
|
-
it "set Cache-Control to chosen one if none is set" do
|
41
|
-
app = lambda { |env| [201, {'Content-Type' => 'text/plain'}, ["Hello, World!"]] }
|
42
|
-
response = etag(app, nil, 'public').call(request)
|
43
|
-
response[1]['Cache-Control'].must_equal 'public'
|
44
|
-
end
|
45
|
-
|
46
|
-
it "set a given Cache-Control even if digest could not be calculated" do
|
47
|
-
app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, []] }
|
48
|
-
response = etag(app, 'no-cache').call(request)
|
49
|
-
response[1]['Cache-Control'].must_equal 'no-cache'
|
50
|
-
end
|
51
|
-
|
52
|
-
it "not set Cache-Control if it is already set" do
|
53
|
-
app = lambda { |env| [201, {'Content-Type' => 'text/plain', 'Cache-Control' => 'public'}, ["Hello, World!"]] }
|
54
|
-
response = etag(app).call(request)
|
55
|
-
response[1]['Cache-Control'].must_equal 'public'
|
56
|
-
end
|
57
|
-
|
58
|
-
it "not set Cache-Control if directive isn't present" do
|
59
|
-
app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, ["Hello, World!"]] }
|
60
|
-
response = etag(app, nil, nil).call(request)
|
61
|
-
response[1]['Cache-Control'].must_be_nil
|
62
|
-
end
|
63
|
-
|
64
|
-
it "not change ETag if it is already set" do
|
65
|
-
app = lambda { |env| [200, {'Content-Type' => 'text/plain', 'ETag' => '"abc"'}, ["Hello, World!"]] }
|
66
|
-
response = etag(app).call(request)
|
67
|
-
response[1]['ETag'].must_equal "\"abc\""
|
68
|
-
end
|
69
|
-
|
70
|
-
it "not set ETag if body is empty" do
|
71
|
-
app = lambda { |env| [200, {'Content-Type' => 'text/plain', 'Last-Modified' => Time.now.httpdate}, []] }
|
72
|
-
response = etag(app).call(request)
|
73
|
-
response[1]['ETag'].must_be_nil
|
74
|
-
end
|
75
|
-
|
76
|
-
it "not set ETag if Last-Modified is set" do
|
77
|
-
app = lambda { |env| [200, {'Content-Type' => 'text/plain', 'Last-Modified' => Time.now.httpdate}, ["Hello, World!"]] }
|
78
|
-
response = etag(app).call(request)
|
79
|
-
response[1]['ETag'].must_be_nil
|
80
|
-
end
|
81
|
-
|
82
|
-
it "not set ETag if a sendfile_body is given" do
|
83
|
-
app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, sendfile_body] }
|
84
|
-
response = etag(app).call(request)
|
85
|
-
response[1]['ETag'].must_be_nil
|
86
|
-
end
|
87
|
-
|
88
|
-
it "not set ETag if a status is not 200 or 201" do
|
89
|
-
app = lambda { |env| [401, {'Content-Type' => 'text/plain'}, ['Access denied.']] }
|
90
|
-
response = etag(app).call(request)
|
91
|
-
response[1]['ETag'].must_be_nil
|
92
|
-
end
|
93
|
-
|
94
|
-
it "not set ETag if no-cache is given" do
|
95
|
-
app = lambda { |env| [200, {'Content-Type' => 'text/plain', 'Cache-Control' => 'no-cache, must-revalidate'}, ['Hello, World!']] }
|
96
|
-
response = etag(app).call(request)
|
97
|
-
response[1]['ETag'].must_be_nil
|
98
|
-
end
|
99
|
-
|
100
|
-
it "close the original body" do
|
101
|
-
body = StringIO.new
|
102
|
-
app = lambda { |env| [200, {}, body] }
|
103
|
-
response = etag(app).call(request)
|
104
|
-
body.wont_be :closed?
|
105
|
-
response[2].close
|
106
|
-
body.must_be :closed?
|
107
|
-
end
|
108
|
-
end
|
data/test/spec_events.rb
DELETED
@@ -1,133 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
require 'rack/events'
|
3
|
-
|
4
|
-
module Rack
|
5
|
-
class TestEvents < Rack::TestCase
|
6
|
-
class EventMiddleware
|
7
|
-
attr_reader :events
|
8
|
-
|
9
|
-
def initialize events
|
10
|
-
@events = events
|
11
|
-
end
|
12
|
-
|
13
|
-
def on_start req, res
|
14
|
-
events << [self, __method__]
|
15
|
-
end
|
16
|
-
|
17
|
-
def on_commit req, res
|
18
|
-
events << [self, __method__]
|
19
|
-
end
|
20
|
-
|
21
|
-
def on_send req, res
|
22
|
-
events << [self, __method__]
|
23
|
-
end
|
24
|
-
|
25
|
-
def on_finish req, res
|
26
|
-
events << [self, __method__]
|
27
|
-
end
|
28
|
-
|
29
|
-
def on_error req, res, e
|
30
|
-
events << [self, __method__]
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
def test_events_fire
|
35
|
-
events = []
|
36
|
-
ret = [200, {}, []]
|
37
|
-
app = lambda { |env| events << [app, :call]; ret }
|
38
|
-
se = EventMiddleware.new events
|
39
|
-
e = Events.new app, [se]
|
40
|
-
triple = e.call({})
|
41
|
-
response_body = []
|
42
|
-
triple[2].each { |x| response_body << x }
|
43
|
-
triple[2].close
|
44
|
-
triple[2] = response_body
|
45
|
-
assert_equal ret, triple
|
46
|
-
assert_equal [[se, :on_start],
|
47
|
-
[app, :call],
|
48
|
-
[se, :on_commit],
|
49
|
-
[se, :on_send],
|
50
|
-
[se, :on_finish],
|
51
|
-
], events
|
52
|
-
end
|
53
|
-
|
54
|
-
def test_send_and_finish_are_not_run_until_body_is_sent
|
55
|
-
events = []
|
56
|
-
ret = [200, {}, []]
|
57
|
-
app = lambda { |env| events << [app, :call]; ret }
|
58
|
-
se = EventMiddleware.new events
|
59
|
-
e = Events.new app, [se]
|
60
|
-
triple = e.call({})
|
61
|
-
assert_equal [[se, :on_start],
|
62
|
-
[app, :call],
|
63
|
-
[se, :on_commit],
|
64
|
-
], events
|
65
|
-
end
|
66
|
-
|
67
|
-
def test_send_is_called_on_each
|
68
|
-
events = []
|
69
|
-
ret = [200, {}, []]
|
70
|
-
app = lambda { |env| events << [app, :call]; ret }
|
71
|
-
se = EventMiddleware.new events
|
72
|
-
e = Events.new app, [se]
|
73
|
-
triple = e.call({})
|
74
|
-
triple[2].each { |x| }
|
75
|
-
assert_equal [[se, :on_start],
|
76
|
-
[app, :call],
|
77
|
-
[se, :on_commit],
|
78
|
-
[se, :on_send],
|
79
|
-
], events
|
80
|
-
end
|
81
|
-
|
82
|
-
def test_finish_is_called_on_close
|
83
|
-
events = []
|
84
|
-
ret = [200, {}, []]
|
85
|
-
app = lambda { |env| events << [app, :call]; ret }
|
86
|
-
se = EventMiddleware.new events
|
87
|
-
e = Events.new app, [se]
|
88
|
-
triple = e.call({})
|
89
|
-
triple[2].each { |x| }
|
90
|
-
triple[2].close
|
91
|
-
assert_equal [[se, :on_start],
|
92
|
-
[app, :call],
|
93
|
-
[se, :on_commit],
|
94
|
-
[se, :on_send],
|
95
|
-
[se, :on_finish],
|
96
|
-
], events
|
97
|
-
end
|
98
|
-
|
99
|
-
def test_finish_is_called_in_reverse_order
|
100
|
-
events = []
|
101
|
-
ret = [200, {}, []]
|
102
|
-
app = lambda { |env| events << [app, :call]; ret }
|
103
|
-
se1 = EventMiddleware.new events
|
104
|
-
se2 = EventMiddleware.new events
|
105
|
-
se3 = EventMiddleware.new events
|
106
|
-
|
107
|
-
e = Events.new app, [se1, se2, se3]
|
108
|
-
triple = e.call({})
|
109
|
-
triple[2].each { |x| }
|
110
|
-
triple[2].close
|
111
|
-
|
112
|
-
groups = events.group_by { |x| x.last }
|
113
|
-
assert_equal groups[:on_start].map(&:first), groups[:on_finish].map(&:first).reverse
|
114
|
-
assert_equal groups[:on_commit].map(&:first), groups[:on_finish].map(&:first)
|
115
|
-
assert_equal groups[:on_send].map(&:first), groups[:on_finish].map(&:first)
|
116
|
-
end
|
117
|
-
|
118
|
-
def test_finish_is_called_if_there_is_an_exception
|
119
|
-
events = []
|
120
|
-
ret = [200, {}, []]
|
121
|
-
app = lambda { |env| raise }
|
122
|
-
se = EventMiddleware.new events
|
123
|
-
e = Events.new app, [se]
|
124
|
-
assert_raises(RuntimeError) do
|
125
|
-
e.call({})
|
126
|
-
end
|
127
|
-
assert_equal [[se, :on_start],
|
128
|
-
[se, :on_error],
|
129
|
-
[se, :on_finish],
|
130
|
-
], events
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
data/test/spec_fastcgi.rb
DELETED
@@ -1,85 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
if defined? LIGHTTPD_PID
|
4
|
-
|
5
|
-
require File.expand_path('../testrequest', __FILE__)
|
6
|
-
require 'rack/handler/fastcgi'
|
7
|
-
|
8
|
-
describe Rack::Handler::FastCGI do
|
9
|
-
include TestRequest::Helpers
|
10
|
-
|
11
|
-
before do
|
12
|
-
@host = '127.0.0.1'
|
13
|
-
@port = 9203
|
14
|
-
end
|
15
|
-
|
16
|
-
it "respond" do
|
17
|
-
sleep 1
|
18
|
-
GET("/test")
|
19
|
-
response.wont_be :nil?
|
20
|
-
end
|
21
|
-
|
22
|
-
it "respond via rackup server" do
|
23
|
-
GET("/sample_rackup.ru")
|
24
|
-
status.must_equal 200
|
25
|
-
end
|
26
|
-
|
27
|
-
it "be a lighttpd" do
|
28
|
-
GET("/test.fcgi")
|
29
|
-
status.must_equal 200
|
30
|
-
response["SERVER_SOFTWARE"].must_match(/lighttpd/)
|
31
|
-
response["HTTP_VERSION"].must_equal "HTTP/1.1"
|
32
|
-
response["SERVER_PROTOCOL"].must_equal "HTTP/1.1"
|
33
|
-
response["SERVER_PORT"].must_equal @port.to_s
|
34
|
-
response["SERVER_NAME"].must_equal @host
|
35
|
-
end
|
36
|
-
|
37
|
-
it "have rack headers" do
|
38
|
-
GET("/test.fcgi")
|
39
|
-
response["rack.version"].must_equal [1,3]
|
40
|
-
assert_equal false, response["rack.multithread"]
|
41
|
-
assert_equal true, response["rack.multiprocess"]
|
42
|
-
assert_equal false, response["rack.run_once"]
|
43
|
-
end
|
44
|
-
|
45
|
-
it "have CGI headers on GET" do
|
46
|
-
GET("/test.fcgi")
|
47
|
-
response["REQUEST_METHOD"].must_equal "GET"
|
48
|
-
response["SCRIPT_NAME"].must_equal "/test.fcgi"
|
49
|
-
response["REQUEST_PATH"].must_equal "/"
|
50
|
-
response["PATH_INFO"].must_equal ""
|
51
|
-
response["QUERY_STRING"].must_equal ""
|
52
|
-
response["test.postdata"].must_equal ""
|
53
|
-
|
54
|
-
GET("/test.fcgi/foo?quux=1")
|
55
|
-
response["REQUEST_METHOD"].must_equal "GET"
|
56
|
-
response["SCRIPT_NAME"].must_equal "/test.fcgi"
|
57
|
-
response["REQUEST_PATH"].must_equal "/"
|
58
|
-
response["PATH_INFO"].must_equal "/foo"
|
59
|
-
response["QUERY_STRING"].must_equal "quux=1"
|
60
|
-
end
|
61
|
-
|
62
|
-
it "have CGI headers on POST" do
|
63
|
-
POST("/test.fcgi", {"rack-form-data" => "23"}, {'X-test-header' => '42'})
|
64
|
-
status.must_equal 200
|
65
|
-
response["REQUEST_METHOD"].must_equal "POST"
|
66
|
-
response["SCRIPT_NAME"].must_equal "/test.fcgi"
|
67
|
-
response["REQUEST_PATH"].must_equal "/"
|
68
|
-
response["QUERY_STRING"].must_equal ""
|
69
|
-
response["HTTP_X_TEST_HEADER"].must_equal "42"
|
70
|
-
response["test.postdata"].must_equal "rack-form-data=23"
|
71
|
-
end
|
72
|
-
|
73
|
-
it "support HTTP auth" do
|
74
|
-
GET("/test.fcgi", {:user => "ruth", :passwd => "secret"})
|
75
|
-
response["HTTP_AUTHORIZATION"].must_equal "Basic cnV0aDpzZWNyZXQ="
|
76
|
-
end
|
77
|
-
|
78
|
-
it "set status" do
|
79
|
-
GET("/test.fcgi?secret")
|
80
|
-
status.must_equal 403
|
81
|
-
response["rack.url_scheme"].must_equal "http"
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
end # if defined? LIGHTTPD_PID
|
data/test/spec_file.rb
DELETED
@@ -1,264 +0,0 @@
|
|
1
|
-
require 'minitest/autorun'
|
2
|
-
require 'rack/file'
|
3
|
-
require 'rack/lint'
|
4
|
-
require 'rack/mock'
|
5
|
-
|
6
|
-
describe Rack::File do
|
7
|
-
DOCROOT = File.expand_path(File.dirname(__FILE__)) unless defined? DOCROOT
|
8
|
-
|
9
|
-
def file(*args)
|
10
|
-
Rack::Lint.new Rack::File.new(*args)
|
11
|
-
end
|
12
|
-
|
13
|
-
it 'serves files with + in the file name' do
|
14
|
-
Dir.mktmpdir do |dir|
|
15
|
-
File.write File.join(dir, "you+me.txt"), "hello world"
|
16
|
-
app = file(dir)
|
17
|
-
env = Rack::MockRequest.env_for("/you+me.txt")
|
18
|
-
status,_,body = app.call env
|
19
|
-
|
20
|
-
assert_equal 200, status
|
21
|
-
|
22
|
-
str = ''
|
23
|
-
body.each { |x| str << x }
|
24
|
-
assert_match "hello world", str
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
it "serve files" do
|
29
|
-
res = Rack::MockRequest.new(file(DOCROOT)).get("/cgi/test")
|
30
|
-
|
31
|
-
res.must_be :ok?
|
32
|
-
assert_match(res, /ruby/)
|
33
|
-
end
|
34
|
-
|
35
|
-
it "set Last-Modified header" do
|
36
|
-
res = Rack::MockRequest.new(file(DOCROOT)).get("/cgi/test")
|
37
|
-
|
38
|
-
path = File.join(DOCROOT, "/cgi/test")
|
39
|
-
|
40
|
-
res.must_be :ok?
|
41
|
-
res["Last-Modified"].must_equal File.mtime(path).httpdate
|
42
|
-
end
|
43
|
-
|
44
|
-
it "return 304 if file isn't modified since last serve" do
|
45
|
-
path = File.join(DOCROOT, "/cgi/test")
|
46
|
-
res = Rack::MockRequest.new(file(DOCROOT)).
|
47
|
-
get("/cgi/test", 'HTTP_IF_MODIFIED_SINCE' => File.mtime(path).httpdate)
|
48
|
-
|
49
|
-
res.status.must_equal 304
|
50
|
-
res.body.must_be :empty?
|
51
|
-
end
|
52
|
-
|
53
|
-
it "return the file if it's modified since last serve" do
|
54
|
-
path = File.join(DOCROOT, "/cgi/test")
|
55
|
-
res = Rack::MockRequest.new(file(DOCROOT)).
|
56
|
-
get("/cgi/test", 'HTTP_IF_MODIFIED_SINCE' => (File.mtime(path) - 100).httpdate)
|
57
|
-
|
58
|
-
res.must_be :ok?
|
59
|
-
end
|
60
|
-
|
61
|
-
it "serve files with URL encoded filenames" do
|
62
|
-
res = Rack::MockRequest.new(file(DOCROOT)).get("/cgi/%74%65%73%74") # "/cgi/test"
|
63
|
-
|
64
|
-
res.must_be :ok?
|
65
|
-
# res.must_match(/ruby/) # nope
|
66
|
-
# (/ruby/).must_match res # This is wierd, but an oddity of minitest
|
67
|
-
# assert_match(/ruby/, res) # nope
|
68
|
-
assert_match(res, /ruby/)
|
69
|
-
end
|
70
|
-
|
71
|
-
it "serve uri with URL encoded null byte (%00) in filenames" do
|
72
|
-
res = Rack::MockRequest.new(file(DOCROOT)).get("/cgi/test%00")
|
73
|
-
res.must_be :bad_request?
|
74
|
-
end
|
75
|
-
|
76
|
-
it "allow safe directory traversal" do
|
77
|
-
req = Rack::MockRequest.new(file(DOCROOT))
|
78
|
-
|
79
|
-
res = req.get('/cgi/../cgi/test')
|
80
|
-
res.must_be :successful?
|
81
|
-
|
82
|
-
res = req.get('.')
|
83
|
-
res.must_be :not_found?
|
84
|
-
|
85
|
-
res = req.get("test/..")
|
86
|
-
res.must_be :not_found?
|
87
|
-
end
|
88
|
-
|
89
|
-
it "not allow unsafe directory traversal" do
|
90
|
-
req = Rack::MockRequest.new(file(DOCROOT))
|
91
|
-
|
92
|
-
res = req.get("/../README.rdoc")
|
93
|
-
res.must_be :client_error?
|
94
|
-
|
95
|
-
res = req.get("../test/spec_file.rb")
|
96
|
-
res.must_be :client_error?
|
97
|
-
|
98
|
-
res = req.get("../README.rdoc")
|
99
|
-
res.must_be :client_error?
|
100
|
-
|
101
|
-
res.must_be :not_found?
|
102
|
-
end
|
103
|
-
|
104
|
-
it "allow files with .. in their name" do
|
105
|
-
req = Rack::MockRequest.new(file(DOCROOT))
|
106
|
-
res = req.get("/cgi/..test")
|
107
|
-
res.must_be :not_found?
|
108
|
-
|
109
|
-
res = req.get("/cgi/test..")
|
110
|
-
res.must_be :not_found?
|
111
|
-
|
112
|
-
res = req.get("/cgi../test..")
|
113
|
-
res.must_be :not_found?
|
114
|
-
end
|
115
|
-
|
116
|
-
it "not allow unsafe directory traversal with encoded periods" do
|
117
|
-
res = Rack::MockRequest.new(file(DOCROOT)).get("/%2E%2E/README")
|
118
|
-
|
119
|
-
res.must_be :client_error?
|
120
|
-
res.must_be :not_found?
|
121
|
-
end
|
122
|
-
|
123
|
-
it "allow safe directory traversal with encoded periods" do
|
124
|
-
res = Rack::MockRequest.new(file(DOCROOT)).get("/cgi/%2E%2E/cgi/test")
|
125
|
-
|
126
|
-
res.must_be :successful?
|
127
|
-
end
|
128
|
-
|
129
|
-
it "404 if it can't find the file" do
|
130
|
-
res = Rack::MockRequest.new(file(DOCROOT)).get("/cgi/blubb")
|
131
|
-
|
132
|
-
res.must_be :not_found?
|
133
|
-
end
|
134
|
-
|
135
|
-
it "detect SystemCallErrors" do
|
136
|
-
res = Rack::MockRequest.new(file(DOCROOT)).get("/cgi")
|
137
|
-
|
138
|
-
res.must_be :not_found?
|
139
|
-
end
|
140
|
-
|
141
|
-
it "return bodies that respond to #to_path" do
|
142
|
-
env = Rack::MockRequest.env_for("/cgi/test")
|
143
|
-
status, _, body = Rack::File.new(DOCROOT).call(env)
|
144
|
-
|
145
|
-
path = File.join(DOCROOT, "/cgi/test")
|
146
|
-
|
147
|
-
status.must_equal 200
|
148
|
-
body.must_respond_to :to_path
|
149
|
-
body.to_path.must_equal path
|
150
|
-
end
|
151
|
-
|
152
|
-
it "return correct byte range in body" do
|
153
|
-
env = Rack::MockRequest.env_for("/cgi/test")
|
154
|
-
env["HTTP_RANGE"] = "bytes=22-33"
|
155
|
-
res = Rack::MockResponse.new(*file(DOCROOT).call(env))
|
156
|
-
|
157
|
-
res.status.must_equal 206
|
158
|
-
res["Content-Length"].must_equal "12"
|
159
|
-
res["Content-Range"].must_equal "bytes 22-33/193"
|
160
|
-
res.body.must_equal "-*- ruby -*-"
|
161
|
-
end
|
162
|
-
|
163
|
-
it "return error for unsatisfiable byte range" do
|
164
|
-
env = Rack::MockRequest.env_for("/cgi/test")
|
165
|
-
env["HTTP_RANGE"] = "bytes=1234-5678"
|
166
|
-
res = Rack::MockResponse.new(*file(DOCROOT).call(env))
|
167
|
-
|
168
|
-
res.status.must_equal 416
|
169
|
-
res["Content-Range"].must_equal "bytes */193"
|
170
|
-
end
|
171
|
-
|
172
|
-
it "support custom http headers" do
|
173
|
-
env = Rack::MockRequest.env_for("/cgi/test")
|
174
|
-
status, heads, _ = file(DOCROOT, 'Cache-Control' => 'public, max-age=38',
|
175
|
-
'Access-Control-Allow-Origin' => '*').call(env)
|
176
|
-
|
177
|
-
status.must_equal 200
|
178
|
-
heads['Cache-Control'].must_equal 'public, max-age=38'
|
179
|
-
heads['Access-Control-Allow-Origin'].must_equal '*'
|
180
|
-
end
|
181
|
-
|
182
|
-
it "support not add custom http headers if none are supplied" do
|
183
|
-
env = Rack::MockRequest.env_for("/cgi/test")
|
184
|
-
status, heads, _ = file(DOCROOT).call(env)
|
185
|
-
|
186
|
-
status.must_equal 200
|
187
|
-
heads['Cache-Control'].must_be_nil
|
188
|
-
heads['Access-Control-Allow-Origin'].must_be_nil
|
189
|
-
end
|
190
|
-
|
191
|
-
it "only support GET, HEAD, and OPTIONS requests" do
|
192
|
-
req = Rack::MockRequest.new(file(DOCROOT))
|
193
|
-
|
194
|
-
forbidden = %w[post put patch delete]
|
195
|
-
forbidden.each do |method|
|
196
|
-
res = req.send(method, "/cgi/test")
|
197
|
-
res.must_be :client_error?
|
198
|
-
res.must_be :method_not_allowed?
|
199
|
-
res.headers['Allow'].split(/, */).sort.must_equal %w(GET HEAD OPTIONS)
|
200
|
-
end
|
201
|
-
|
202
|
-
allowed = %w[get head options]
|
203
|
-
allowed.each do |method|
|
204
|
-
res = req.send(method, "/cgi/test")
|
205
|
-
res.must_be :successful?
|
206
|
-
end
|
207
|
-
end
|
208
|
-
|
209
|
-
it "set Allow correctly for OPTIONS requests" do
|
210
|
-
req = Rack::MockRequest.new(file(DOCROOT))
|
211
|
-
res = req.options('/cgi/test')
|
212
|
-
res.must_be :successful?
|
213
|
-
res.headers['Allow'].wont_equal nil
|
214
|
-
res.headers['Allow'].split(/, */).sort.must_equal %w(GET HEAD OPTIONS)
|
215
|
-
end
|
216
|
-
|
217
|
-
it "set Content-Length correctly for HEAD requests" do
|
218
|
-
req = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT)))
|
219
|
-
res = req.head "/cgi/test"
|
220
|
-
res.must_be :successful?
|
221
|
-
res['Content-Length'].must_equal "193"
|
222
|
-
end
|
223
|
-
|
224
|
-
it "default to a mime type of text/plain" do
|
225
|
-
req = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT)))
|
226
|
-
res = req.get "/cgi/test"
|
227
|
-
res.must_be :successful?
|
228
|
-
res['Content-Type'].must_equal "text/plain"
|
229
|
-
end
|
230
|
-
|
231
|
-
it "allow the default mime type to be set" do
|
232
|
-
req = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT, nil, 'application/octet-stream')))
|
233
|
-
res = req.get "/cgi/test"
|
234
|
-
res.must_be :successful?
|
235
|
-
res['Content-Type'].must_equal "application/octet-stream"
|
236
|
-
end
|
237
|
-
|
238
|
-
it "not set Content-Type if the mime type is not set" do
|
239
|
-
req = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT, nil, nil)))
|
240
|
-
res = req.get "/cgi/test"
|
241
|
-
res.must_be :successful?
|
242
|
-
res['Content-Type'].must_be_nil
|
243
|
-
end
|
244
|
-
|
245
|
-
it "return error when file not found for head request" do
|
246
|
-
res = Rack::MockRequest.new(file(DOCROOT)).head("/cgi/missing")
|
247
|
-
res.must_be :not_found?
|
248
|
-
res.body.must_be :empty?
|
249
|
-
end
|
250
|
-
|
251
|
-
class MyFile < Rack::File
|
252
|
-
def response_body
|
253
|
-
"hello world"
|
254
|
-
end
|
255
|
-
end
|
256
|
-
|
257
|
-
it "behaves gracefully if response_body is present" do
|
258
|
-
file = Rack::Lint.new MyFile.new(DOCROOT)
|
259
|
-
res = Rack::MockRequest.new(file).get("/cgi/test")
|
260
|
-
|
261
|
-
res.must_be :ok?
|
262
|
-
end
|
263
|
-
|
264
|
-
end
|