rack 1.6.13 → 2.0.9
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of rack might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/COPYING +1 -1
- data/HISTORY.md +138 -8
- data/README.rdoc +18 -28
- data/Rakefile +6 -14
- data/SPEC +3 -3
- data/contrib/rack_logo.svg +164 -111
- data/example/protectedlobster.rb +1 -1
- data/example/protectedlobster.ru +1 -1
- data/lib/rack/auth/abstract/request.rb +5 -1
- data/lib/rack/auth/digest/params.rb +2 -3
- data/lib/rack/auth/digest/request.rb +1 -1
- data/lib/rack/body_proxy.rb +14 -9
- data/lib/rack/builder.rb +3 -3
- data/lib/rack/chunked.rb +5 -5
- data/lib/rack/{commonlogger.rb → common_logger.rb} +3 -3
- data/lib/rack/content_length.rb +2 -2
- data/lib/rack/deflater.rb +4 -39
- data/lib/rack/directory.rb +66 -54
- data/lib/rack/etag.rb +5 -4
- data/lib/rack/events.rb +154 -0
- data/lib/rack/file.rb +64 -40
- data/lib/rack/handler/cgi.rb +15 -16
- data/lib/rack/handler/fastcgi.rb +13 -14
- data/lib/rack/handler/lsws.rb +11 -11
- data/lib/rack/handler/scgi.rb +15 -15
- data/lib/rack/handler/thin.rb +3 -0
- data/lib/rack/handler/webrick.rb +24 -26
- data/lib/rack/handler.rb +3 -25
- data/lib/rack/head.rb +15 -17
- data/lib/rack/lint.rb +40 -40
- data/lib/rack/lobster.rb +1 -1
- data/lib/rack/lock.rb +15 -10
- data/lib/rack/logger.rb +2 -2
- data/lib/rack/media_type.rb +38 -0
- data/lib/rack/{methodoverride.rb → method_override.rb} +6 -6
- data/lib/rack/mime.rb +18 -5
- data/lib/rack/mock.rb +36 -54
- data/lib/rack/multipart/generator.rb +5 -5
- data/lib/rack/multipart/parser.rb +270 -157
- data/lib/rack/multipart/uploaded_file.rb +1 -2
- data/lib/rack/multipart.rb +35 -6
- data/lib/rack/{nulllogger.rb → null_logger.rb} +1 -1
- data/lib/rack/query_parser.rb +192 -0
- data/lib/rack/recursive.rb +8 -8
- data/lib/rack/request.rb +394 -305
- data/lib/rack/response.rb +130 -57
- data/lib/rack/rewindable_input.rb +1 -12
- data/lib/rack/runtime.rb +10 -18
- data/lib/rack/sendfile.rb +5 -7
- data/lib/rack/server.rb +30 -23
- data/lib/rack/session/abstract/id.rb +110 -75
- data/lib/rack/session/cookie.rb +24 -17
- data/lib/rack/session/memcache.rb +9 -9
- data/lib/rack/session/pool.rb +8 -8
- data/lib/rack/show_exceptions.rb +386 -0
- data/lib/rack/{showstatus.rb → show_status.rb} +3 -3
- data/lib/rack/static.rb +30 -5
- data/lib/rack/tempfile_reaper.rb +2 -2
- data/lib/rack/urlmap.rb +15 -14
- data/lib/rack/utils.rb +138 -211
- data/lib/rack.rb +70 -21
- data/rack.gemspec +10 -9
- data/test/builder/an_underscore_app.rb +5 -0
- data/test/builder/options.ru +1 -1
- data/test/cgi/test.fcgi +1 -0
- data/test/cgi/test.gz +0 -0
- data/test/helper.rb +34 -0
- data/test/multipart/filename_with_encoded_words +7 -0
- data/test/multipart/filename_with_single_quote +7 -0
- data/test/multipart/quoted +15 -0
- data/test/multipart/rack-logo.png +0 -0
- data/test/multipart/unity3d_wwwform +11 -0
- data/test/registering_handler/rack/handler/registering_myself.rb +1 -1
- data/test/spec_auth_basic.rb +27 -19
- data/test/spec_auth_digest.rb +47 -46
- data/test/spec_body_proxy.rb +27 -27
- data/test/spec_builder.rb +51 -41
- data/test/spec_cascade.rb +24 -22
- data/test/spec_cgi.rb +49 -67
- data/test/spec_chunked.rb +37 -35
- data/test/{spec_commonlogger.rb → spec_common_logger.rb} +23 -21
- data/test/{spec_conditionalget.rb → spec_conditional_get.rb} +29 -28
- data/test/spec_config.rb +3 -2
- data/test/spec_content_length.rb +18 -17
- data/test/spec_content_type.rb +13 -12
- data/test/spec_deflater.rb +85 -49
- data/test/spec_directory.rb +87 -27
- data/test/spec_etag.rb +32 -31
- data/test/spec_events.rb +133 -0
- data/test/spec_fastcgi.rb +50 -72
- data/test/spec_file.rb +120 -77
- data/test/spec_handler.rb +19 -34
- data/test/spec_head.rb +15 -14
- data/test/spec_lint.rb +164 -199
- data/test/spec_lobster.rb +24 -23
- data/test/spec_lock.rb +79 -39
- data/test/spec_logger.rb +4 -3
- data/test/spec_media_type.rb +42 -0
- data/test/{spec_methodoverride.rb → spec_method_override.rb} +34 -35
- data/test/spec_mime.rb +19 -19
- data/test/spec_mock.rb +206 -144
- data/test/spec_multipart.rb +322 -200
- data/test/{spec_nulllogger.rb → spec_null_logger.rb} +5 -4
- data/test/spec_recursive.rb +17 -14
- data/test/spec_request.rb +780 -605
- data/test/spec_response.rb +233 -112
- data/test/spec_rewindable_input.rb +50 -40
- data/test/spec_runtime.rb +11 -10
- data/test/spec_sendfile.rb +30 -35
- data/test/spec_server.rb +78 -52
- data/test/spec_session_abstract_id.rb +11 -33
- data/test/spec_session_abstract_session_hash.rb +45 -0
- data/test/spec_session_cookie.rb +99 -67
- data/test/spec_session_memcache.rb +67 -68
- data/test/spec_session_pool.rb +52 -51
- data/test/{spec_showexceptions.rb → spec_show_exceptions.rb} +23 -28
- data/test/{spec_showstatus.rb → spec_show_status.rb} +36 -35
- data/test/spec_static.rb +71 -32
- data/test/spec_tempfile_reaper.rb +11 -10
- data/test/spec_thin.rb +55 -50
- data/test/spec_urlmap.rb +79 -78
- data/test/spec_utils.rb +441 -346
- data/test/spec_version.rb +2 -8
- data/test/spec_webrick.rb +93 -71
- data/test/static/foo.html +1 -0
- data/test/testrequest.rb +1 -1
- data/test/unregistered_handler/rack/handler/unregistered.rb +1 -1
- data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +1 -1
- metadata +57 -36
- data/KNOWN-ISSUES +0 -44
- data/lib/rack/backports/uri/common_18.rb +0 -56
- data/lib/rack/backports/uri/common_192.rb +0 -52
- data/lib/rack/backports/uri/common_193.rb +0 -29
- data/lib/rack/handler/evented_mongrel.rb +0 -8
- data/lib/rack/handler/mongrel.rb +0 -106
- data/lib/rack/handler/swiftiplied_mongrel.rb +0 -8
- data/lib/rack/showexceptions.rb +0 -387
- data/lib/rack/utils/okjson.rb +0 -600
- data/test/spec_mongrel.rb +0 -182
- /data/lib/rack/{conditionalget.rb → conditional_get.rb} +0 -0
@@ -1,118 +1,128 @@
|
|
1
|
+
require 'minitest/autorun'
|
1
2
|
require 'stringio'
|
2
3
|
require 'rack/rewindable_input'
|
3
4
|
|
4
|
-
|
5
|
-
|
5
|
+
module RewindableTest
|
6
|
+
extend Minitest::Spec::DSL
|
7
|
+
|
8
|
+
def setup
|
6
9
|
@rio = Rack::RewindableInput.new(@io)
|
7
10
|
end
|
8
11
|
|
9
|
-
|
10
|
-
|
12
|
+
class << self # HACK to get this running w/ as few changes as possible
|
13
|
+
alias_method :should, :it
|
14
|
+
end
|
15
|
+
|
16
|
+
it "be able to handle to read()" do
|
17
|
+
@rio.read.must_equal "hello world"
|
11
18
|
end
|
12
19
|
|
13
|
-
|
14
|
-
@rio.read(nil).
|
20
|
+
it "be able to handle to read(nil)" do
|
21
|
+
@rio.read(nil).must_equal "hello world"
|
15
22
|
end
|
16
23
|
|
17
|
-
|
18
|
-
@rio.read(1).
|
24
|
+
it "be able to handle to read(length)" do
|
25
|
+
@rio.read(1).must_equal "h"
|
19
26
|
end
|
20
27
|
|
21
|
-
|
28
|
+
it "be able to handle to read(length, buffer)" do
|
22
29
|
buffer = ""
|
23
30
|
result = @rio.read(1, buffer)
|
24
|
-
result.
|
25
|
-
result.object_id.
|
31
|
+
result.must_equal "h"
|
32
|
+
result.object_id.must_equal buffer.object_id
|
26
33
|
end
|
27
34
|
|
28
|
-
|
35
|
+
it "be able to handle to read(nil, buffer)" do
|
29
36
|
buffer = ""
|
30
37
|
result = @rio.read(nil, buffer)
|
31
|
-
result.
|
32
|
-
result.object_id.
|
38
|
+
result.must_equal "hello world"
|
39
|
+
result.object_id.must_equal buffer.object_id
|
33
40
|
end
|
34
41
|
|
35
|
-
|
42
|
+
it "rewind to the beginning when #rewind is called" do
|
36
43
|
@rio.read(1)
|
37
44
|
@rio.rewind
|
38
|
-
@rio.read.
|
45
|
+
@rio.read.must_equal "hello world"
|
39
46
|
end
|
40
47
|
|
41
|
-
|
42
|
-
@rio.gets.
|
48
|
+
it "be able to handle gets" do
|
49
|
+
@rio.gets.must_equal "hello world"
|
43
50
|
end
|
44
51
|
|
45
|
-
|
52
|
+
it "be able to handle each" do
|
46
53
|
array = []
|
47
54
|
@rio.each do |data|
|
48
55
|
array << data
|
49
56
|
end
|
50
|
-
array.
|
57
|
+
array.must_equal ["hello world"]
|
51
58
|
end
|
52
59
|
|
53
|
-
|
54
|
-
@rio.instance_variable_get(:@rewindable_io).
|
60
|
+
it "not buffer into a Tempfile if no data has been read yet" do
|
61
|
+
@rio.instance_variable_get(:@rewindable_io).must_be_nil
|
55
62
|
end
|
56
63
|
|
57
|
-
|
64
|
+
it "buffer into a Tempfile when data has been consumed for the first time" do
|
58
65
|
@rio.read(1)
|
59
66
|
tempfile = @rio.instance_variable_get(:@rewindable_io)
|
60
|
-
tempfile.
|
67
|
+
tempfile.wont_be :nil?
|
61
68
|
@rio.read(1)
|
62
69
|
tempfile2 = @rio.instance_variable_get(:@rewindable_io)
|
63
|
-
tempfile2.path.
|
70
|
+
tempfile2.path.must_equal tempfile.path
|
64
71
|
end
|
65
72
|
|
66
|
-
|
73
|
+
it "close the underlying tempfile upon calling #close" do
|
67
74
|
@rio.read(1)
|
68
75
|
tempfile = @rio.instance_variable_get(:@rewindable_io)
|
69
76
|
@rio.close
|
70
|
-
tempfile.
|
77
|
+
tempfile.must_be :closed?
|
71
78
|
end
|
72
79
|
|
73
|
-
|
74
|
-
|
80
|
+
it "be possible to call #close when no data has been buffered yet" do
|
81
|
+
@rio.close.must_be_nil
|
75
82
|
end
|
76
83
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
@rio.close
|
81
|
-
}.should.not.raise
|
84
|
+
it "be possible to call #close multiple times" do
|
85
|
+
@rio.close.must_be_nil
|
86
|
+
@rio.close.must_be_nil
|
82
87
|
end
|
83
88
|
|
89
|
+
after do
|
84
90
|
@rio.close
|
85
91
|
@rio = nil
|
92
|
+
end
|
86
93
|
end
|
87
94
|
|
88
95
|
describe Rack::RewindableInput do
|
89
96
|
describe "given an IO object that is already rewindable" do
|
90
|
-
|
97
|
+
def setup
|
91
98
|
@io = StringIO.new("hello world")
|
99
|
+
super
|
92
100
|
end
|
93
101
|
|
94
|
-
|
102
|
+
include RewindableTest
|
95
103
|
end
|
96
104
|
|
97
105
|
describe "given an IO object that is not rewindable" do
|
98
|
-
|
106
|
+
def setup
|
99
107
|
@io = StringIO.new("hello world")
|
100
108
|
@io.instance_eval do
|
101
109
|
undef :rewind
|
102
110
|
end
|
111
|
+
super
|
103
112
|
end
|
104
113
|
|
105
|
-
|
114
|
+
include RewindableTest
|
106
115
|
end
|
107
116
|
|
108
117
|
describe "given an IO object whose rewind method raises Errno::ESPIPE" do
|
109
|
-
|
118
|
+
def setup
|
110
119
|
@io = StringIO.new("hello world")
|
111
120
|
def @io.rewind
|
112
121
|
raise Errno::ESPIPE, "You can't rewind this!"
|
113
122
|
end
|
123
|
+
super
|
114
124
|
end
|
115
125
|
|
116
|
-
|
126
|
+
include RewindableTest
|
117
127
|
end
|
118
128
|
end
|
data/test/spec_runtime.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'minitest/autorun'
|
1
2
|
require 'rack/lint'
|
2
3
|
require 'rack/mock'
|
3
4
|
require 'rack/runtime'
|
@@ -6,30 +7,30 @@ describe Rack::Runtime do
|
|
6
7
|
def runtime_app(app, *args)
|
7
8
|
Rack::Lint.new Rack::Runtime.new(app, *args)
|
8
9
|
end
|
9
|
-
|
10
|
+
|
10
11
|
def request
|
11
12
|
Rack::MockRequest.env_for
|
12
13
|
end
|
13
|
-
|
14
|
+
|
14
15
|
it "sets X-Runtime is none is set" do
|
15
16
|
app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, "Hello, World!"] }
|
16
17
|
response = runtime_app(app).call(request)
|
17
|
-
response[1]['X-Runtime'].
|
18
|
+
response[1]['X-Runtime'].must_match(/[\d\.]+/)
|
18
19
|
end
|
19
20
|
|
20
21
|
it "doesn't set the X-Runtime if it is already set" do
|
21
22
|
app = lambda { |env| [200, {'Content-Type' => 'text/plain', "X-Runtime" => "foobar"}, "Hello, World!"] }
|
22
23
|
response = runtime_app(app).call(request)
|
23
|
-
response[1]['X-Runtime'].
|
24
|
+
response[1]['X-Runtime'].must_equal "foobar"
|
24
25
|
end
|
25
26
|
|
26
|
-
|
27
|
+
it "allow a suffix to be set" do
|
27
28
|
app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, "Hello, World!"] }
|
28
29
|
response = runtime_app(app, "Test").call(request)
|
29
|
-
response[1]['X-Runtime-Test'].
|
30
|
+
response[1]['X-Runtime-Test'].must_match(/[\d\.]+/)
|
30
31
|
end
|
31
32
|
|
32
|
-
|
33
|
+
it "allow multiple timers to be set" do
|
33
34
|
app = lambda { |env| sleep 0.1; [200, {'Content-Type' => 'text/plain'}, "Hello, World!"] }
|
34
35
|
runtime = runtime_app(app, "App")
|
35
36
|
|
@@ -41,9 +42,9 @@ describe Rack::Runtime do
|
|
41
42
|
|
42
43
|
response = runtime.call(request)
|
43
44
|
|
44
|
-
response[1]['X-Runtime-App'].
|
45
|
-
response[1]['X-Runtime-All'].
|
45
|
+
response[1]['X-Runtime-App'].must_match(/[\d\.]+/)
|
46
|
+
response[1]['X-Runtime-All'].must_match(/[\d\.]+/)
|
46
47
|
|
47
|
-
Float(response[1]['X-Runtime-All']).
|
48
|
+
Float(response[1]['X-Runtime-All']).must_be :>, Float(response[1]['X-Runtime-App'])
|
48
49
|
end
|
49
50
|
end
|
data/test/spec_sendfile.rb
CHANGED
@@ -1,15 +1,10 @@
|
|
1
|
+
require 'minitest/autorun'
|
1
2
|
require 'fileutils'
|
2
3
|
require 'rack/lint'
|
3
4
|
require 'rack/sendfile'
|
4
5
|
require 'rack/mock'
|
5
6
|
require 'tmpdir'
|
6
7
|
|
7
|
-
describe Rack::File do
|
8
|
-
should "respond to #to_path" do
|
9
|
-
Rack::File.new(Dir.pwd).should.respond_to :to_path
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
8
|
describe Rack::Sendfile do
|
14
9
|
def sendfile_body
|
15
10
|
FileUtils.touch File.join(Dir.tmpdir, "rack_sendfile")
|
@@ -40,27 +35,27 @@ describe Rack::Sendfile do
|
|
40
35
|
|
41
36
|
it "does nothing when no X-Sendfile-Type header present" do
|
42
37
|
request do |response|
|
43
|
-
response.
|
44
|
-
response.body.
|
45
|
-
response.headers.
|
38
|
+
response.must_be :ok?
|
39
|
+
response.body.must_equal 'Hello World'
|
40
|
+
response.headers.wont_include 'X-Sendfile'
|
46
41
|
end
|
47
42
|
end
|
48
43
|
|
49
44
|
it "sets X-Sendfile response header and discards body" do
|
50
45
|
request 'HTTP_X_SENDFILE_TYPE' => 'X-Sendfile' do |response|
|
51
|
-
response.
|
52
|
-
response.body.
|
53
|
-
response.headers['Content-Length'].
|
54
|
-
response.headers['X-Sendfile'].
|
46
|
+
response.must_be :ok?
|
47
|
+
response.body.must_be :empty?
|
48
|
+
response.headers['Content-Length'].must_equal '0'
|
49
|
+
response.headers['X-Sendfile'].must_equal File.join(Dir.tmpdir, "rack_sendfile")
|
55
50
|
end
|
56
51
|
end
|
57
52
|
|
58
53
|
it "sets X-Lighttpd-Send-File response header and discards body" do
|
59
54
|
request 'HTTP_X_SENDFILE_TYPE' => 'X-Lighttpd-Send-File' do |response|
|
60
|
-
response.
|
61
|
-
response.body.
|
62
|
-
response.headers['Content-Length'].
|
63
|
-
response.headers['X-Lighttpd-Send-File'].
|
55
|
+
response.must_be :ok?
|
56
|
+
response.body.must_be :empty?
|
57
|
+
response.headers['Content-Length'].must_equal '0'
|
58
|
+
response.headers['X-Lighttpd-Send-File'].must_equal File.join(Dir.tmpdir, "rack_sendfile")
|
64
59
|
end
|
65
60
|
end
|
66
61
|
|
@@ -70,26 +65,26 @@ describe Rack::Sendfile do
|
|
70
65
|
'HTTP_X_ACCEL_MAPPING' => "#{Dir.tmpdir}/=/foo/bar/"
|
71
66
|
}
|
72
67
|
request headers do |response|
|
73
|
-
response.
|
74
|
-
response.body.
|
75
|
-
response.headers['Content-Length'].
|
76
|
-
response.headers['X-Accel-Redirect'].
|
68
|
+
response.must_be :ok?
|
69
|
+
response.body.must_be :empty?
|
70
|
+
response.headers['Content-Length'].must_equal '0'
|
71
|
+
response.headers['X-Accel-Redirect'].must_equal '/foo/bar/rack_sendfile'
|
77
72
|
end
|
78
73
|
end
|
79
74
|
|
80
75
|
it 'writes to rack.error when no X-Accel-Mapping is specified' do
|
81
76
|
request 'HTTP_X_SENDFILE_TYPE' => 'X-Accel-Redirect' do |response|
|
82
|
-
response.
|
83
|
-
response.body.
|
84
|
-
response.headers.
|
85
|
-
response.errors.
|
77
|
+
response.must_be :ok?
|
78
|
+
response.body.must_equal 'Hello World'
|
79
|
+
response.headers.wont_include 'X-Accel-Redirect'
|
80
|
+
response.errors.must_include 'X-Accel-Mapping'
|
86
81
|
end
|
87
82
|
end
|
88
83
|
|
89
84
|
it 'does nothing when body does not respond to #to_path' do
|
90
85
|
request({'HTTP_X_SENDFILE_TYPE' => 'X-Sendfile'}, ['Not a file...']) do |response|
|
91
|
-
response.body.
|
92
|
-
response.headers.
|
86
|
+
response.body.must_equal 'Not a file...'
|
87
|
+
response.headers.wont_include 'X-Sendfile'
|
93
88
|
end
|
94
89
|
end
|
95
90
|
|
@@ -110,17 +105,17 @@ describe Rack::Sendfile do
|
|
110
105
|
]
|
111
106
|
|
112
107
|
request({'HTTP_X_SENDFILE_TYPE' => 'X-Accel-Redirect'}, first_body, mappings) do |response|
|
113
|
-
response.
|
114
|
-
response.body.
|
115
|
-
response.headers['Content-Length'].
|
116
|
-
response.headers['X-Accel-Redirect'].
|
108
|
+
response.must_be :ok?
|
109
|
+
response.body.must_be :empty?
|
110
|
+
response.headers['Content-Length'].must_equal '0'
|
111
|
+
response.headers['X-Accel-Redirect'].must_equal '/foo/bar/rack_sendfile'
|
117
112
|
end
|
118
113
|
|
119
114
|
request({'HTTP_X_SENDFILE_TYPE' => 'X-Accel-Redirect'}, second_body, mappings) do |response|
|
120
|
-
response.
|
121
|
-
response.body.
|
122
|
-
response.headers['Content-Length'].
|
123
|
-
response.headers['X-Accel-Redirect'].
|
115
|
+
response.must_be :ok?
|
116
|
+
response.body.must_be :empty?
|
117
|
+
response.headers['Content-Length'].must_equal '0'
|
118
|
+
response.headers['X-Accel-Redirect'].must_equal '/wibble/rack_sendfile'
|
124
119
|
end
|
125
120
|
ensure
|
126
121
|
FileUtils.remove_entry_secure dir1
|
data/test/spec_server.rb
CHANGED
@@ -1,10 +1,18 @@
|
|
1
|
+
require 'minitest/autorun'
|
1
2
|
require 'rack'
|
2
3
|
require 'rack/server'
|
3
4
|
require 'tempfile'
|
4
5
|
require 'socket'
|
5
6
|
require 'open-uri'
|
6
7
|
|
8
|
+
module Minitest::Spec::DSL
|
9
|
+
alias :should :it
|
10
|
+
end
|
11
|
+
|
7
12
|
describe Rack::Server do
|
13
|
+
SPEC_ARGV = []
|
14
|
+
|
15
|
+
before { SPEC_ARGV[0..-1] = [] }
|
8
16
|
|
9
17
|
def app
|
10
18
|
lambda { |env| [200, {'Content-Type' => 'text/plain'}, ['success']] }
|
@@ -19,148 +27,166 @@ describe Rack::Server do
|
|
19
27
|
|
20
28
|
it "overrides :config if :app is passed in" do
|
21
29
|
server = Rack::Server.new(:app => "FOO")
|
22
|
-
server.app.
|
30
|
+
server.app.must_equal "FOO"
|
23
31
|
end
|
24
32
|
|
25
|
-
|
33
|
+
it "prefer to use :builder when it is passed in" do
|
26
34
|
server = Rack::Server.new(:builder => "run lambda { |env| [200, {'Content-Type' => 'text/plain'}, ['success']] }")
|
27
|
-
server.app.class.
|
28
|
-
Rack::MockRequest.new(server.app).get("/").body.to_s.
|
35
|
+
server.app.class.must_equal Proc
|
36
|
+
Rack::MockRequest.new(server.app).get("/").body.to_s.must_equal 'success'
|
29
37
|
end
|
30
38
|
|
31
|
-
|
39
|
+
it "allow subclasses to override middleware" do
|
32
40
|
server = Class.new(Rack::Server).class_eval { def middleware; Hash.new [] end; self }
|
33
|
-
server.middleware['deployment'].
|
34
|
-
server.new(:app => 'foo').middleware['deployment'].
|
41
|
+
server.middleware['deployment'].wont_equal []
|
42
|
+
server.new(:app => 'foo').middleware['deployment'].must_equal []
|
35
43
|
end
|
36
44
|
|
37
|
-
|
45
|
+
it "allow subclasses to override default middleware" do
|
38
46
|
server = Class.new(Rack::Server).instance_eval { def default_middleware_by_environment; Hash.new [] end; self }
|
39
|
-
server.middleware['deployment'].
|
40
|
-
server.new(:app => 'foo').middleware['deployment'].
|
47
|
+
server.middleware['deployment'].must_equal []
|
48
|
+
server.new(:app => 'foo').middleware['deployment'].must_equal []
|
41
49
|
end
|
42
50
|
|
43
|
-
|
44
|
-
Rack::Server.default_middleware_by_environment.keys.sort.
|
51
|
+
it "only provide default middleware for development and deployment environments" do
|
52
|
+
Rack::Server.default_middleware_by_environment.keys.sort.must_equal %w(deployment development)
|
45
53
|
end
|
46
54
|
|
47
|
-
|
55
|
+
it "always return an empty array for unknown environments" do
|
48
56
|
server = Rack::Server.new(:app => 'foo')
|
49
|
-
server.middleware['production'].
|
57
|
+
server.middleware['production'].must_equal []
|
50
58
|
end
|
51
59
|
|
52
|
-
|
60
|
+
it "not include Rack::Lint in deployment environment" do
|
53
61
|
server = Rack::Server.new(:app => 'foo')
|
54
|
-
server.middleware['deployment'].flatten.
|
62
|
+
server.middleware['deployment'].flatten.wont_include Rack::Lint
|
55
63
|
end
|
56
64
|
|
57
|
-
|
65
|
+
it "not include Rack::ShowExceptions in deployment environment" do
|
58
66
|
server = Rack::Server.new(:app => 'foo')
|
59
|
-
server.middleware['deployment'].flatten.
|
67
|
+
server.middleware['deployment'].flatten.wont_include Rack::ShowExceptions
|
60
68
|
end
|
61
69
|
|
62
|
-
|
70
|
+
it "include Rack::TempfileReaper in deployment environment" do
|
63
71
|
server = Rack::Server.new(:app => 'foo')
|
64
|
-
server.middleware['deployment'].flatten.
|
72
|
+
server.middleware['deployment'].flatten.must_include Rack::TempfileReaper
|
65
73
|
end
|
66
74
|
|
67
|
-
|
75
|
+
it "support CGI" do
|
68
76
|
begin
|
69
77
|
o, ENV["REQUEST_METHOD"] = ENV["REQUEST_METHOD"], 'foo'
|
70
78
|
server = Rack::Server.new(:app => 'foo')
|
71
79
|
server.server.name =~ /CGI/
|
72
|
-
Rack::Server.logging_middleware.call(server).
|
80
|
+
Rack::Server.logging_middleware.call(server).must_be_nil
|
73
81
|
ensure
|
74
82
|
ENV['REQUEST_METHOD'] = o
|
75
83
|
end
|
76
84
|
end
|
77
85
|
|
78
|
-
|
86
|
+
it "be quiet if said so" do
|
79
87
|
server = Rack::Server.new(:app => "FOO", :quiet => true)
|
80
|
-
Rack::Server.logging_middleware.call(server).
|
88
|
+
Rack::Server.logging_middleware.call(server).must_be_nil
|
81
89
|
end
|
82
90
|
|
83
|
-
|
91
|
+
it "use a full path to the pidfile" do
|
84
92
|
# avoids issues with daemonize chdir
|
85
93
|
opts = Rack::Server.new.send(:parse_options, %w[--pid testing.pid])
|
86
|
-
opts[:pid].
|
94
|
+
opts[:pid].must_equal ::File.expand_path('testing.pid')
|
87
95
|
end
|
88
96
|
|
89
|
-
|
90
|
-
|
91
|
-
|
97
|
+
it "get options from ARGV" do
|
98
|
+
SPEC_ARGV[0..-1] = ['--debug', '-sthin', '--env', 'production']
|
99
|
+
server = Rack::Server.new
|
100
|
+
server.options[:debug].must_equal true
|
101
|
+
server.options[:server].must_equal 'thin'
|
102
|
+
server.options[:environment].must_equal 'production'
|
103
|
+
end
|
104
|
+
|
105
|
+
it "only override non-passed options from parsed .ru file" do
|
106
|
+
builder_file = File.join(File.dirname(__FILE__), 'builder', 'options.ru')
|
107
|
+
SPEC_ARGV[0..-1] = ['--debug', '-sthin', '--env', 'production', builder_file]
|
108
|
+
server = Rack::Server.new
|
109
|
+
server.app # force .ru file to be parsed
|
110
|
+
|
111
|
+
server.options[:debug].must_equal true
|
112
|
+
server.options[:server].must_equal 'thin'
|
113
|
+
server.options[:environment].must_equal 'production'
|
114
|
+
server.options[:Port].must_equal '2929'
|
115
|
+
end
|
116
|
+
|
117
|
+
it "run a server" do
|
118
|
+
pidfile = Tempfile.open('pidfile') { |f| break f }
|
119
|
+
FileUtils.rm pidfile.path
|
92
120
|
server = Rack::Server.new(
|
93
121
|
:app => app,
|
94
122
|
:environment => 'none',
|
95
|
-
:pid => pidfile,
|
123
|
+
:pid => pidfile.path,
|
96
124
|
:Port => TCPServer.open('127.0.0.1', 0){|s| s.addr[1] },
|
97
125
|
:Host => '127.0.0.1',
|
126
|
+
:Logger => WEBrick::Log.new(nil, WEBrick::BasicLog::WARN),
|
127
|
+
:AccessLog => [],
|
98
128
|
:daemonize => false,
|
99
129
|
:server => 'webrick'
|
100
130
|
)
|
101
131
|
t = Thread.new { server.start { |s| Thread.current[:server] = s } }
|
102
132
|
t.join(0.01) until t[:server] && t[:server].status != :Stop
|
103
133
|
body = open("http://127.0.0.1:#{server.options[:Port]}/") { |f| f.read }
|
104
|
-
body.
|
134
|
+
body.must_equal 'success'
|
105
135
|
|
106
136
|
Process.kill(:INT, $$)
|
107
137
|
t.join
|
108
|
-
open(pidfile) { |f| f.read.
|
138
|
+
open(pidfile.path) { |f| f.read.must_equal $$.to_s }
|
109
139
|
end
|
110
140
|
|
111
|
-
|
141
|
+
it "check pid file presence and running process" do
|
112
142
|
pidfile = Tempfile.open('pidfile') { |f| f.write($$); break f }.path
|
113
143
|
server = Rack::Server.new(:pid => pidfile)
|
114
|
-
server.send(:pidfile_process_status).
|
144
|
+
server.send(:pidfile_process_status).must_equal :running
|
115
145
|
end
|
116
146
|
|
117
|
-
|
147
|
+
it "check pid file presence and dead process" do
|
118
148
|
dead_pid = `echo $$`.to_i
|
119
149
|
pidfile = Tempfile.open('pidfile') { |f| f.write(dead_pid); break f }.path
|
120
150
|
server = Rack::Server.new(:pid => pidfile)
|
121
|
-
server.send(:pidfile_process_status).
|
151
|
+
server.send(:pidfile_process_status).must_equal :dead
|
122
152
|
end
|
123
153
|
|
124
|
-
|
154
|
+
it "check pid file presence and exited process" do
|
125
155
|
pidfile = Tempfile.open('pidfile') { |f| break f }.path
|
126
156
|
::File.delete(pidfile)
|
127
157
|
server = Rack::Server.new(:pid => pidfile)
|
128
|
-
server.send(:pidfile_process_status).
|
158
|
+
server.send(:pidfile_process_status).must_equal :exited
|
129
159
|
end
|
130
160
|
|
131
|
-
|
161
|
+
it "check pid file presence and not owned process" do
|
132
162
|
pidfile = Tempfile.open('pidfile') { |f| f.write(1); break f }.path
|
133
163
|
server = Rack::Server.new(:pid => pidfile)
|
134
|
-
server.send(:pidfile_process_status).
|
164
|
+
server.send(:pidfile_process_status).must_equal :not_owned
|
135
165
|
end
|
136
166
|
|
137
|
-
|
167
|
+
it "not write pid file when it is created after check" do
|
138
168
|
pidfile = Tempfile.open('pidfile') { |f| break f }.path
|
139
169
|
::File.delete(pidfile)
|
140
170
|
server = Rack::Server.new(:pid => pidfile)
|
141
171
|
::File.open(pidfile, 'w') { |f| f.write(1) }
|
142
172
|
with_stderr do |err|
|
143
|
-
|
144
|
-
server.send(:write_pid)
|
145
|
-
end
|
173
|
+
lambda { server.send(:write_pid) }.must_raise SystemExit
|
146
174
|
err.rewind
|
147
175
|
output = err.read
|
148
|
-
output.
|
149
|
-
output.
|
176
|
+
output.must_match(/already running/)
|
177
|
+
output.must_include pidfile
|
150
178
|
end
|
151
179
|
end
|
152
180
|
|
153
|
-
|
181
|
+
it "inform the user about existing pidfiles with running processes" do
|
154
182
|
pidfile = Tempfile.open('pidfile') { |f| f.write(1); break f }.path
|
155
183
|
server = Rack::Server.new(:pid => pidfile)
|
156
184
|
with_stderr do |err|
|
157
|
-
|
158
|
-
server.start
|
159
|
-
end
|
185
|
+
lambda { server.start }.must_raise SystemExit
|
160
186
|
err.rewind
|
161
187
|
output = err.read
|
162
|
-
output.
|
163
|
-
output.
|
188
|
+
output.must_match(/already running/)
|
189
|
+
output.must_include pidfile
|
164
190
|
end
|
165
191
|
end
|
166
192
|
|
@@ -1,53 +1,31 @@
|
|
1
|
+
require 'minitest/autorun'
|
1
2
|
### WARNING: there be hax in this file.
|
2
3
|
|
3
4
|
require 'rack/session/abstract/id'
|
4
5
|
|
5
6
|
describe Rack::Session::Abstract::ID do
|
6
|
-
id
|
7
|
+
attr_reader :id
|
7
8
|
|
8
|
-
def
|
9
|
-
|
10
|
-
|
11
|
-
ensure
|
12
|
-
$VERBOSE = o
|
9
|
+
def setup
|
10
|
+
super
|
11
|
+
@id = Rack::Session::Abstract::ID
|
13
12
|
end
|
14
13
|
|
15
|
-
|
16
|
-
|
17
|
-
silence_warning { require 'rack/session/abstract/id' }
|
18
|
-
end
|
19
|
-
|
20
|
-
should "use securerandom when available" do
|
21
|
-
begin
|
22
|
-
fake = false
|
23
|
-
silence_warning do
|
24
|
-
::SecureRandom = fake = true unless defined?(SecureRandom)
|
25
|
-
end
|
26
|
-
reload_id
|
27
|
-
id::DEFAULT_OPTIONS[:secure_random].should.eql(fake || SecureRandom)
|
28
|
-
ensure
|
29
|
-
Object.send(:remove_const, :SecureRandom) if fake
|
30
|
-
end
|
31
|
-
end
|
14
|
+
it "use securerandom" do
|
15
|
+
assert_equal ::SecureRandom, id::DEFAULT_OPTIONS[:secure_random]
|
32
16
|
|
33
|
-
|
34
|
-
|
35
|
-
sr = Object.send(:remove_const, :SecureRandom) if defined?(SecureRandom)
|
36
|
-
reload_id
|
37
|
-
id::DEFAULT_OPTIONS[:secure_random].should.eql false
|
38
|
-
ensure
|
39
|
-
::SecureRandom = sr if defined?(sr)
|
40
|
-
end
|
17
|
+
id = @id.new nil
|
18
|
+
assert_equal ::SecureRandom, id.sid_secure
|
41
19
|
end
|
42
20
|
|
43
|
-
|
21
|
+
it "allow to use another securerandom provider" do
|
44
22
|
secure_random = Class.new do
|
45
23
|
def hex(*args)
|
46
24
|
'fake_hex'
|
47
25
|
end
|
48
26
|
end
|
49
27
|
id = Rack::Session::Abstract::ID.new nil, :secure_random => secure_random.new
|
50
|
-
id.send(:generate_sid).
|
28
|
+
id.send(:generate_sid).must_equal 'fake_hex'
|
51
29
|
end
|
52
30
|
|
53
31
|
end
|