rack 1.1.6 → 1.6.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/COPYING +1 -1
- data/HISTORY.md +375 -0
- data/KNOWN-ISSUES +23 -0
- data/README.rdoc +312 -0
- data/Rakefile +124 -0
- data/SPEC +125 -32
- data/contrib/rack.png +0 -0
- data/contrib/rack.svg +150 -0
- data/contrib/rack_logo.svg +1 -1
- data/contrib/rdoc.css +412 -0
- data/example/protectedlobster.rb +1 -1
- data/lib/rack/auth/abstract/handler.rb +4 -4
- data/lib/rack/auth/abstract/request.rb +7 -5
- data/lib/rack/auth/basic.rb +1 -1
- data/lib/rack/auth/digest/md5.rb +7 -3
- data/lib/rack/auth/digest/nonce.rb +1 -1
- data/lib/rack/auth/digest/params.rb +7 -9
- data/lib/rack/auth/digest/request.rb +10 -9
- data/lib/rack/backports/uri/common_18.rb +56 -0
- data/lib/rack/backports/uri/common_192.rb +52 -0
- data/lib/rack/backports/uri/common_193.rb +29 -0
- data/lib/rack/body_proxy.rb +39 -0
- data/lib/rack/builder.rb +106 -22
- data/lib/rack/cascade.rb +17 -6
- data/lib/rack/chunked.rb +44 -24
- data/lib/rack/commonlogger.rb +36 -13
- data/lib/rack/conditionalget.rb +49 -17
- data/lib/rack/config.rb +5 -0
- data/lib/rack/content_length.rb +14 -6
- data/lib/rack/content_type.rb +7 -1
- data/lib/rack/deflater.rb +73 -15
- data/lib/rack/directory.rb +18 -8
- data/lib/rack/etag.rb +59 -9
- data/lib/rack/file.rb +106 -44
- data/lib/rack/handler/cgi.rb +11 -11
- data/lib/rack/handler/fastcgi.rb +18 -6
- data/lib/rack/handler/lsws.rb +2 -4
- data/lib/rack/handler/mongrel.rb +22 -6
- data/lib/rack/handler/scgi.rb +16 -8
- data/lib/rack/handler/thin.rb +19 -4
- data/lib/rack/handler/webrick.rb +72 -19
- data/lib/rack/handler.rb +47 -14
- data/lib/rack/head.rb +10 -2
- data/lib/rack/lint.rb +260 -75
- data/lib/rack/lobster.rb +13 -8
- data/lib/rack/lock.rb +13 -3
- data/lib/rack/logger.rb +0 -2
- data/lib/rack/methodoverride.rb +27 -8
- data/lib/rack/mime.rb +625 -167
- data/lib/rack/mock.rb +78 -53
- data/lib/rack/multipart/generator.rb +93 -0
- data/lib/rack/multipart/parser.rb +253 -0
- data/lib/rack/multipart/uploaded_file.rb +34 -0
- data/lib/rack/multipart.rb +34 -0
- data/lib/rack/nulllogger.rb +21 -2
- data/lib/rack/recursive.rb +10 -5
- data/lib/rack/reloader.rb +3 -2
- data/lib/rack/request.rb +201 -74
- data/lib/rack/response.rb +41 -28
- data/lib/rack/rewindable_input.rb +15 -11
- data/lib/rack/runtime.rb +16 -3
- data/lib/rack/sendfile.rb +47 -29
- data/lib/rack/server.rb +223 -47
- data/lib/rack/session/abstract/id.rb +289 -30
- data/lib/rack/session/cookie.rb +133 -44
- data/lib/rack/session/memcache.rb +30 -56
- data/lib/rack/session/pool.rb +19 -43
- data/lib/rack/showexceptions.rb +53 -15
- data/lib/rack/showstatus.rb +14 -7
- data/lib/rack/static.rb +124 -12
- data/lib/rack/tempfile_reaper.rb +22 -0
- data/lib/rack/urlmap.rb +49 -15
- data/lib/rack/utils/okjson.rb +600 -0
- data/lib/rack/utils.rb +363 -361
- data/lib/rack.rb +17 -23
- data/rack.gemspec +11 -20
- data/test/builder/anything.rb +5 -0
- data/test/builder/comment.ru +4 -0
- data/test/builder/end.ru +5 -0
- data/test/builder/line.ru +1 -0
- data/test/builder/options.ru +2 -0
- data/test/cgi/assets/folder/test.js +1 -0
- data/test/cgi/assets/fonts/font.eot +1 -0
- data/test/cgi/assets/images/image.png +1 -0
- data/test/cgi/assets/index.html +1 -0
- data/test/cgi/assets/javascripts/app.js +1 -0
- data/test/cgi/assets/stylesheets/app.css +1 -0
- data/test/cgi/lighttpd.conf +26 -0
- data/test/cgi/rackup_stub.rb +6 -0
- data/test/cgi/sample_rackup.ru +5 -0
- data/test/cgi/test +9 -0
- data/test/cgi/test+directory/test+file +1 -0
- data/test/cgi/test.fcgi +8 -0
- data/test/cgi/test.ru +5 -0
- data/test/gemloader.rb +10 -0
- data/test/multipart/bad_robots +259 -0
- data/test/multipart/binary +0 -0
- data/test/multipart/content_type_and_no_filename +6 -0
- data/test/multipart/empty +10 -0
- data/test/multipart/fail_16384_nofile +814 -0
- data/test/multipart/file1.txt +1 -0
- data/test/multipart/filename_and_modification_param +7 -0
- data/test/multipart/filename_and_no_name +6 -0
- data/test/multipart/filename_with_escaped_quotes +6 -0
- data/test/multipart/filename_with_escaped_quotes_and_modification_param +7 -0
- data/test/multipart/filename_with_null_byte +7 -0
- data/test/multipart/filename_with_percent_escaped_quotes +6 -0
- data/test/multipart/filename_with_unescaped_percentages +6 -0
- data/test/multipart/filename_with_unescaped_percentages2 +6 -0
- data/test/multipart/filename_with_unescaped_percentages3 +6 -0
- data/test/multipart/filename_with_unescaped_quotes +6 -0
- data/test/multipart/ie +6 -0
- data/test/multipart/invalid_character +6 -0
- data/test/multipart/mixed_files +21 -0
- data/test/multipart/nested +10 -0
- data/test/multipart/none +9 -0
- data/test/multipart/semicolon +6 -0
- data/test/multipart/text +15 -0
- data/test/multipart/three_files_three_fields +31 -0
- data/test/multipart/webkit +32 -0
- data/test/rackup/config.ru +31 -0
- data/test/registering_handler/rack/handler/registering_myself.rb +8 -0
- data/test/{spec_rack_auth_basic.rb → spec_auth_basic.rb} +23 -15
- data/test/{spec_rack_auth_digest.rb → spec_auth_digest.rb} +56 -29
- data/test/spec_body_proxy.rb +85 -0
- data/test/spec_builder.rb +223 -0
- data/test/{spec_rack_cascade.rb → spec_cascade.rb} +28 -15
- data/test/{spec_rack_cgi.rb → spec_cgi.rb} +44 -31
- data/test/spec_chunked.rb +101 -0
- data/test/spec_commonlogger.rb +93 -0
- data/test/spec_conditionalget.rb +102 -0
- data/test/{spec_rack_config.rb → spec_config.rb} +6 -8
- data/test/spec_content_length.rb +85 -0
- data/test/spec_content_type.rb +45 -0
- data/test/spec_deflater.rb +339 -0
- data/test/{spec_rack_directory.rb → spec_directory.rb} +37 -10
- data/test/spec_etag.rb +107 -0
- data/test/{spec_rack_fastcgi.rb → spec_fastcgi.rb} +47 -29
- data/test/spec_file.rb +221 -0
- data/test/spec_handler.rb +72 -0
- data/test/spec_head.rb +45 -0
- data/test/{spec_rack_lint.rb → spec_lint.rb} +82 -60
- data/test/spec_lobster.rb +58 -0
- data/test/spec_lock.rb +164 -0
- data/test/spec_logger.rb +23 -0
- data/test/spec_methodoverride.rb +95 -0
- data/test/spec_mime.rb +51 -0
- data/test/{spec_rack_mock.rb → spec_mock.rb} +92 -38
- data/test/{spec_rack_mongrel.rb → spec_mongrel.rb} +46 -53
- data/test/spec_multipart.rb +600 -0
- data/test/spec_nulllogger.rb +20 -0
- data/test/spec_recursive.rb +72 -0
- data/test/spec_request.rb +1227 -0
- data/test/spec_response.rb +407 -0
- data/test/spec_rewindable_input.rb +118 -0
- data/test/spec_runtime.rb +49 -0
- data/test/spec_sendfile.rb +130 -0
- data/test/spec_server.rb +167 -0
- data/test/spec_session_abstract_id.rb +53 -0
- data/test/spec_session_cookie.rb +410 -0
- data/test/{spec_rack_session_memcache.rb → spec_session_memcache.rb} +119 -71
- data/test/{spec_rack_session_pool.rb → spec_session_pool.rb} +106 -69
- data/test/spec_showexceptions.rb +85 -0
- data/test/spec_showstatus.rb +103 -0
- data/test/spec_static.rb +145 -0
- data/test/spec_tempfile_reaper.rb +63 -0
- data/test/{spec_rack_thin.rb → spec_thin.rb} +35 -35
- data/test/{spec_rack_urlmap.rb → spec_urlmap.rb} +40 -19
- data/test/spec_utils.rb +647 -0
- data/test/spec_version.rb +17 -0
- data/test/spec_webrick.rb +184 -0
- data/test/static/another/index.html +1 -0
- data/test/static/index.html +1 -0
- data/test/testrequest.rb +78 -0
- data/test/unregistered_handler/rack/handler/unregistered.rb +7 -0
- data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +7 -0
- metadata +220 -239
- data/RDOX +0 -0
- data/README +0 -592
- data/lib/rack/adapter/camping.rb +0 -22
- data/test/spec_auth.rb +0 -57
- data/test/spec_rack_builder.rb +0 -84
- data/test/spec_rack_camping.rb +0 -55
- data/test/spec_rack_chunked.rb +0 -62
- data/test/spec_rack_commonlogger.rb +0 -61
- data/test/spec_rack_conditionalget.rb +0 -41
- data/test/spec_rack_content_length.rb +0 -43
- data/test/spec_rack_content_type.rb +0 -30
- data/test/spec_rack_deflater.rb +0 -127
- data/test/spec_rack_etag.rb +0 -17
- data/test/spec_rack_file.rb +0 -75
- data/test/spec_rack_handler.rb +0 -43
- data/test/spec_rack_head.rb +0 -30
- data/test/spec_rack_lobster.rb +0 -45
- data/test/spec_rack_lock.rb +0 -38
- data/test/spec_rack_logger.rb +0 -21
- data/test/spec_rack_methodoverride.rb +0 -60
- data/test/spec_rack_nulllogger.rb +0 -13
- data/test/spec_rack_recursive.rb +0 -77
- data/test/spec_rack_request.rb +0 -594
- data/test/spec_rack_response.rb +0 -221
- data/test/spec_rack_rewindable_input.rb +0 -118
- data/test/spec_rack_runtime.rb +0 -35
- data/test/spec_rack_sendfile.rb +0 -86
- data/test/spec_rack_session_cookie.rb +0 -92
- data/test/spec_rack_showexceptions.rb +0 -21
- data/test/spec_rack_showstatus.rb +0 -72
- data/test/spec_rack_static.rb +0 -37
- data/test/spec_rack_utils.rb +0 -557
- data/test/spec_rack_webrick.rb +0 -130
- data/test/spec_rackup.rb +0 -164
data/lib/rack/sendfile.rb
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
require 'rack/file'
|
|
2
|
+
require 'rack/body_proxy'
|
|
2
3
|
|
|
3
4
|
module Rack
|
|
4
|
-
class File #:nodoc:
|
|
5
|
-
alias :to_path :path
|
|
6
|
-
end
|
|
7
5
|
|
|
8
6
|
# = Sendfile
|
|
9
7
|
#
|
|
@@ -11,7 +9,7 @@ module Rack
|
|
|
11
9
|
# served from a file and replaces it with a server specific X-Sendfile
|
|
12
10
|
# header. The web server is then responsible for writing the file contents
|
|
13
11
|
# to the client. This can dramatically reduce the amount of work required
|
|
14
|
-
# by the Ruby backend and takes advantage of the web
|
|
12
|
+
# by the Ruby backend and takes advantage of the web server's optimized file
|
|
15
13
|
# delivery code.
|
|
16
14
|
#
|
|
17
15
|
# In order to take advantage of this middleware, the response body must
|
|
@@ -25,33 +23,33 @@ module Rack
|
|
|
25
23
|
#
|
|
26
24
|
# Nginx supports the X-Accel-Redirect header. This is similar to X-Sendfile
|
|
27
25
|
# but requires parts of the filesystem to be mapped into a private URL
|
|
28
|
-
#
|
|
26
|
+
# hierarchy.
|
|
29
27
|
#
|
|
30
28
|
# The following example shows the Nginx configuration required to create
|
|
31
29
|
# a private "/files/" area, enable X-Accel-Redirect, and pass the special
|
|
32
30
|
# X-Sendfile-Type and X-Accel-Mapping headers to the backend:
|
|
33
31
|
#
|
|
34
|
-
# location /files/ {
|
|
32
|
+
# location ~ /files/(.*) {
|
|
35
33
|
# internal;
|
|
36
|
-
# alias /var/www
|
|
34
|
+
# alias /var/www/$1;
|
|
37
35
|
# }
|
|
38
36
|
#
|
|
39
37
|
# location / {
|
|
40
|
-
# proxy_redirect
|
|
38
|
+
# proxy_redirect off;
|
|
41
39
|
#
|
|
42
40
|
# proxy_set_header Host $host;
|
|
43
41
|
# proxy_set_header X-Real-IP $remote_addr;
|
|
44
42
|
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
45
43
|
#
|
|
46
|
-
# proxy_set_header X-Sendfile-Type X-Accel-Redirect
|
|
47
|
-
# proxy_set_header X-Accel-Mapping /
|
|
44
|
+
# proxy_set_header X-Sendfile-Type X-Accel-Redirect;
|
|
45
|
+
# proxy_set_header X-Accel-Mapping /var/www/=/files/;
|
|
48
46
|
#
|
|
49
47
|
# proxy_pass http://127.0.0.1:8080/;
|
|
50
48
|
# }
|
|
51
49
|
#
|
|
52
|
-
# Note that the X-Sendfile-Type header must be set exactly as shown above.
|
|
53
|
-
# X-Accel-Mapping header should specify the
|
|
54
|
-
# followed by an equals sign (=), followed
|
|
50
|
+
# Note that the X-Sendfile-Type header must be set exactly as shown above.
|
|
51
|
+
# The X-Accel-Mapping header should specify the location on the file system,
|
|
52
|
+
# followed by an equals sign (=), followed name of the private URL pattern
|
|
55
53
|
# that it maps to. The middleware performs a simple substitution on the
|
|
56
54
|
# resulting path.
|
|
57
55
|
#
|
|
@@ -84,7 +82,7 @@ module Rack
|
|
|
84
82
|
#
|
|
85
83
|
# X-Sendfile is supported under Apache 2.x using a separate module:
|
|
86
84
|
#
|
|
87
|
-
#
|
|
85
|
+
# https://tn123.org/mod_xsendfile/
|
|
88
86
|
#
|
|
89
87
|
# Once the module is compiled and installed, you can enable it using
|
|
90
88
|
# XSendFile config directive:
|
|
@@ -92,13 +90,23 @@ module Rack
|
|
|
92
90
|
# RequestHeader Set X-Sendfile-Type X-Sendfile
|
|
93
91
|
# ProxyPassReverse / http://localhost:8001/
|
|
94
92
|
# XSendFile on
|
|
93
|
+
#
|
|
94
|
+
# === Mapping parameter
|
|
95
|
+
#
|
|
96
|
+
# The third parameter allows for an overriding extension of the
|
|
97
|
+
# X-Accel-Mapping header. Mappings should be provided in tuples of internal to
|
|
98
|
+
# external. The internal values may contain regular expression syntax, they
|
|
99
|
+
# will be matched with case indifference.
|
|
95
100
|
|
|
96
101
|
class Sendfile
|
|
97
102
|
F = ::File
|
|
98
103
|
|
|
99
|
-
def initialize(app, variation=nil)
|
|
104
|
+
def initialize(app, variation=nil, mappings=[])
|
|
100
105
|
@app = app
|
|
101
106
|
@variation = variation
|
|
107
|
+
@mappings = mappings.map do |internal, external|
|
|
108
|
+
[/^#{internal}/i, external]
|
|
109
|
+
end
|
|
102
110
|
end
|
|
103
111
|
|
|
104
112
|
def call(env)
|
|
@@ -108,35 +116,45 @@ module Rack
|
|
|
108
116
|
when 'X-Accel-Redirect'
|
|
109
117
|
path = F.expand_path(body.to_path)
|
|
110
118
|
if url = map_accel_path(env, path)
|
|
119
|
+
headers[CONTENT_LENGTH] = '0'
|
|
111
120
|
headers[type] = url
|
|
112
|
-
|
|
121
|
+
obody = body
|
|
122
|
+
body = Rack::BodyProxy.new([]) do
|
|
123
|
+
obody.close if obody.respond_to?(:close)
|
|
124
|
+
end
|
|
113
125
|
else
|
|
114
|
-
env['rack.errors']
|
|
126
|
+
env['rack.errors'].puts "X-Accel-Mapping header missing"
|
|
115
127
|
end
|
|
116
128
|
when 'X-Sendfile', 'X-Lighttpd-Send-File'
|
|
117
129
|
path = F.expand_path(body.to_path)
|
|
130
|
+
headers[CONTENT_LENGTH] = '0'
|
|
118
131
|
headers[type] = path
|
|
119
|
-
|
|
132
|
+
obody = body
|
|
133
|
+
body = Rack::BodyProxy.new([]) do
|
|
134
|
+
obody.close if obody.respond_to?(:close)
|
|
135
|
+
end
|
|
120
136
|
when '', nil
|
|
121
137
|
else
|
|
122
|
-
env['rack.errors']
|
|
138
|
+
env['rack.errors'].puts "Unknown x-sendfile variation: '#{type}'.\n"
|
|
123
139
|
end
|
|
124
140
|
end
|
|
125
141
|
[status, headers, body]
|
|
126
142
|
end
|
|
127
143
|
|
|
128
144
|
private
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
145
|
+
def variation(env)
|
|
146
|
+
@variation ||
|
|
147
|
+
env['sendfile.type'] ||
|
|
148
|
+
env['HTTP_X_SENDFILE_TYPE']
|
|
149
|
+
end
|
|
134
150
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
151
|
+
def map_accel_path(env, path)
|
|
152
|
+
if mapping = @mappings.find { |internal,_| internal =~ path }
|
|
153
|
+
path.sub(*mapping)
|
|
154
|
+
elsif mapping = env['HTTP_X_ACCEL_MAPPING']
|
|
155
|
+
internal, external = mapping.split('=', 2).map{ |p| p.strip }
|
|
156
|
+
path.sub(/^#{internal}/i, external)
|
|
140
157
|
end
|
|
158
|
+
end
|
|
141
159
|
end
|
|
142
160
|
end
|
data/lib/rack/server.rb
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
require 'optparse'
|
|
2
|
+
require 'fileutils'
|
|
3
|
+
|
|
2
4
|
|
|
3
5
|
module Rack
|
|
6
|
+
|
|
4
7
|
class Server
|
|
8
|
+
|
|
5
9
|
class Options
|
|
6
10
|
def parse!(args)
|
|
7
11
|
options = {}
|
|
@@ -17,16 +21,23 @@ module Rack
|
|
|
17
21
|
lineno += 1
|
|
18
22
|
}
|
|
19
23
|
|
|
24
|
+
opts.on("-b", "--builder BUILDER_LINE", "evaluate a BUILDER_LINE of code as a builder script") { |line|
|
|
25
|
+
options[:builder] = line
|
|
26
|
+
}
|
|
27
|
+
|
|
20
28
|
opts.on("-d", "--debug", "set debugging flags (set $DEBUG to true)") {
|
|
21
29
|
options[:debug] = true
|
|
22
30
|
}
|
|
23
31
|
opts.on("-w", "--warn", "turn warnings on for your script") {
|
|
24
32
|
options[:warn] = true
|
|
25
33
|
}
|
|
34
|
+
opts.on("-q", "--quiet", "turn off logging") {
|
|
35
|
+
options[:quiet] = true
|
|
36
|
+
}
|
|
26
37
|
|
|
27
38
|
opts.on("-I", "--include PATH",
|
|
28
39
|
"specify $LOAD_PATH (may be used more than once)") { |path|
|
|
29
|
-
options[:include]
|
|
40
|
+
(options[:include] ||= []).concat(path.split(":"))
|
|
30
41
|
}
|
|
31
42
|
|
|
32
43
|
opts.on("-r", "--require LIBRARY",
|
|
@@ -36,11 +47,11 @@ module Rack
|
|
|
36
47
|
|
|
37
48
|
opts.separator ""
|
|
38
49
|
opts.separator "Rack options:"
|
|
39
|
-
opts.on("-s", "--server SERVER", "serve using SERVER (webrick/mongrel)") { |s|
|
|
50
|
+
opts.on("-s", "--server SERVER", "serve using SERVER (thin/puma/webrick/mongrel)") { |s|
|
|
40
51
|
options[:server] = s
|
|
41
52
|
}
|
|
42
53
|
|
|
43
|
-
opts.on("-o", "--host HOST", "listen on HOST (default:
|
|
54
|
+
opts.on("-o", "--host HOST", "listen on HOST (default: localhost)") { |host|
|
|
44
55
|
options[:Host] = host
|
|
45
56
|
}
|
|
46
57
|
|
|
@@ -48,6 +59,12 @@ module Rack
|
|
|
48
59
|
options[:Port] = port
|
|
49
60
|
}
|
|
50
61
|
|
|
62
|
+
opts.on("-O", "--option NAME[=VALUE]", "pass VALUE to the server as option NAME. If no VALUE, sets it to true. Run '#{$0} -s SERVER -h' to get a list of options for SERVER") { |name|
|
|
63
|
+
name, value = name.split('=', 2)
|
|
64
|
+
value = true if value.nil?
|
|
65
|
+
options[name.to_sym] = value
|
|
66
|
+
}
|
|
67
|
+
|
|
51
68
|
opts.on("-E", "--env ENVIRONMENT", "use ENVIRONMENT for defaults (default: development)") { |e|
|
|
52
69
|
options[:environment] = e
|
|
53
70
|
}
|
|
@@ -56,37 +73,118 @@ module Rack
|
|
|
56
73
|
options[:daemonize] = d ? true : false
|
|
57
74
|
}
|
|
58
75
|
|
|
59
|
-
opts.on("-P", "--pid FILE", "file to store PID
|
|
60
|
-
options[:pid] = ::File.expand_path(f
|
|
76
|
+
opts.on("-P", "--pid FILE", "file to store PID") { |f|
|
|
77
|
+
options[:pid] = ::File.expand_path(f)
|
|
61
78
|
}
|
|
62
79
|
|
|
63
80
|
opts.separator ""
|
|
64
81
|
opts.separator "Common options:"
|
|
65
82
|
|
|
66
|
-
opts.on_tail("-h", "--help", "Show this message") do
|
|
83
|
+
opts.on_tail("-h", "-?", "--help", "Show this message") do
|
|
67
84
|
puts opts
|
|
85
|
+
puts handler_opts(options)
|
|
86
|
+
|
|
68
87
|
exit
|
|
69
88
|
end
|
|
70
89
|
|
|
71
90
|
opts.on_tail("--version", "Show version") do
|
|
72
|
-
puts "Rack #{Rack.version}"
|
|
91
|
+
puts "Rack #{Rack.version} (Release: #{Rack.release})"
|
|
73
92
|
exit
|
|
74
93
|
end
|
|
75
94
|
end
|
|
76
|
-
|
|
95
|
+
|
|
96
|
+
begin
|
|
97
|
+
opt_parser.parse! args
|
|
98
|
+
rescue OptionParser::InvalidOption => e
|
|
99
|
+
warn e.message
|
|
100
|
+
abort opt_parser.to_s
|
|
101
|
+
end
|
|
102
|
+
|
|
77
103
|
options[:config] = args.last if args.last
|
|
78
104
|
options
|
|
79
105
|
end
|
|
80
|
-
end
|
|
81
106
|
|
|
82
|
-
|
|
83
|
-
|
|
107
|
+
def handler_opts(options)
|
|
108
|
+
begin
|
|
109
|
+
info = []
|
|
110
|
+
server = Rack::Handler.get(options[:server]) || Rack::Handler.default(options)
|
|
111
|
+
if server && server.respond_to?(:valid_options)
|
|
112
|
+
info << ""
|
|
113
|
+
info << "Server-specific options for #{server.name}:"
|
|
114
|
+
|
|
115
|
+
has_options = false
|
|
116
|
+
server.valid_options.each do |name, description|
|
|
117
|
+
next if name.to_s.match(/^(Host|Port)[^a-zA-Z]/) # ignore handler's host and port options, we do our own.
|
|
118
|
+
info << " -O %-21s %s" % [name, description]
|
|
119
|
+
has_options = true
|
|
120
|
+
end
|
|
121
|
+
return "" if !has_options
|
|
122
|
+
end
|
|
123
|
+
info.join("\n")
|
|
124
|
+
rescue NameError
|
|
125
|
+
return "Warning: Could not find handler specified (#{options[:server] || 'default'}) to determine handler-specific options"
|
|
126
|
+
end
|
|
127
|
+
end
|
|
84
128
|
end
|
|
85
129
|
|
|
86
|
-
|
|
130
|
+
# Start a new rack server (like running rackup). This will parse ARGV and
|
|
131
|
+
# provide standard ARGV rackup options, defaulting to load 'config.ru'.
|
|
132
|
+
#
|
|
133
|
+
# Providing an options hash will prevent ARGV parsing and will not include
|
|
134
|
+
# any default options.
|
|
135
|
+
#
|
|
136
|
+
# This method can be used to very easily launch a CGI application, for
|
|
137
|
+
# example:
|
|
138
|
+
#
|
|
139
|
+
# Rack::Server.start(
|
|
140
|
+
# :app => lambda do |e|
|
|
141
|
+
# [200, {'Content-Type' => 'text/html'}, ['hello world']]
|
|
142
|
+
# end,
|
|
143
|
+
# :server => 'cgi'
|
|
144
|
+
# )
|
|
145
|
+
#
|
|
146
|
+
# Further options available here are documented on Rack::Server#initialize
|
|
147
|
+
def self.start(options = nil)
|
|
148
|
+
new(options).start
|
|
149
|
+
end
|
|
87
150
|
|
|
151
|
+
attr_writer :options
|
|
152
|
+
|
|
153
|
+
# Options may include:
|
|
154
|
+
# * :app
|
|
155
|
+
# a rack application to run (overrides :config)
|
|
156
|
+
# * :config
|
|
157
|
+
# a rackup configuration file path to load (.ru)
|
|
158
|
+
# * :environment
|
|
159
|
+
# this selects the middleware that will be wrapped around
|
|
160
|
+
# your application. Default options available are:
|
|
161
|
+
# - development: CommonLogger, ShowExceptions, and Lint
|
|
162
|
+
# - deployment: CommonLogger
|
|
163
|
+
# - none: no extra middleware
|
|
164
|
+
# note: when the server is a cgi server, CommonLogger is not included.
|
|
165
|
+
# * :server
|
|
166
|
+
# choose a specific Rack::Handler, e.g. cgi, fcgi, webrick
|
|
167
|
+
# * :daemonize
|
|
168
|
+
# if true, the server will daemonize itself (fork, detach, etc)
|
|
169
|
+
# * :pid
|
|
170
|
+
# path to write a pid file after daemonize
|
|
171
|
+
# * :Host
|
|
172
|
+
# the host address to bind to (used by supporting Rack::Handler)
|
|
173
|
+
# * :Port
|
|
174
|
+
# the port to bind to (used by supporting Rack::Handler)
|
|
175
|
+
# * :AccessLog
|
|
176
|
+
# webrick access log options (or supporting Rack::Handler)
|
|
177
|
+
# * :debug
|
|
178
|
+
# turn on debug output ($DEBUG = true)
|
|
179
|
+
# * :warn
|
|
180
|
+
# turn on warnings ($-w = true)
|
|
181
|
+
# * :include
|
|
182
|
+
# add given paths to $LOAD_PATH
|
|
183
|
+
# * :require
|
|
184
|
+
# require the given libraries
|
|
88
185
|
def initialize(options = nil)
|
|
89
186
|
@options = options
|
|
187
|
+
@app = options[:app] if options && options[:app]
|
|
90
188
|
end
|
|
91
189
|
|
|
92
190
|
def options
|
|
@@ -94,80 +192,130 @@ module Rack
|
|
|
94
192
|
end
|
|
95
193
|
|
|
96
194
|
def default_options
|
|
195
|
+
environment = ENV['RACK_ENV'] || 'development'
|
|
196
|
+
default_host = environment == 'development' ? 'localhost' : '0.0.0.0'
|
|
197
|
+
|
|
97
198
|
{
|
|
98
|
-
:environment =>
|
|
199
|
+
:environment => environment,
|
|
99
200
|
:pid => nil,
|
|
100
201
|
:Port => 9292,
|
|
101
|
-
:Host =>
|
|
202
|
+
:Host => default_host,
|
|
102
203
|
:AccessLog => [],
|
|
103
|
-
:config =>
|
|
204
|
+
:config => "config.ru"
|
|
104
205
|
}
|
|
105
206
|
end
|
|
106
207
|
|
|
107
208
|
def app
|
|
108
|
-
@app ||=
|
|
109
|
-
|
|
110
|
-
abort "configuration #{options[:config]} not found"
|
|
111
|
-
end
|
|
209
|
+
@app ||= options[:builder] ? build_app_from_string : build_app_and_options_from_config
|
|
210
|
+
end
|
|
112
211
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
212
|
+
class << self
|
|
213
|
+
def logging_middleware
|
|
214
|
+
lambda { |server|
|
|
215
|
+
server.server.name =~ /CGI/ || server.options[:quiet] ? nil : [Rack::CommonLogger, $stderr]
|
|
216
|
+
}
|
|
116
217
|
end
|
|
117
|
-
end
|
|
118
218
|
|
|
119
|
-
|
|
120
|
-
@middleware ||= begin
|
|
219
|
+
def default_middleware_by_environment
|
|
121
220
|
m = Hash.new {|h,k| h[k] = []}
|
|
122
|
-
m["deployment"]
|
|
123
|
-
|
|
221
|
+
m["deployment"] = [
|
|
222
|
+
[Rack::ContentLength],
|
|
223
|
+
[Rack::Chunked],
|
|
224
|
+
logging_middleware,
|
|
225
|
+
[Rack::TempfileReaper]
|
|
226
|
+
]
|
|
227
|
+
m["development"] = [
|
|
228
|
+
[Rack::ContentLength],
|
|
229
|
+
[Rack::Chunked],
|
|
230
|
+
logging_middleware,
|
|
231
|
+
[Rack::ShowExceptions],
|
|
232
|
+
[Rack::Lint],
|
|
233
|
+
[Rack::TempfileReaper]
|
|
234
|
+
]
|
|
235
|
+
|
|
124
236
|
m
|
|
125
237
|
end
|
|
238
|
+
|
|
239
|
+
def middleware
|
|
240
|
+
default_middleware_by_environment
|
|
241
|
+
end
|
|
126
242
|
end
|
|
127
243
|
|
|
128
244
|
def middleware
|
|
129
245
|
self.class.middleware
|
|
130
246
|
end
|
|
131
247
|
|
|
132
|
-
def start
|
|
133
|
-
if options[:debug]
|
|
134
|
-
$DEBUG = true
|
|
135
|
-
require 'pp'
|
|
136
|
-
p options[:server]
|
|
137
|
-
pp wrapped_app
|
|
138
|
-
pp app
|
|
139
|
-
end
|
|
140
|
-
|
|
248
|
+
def start &blk
|
|
141
249
|
if options[:warn]
|
|
142
250
|
$-w = true
|
|
143
251
|
end
|
|
144
252
|
|
|
145
253
|
if includes = options[:include]
|
|
146
|
-
$LOAD_PATH.unshift
|
|
254
|
+
$LOAD_PATH.unshift(*includes)
|
|
147
255
|
end
|
|
148
256
|
|
|
149
257
|
if library = options[:require]
|
|
150
258
|
require library
|
|
151
259
|
end
|
|
152
260
|
|
|
261
|
+
if options[:debug]
|
|
262
|
+
$DEBUG = true
|
|
263
|
+
require 'pp'
|
|
264
|
+
p options[:server]
|
|
265
|
+
pp wrapped_app
|
|
266
|
+
pp app
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
check_pid! if options[:pid]
|
|
270
|
+
|
|
271
|
+
# Touch the wrapped app, so that the config.ru is loaded before
|
|
272
|
+
# daemonization (i.e. before chdir, etc).
|
|
273
|
+
wrapped_app
|
|
274
|
+
|
|
153
275
|
daemonize_app if options[:daemonize]
|
|
276
|
+
|
|
154
277
|
write_pid if options[:pid]
|
|
155
|
-
|
|
278
|
+
|
|
279
|
+
trap(:INT) do
|
|
280
|
+
if server.respond_to?(:shutdown)
|
|
281
|
+
server.shutdown
|
|
282
|
+
else
|
|
283
|
+
exit
|
|
284
|
+
end
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
server.run wrapped_app, options, &blk
|
|
156
288
|
end
|
|
157
289
|
|
|
158
290
|
def server
|
|
159
|
-
@_server ||= Rack::Handler.get(options[:server]) || Rack::Handler.default
|
|
291
|
+
@_server ||= Rack::Handler.get(options[:server]) || Rack::Handler.default(options)
|
|
160
292
|
end
|
|
161
293
|
|
|
162
294
|
private
|
|
295
|
+
def build_app_and_options_from_config
|
|
296
|
+
if !::File.exist? options[:config]
|
|
297
|
+
abort "configuration #{options[:config]} not found"
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
app, options = Rack::Builder.parse_file(self.options[:config], opt_parser)
|
|
301
|
+
self.options.merge! options
|
|
302
|
+
app
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
def build_app_from_string
|
|
306
|
+
Rack::Builder.new_from_string(self.options[:builder])
|
|
307
|
+
end
|
|
308
|
+
|
|
163
309
|
def parse_options(args)
|
|
164
310
|
options = default_options
|
|
165
311
|
|
|
166
312
|
# Don't evaluate CGI ISINDEX parameters.
|
|
167
|
-
# http://
|
|
168
|
-
args.clear if ENV.include?(
|
|
313
|
+
# http://www.meb.uni-bonn.de/docs/cgi/cl.html
|
|
314
|
+
args.clear if ENV.include?(REQUEST_METHOD)
|
|
169
315
|
|
|
170
|
-
options.merge! opt_parser.parse!
|
|
316
|
+
options.merge! opt_parser.parse!(args)
|
|
317
|
+
options[:config] = ::File.expand_path(options[:config])
|
|
318
|
+
ENV["RACK_ENV"] = options[:environment]
|
|
171
319
|
options
|
|
172
320
|
end
|
|
173
321
|
|
|
@@ -179,8 +327,8 @@ module Rack
|
|
|
179
327
|
middleware[options[:environment]].reverse_each do |middleware|
|
|
180
328
|
middleware = middleware.call(self) if middleware.respond_to?(:call)
|
|
181
329
|
next unless middleware
|
|
182
|
-
klass = middleware
|
|
183
|
-
app = klass.new(app, *
|
|
330
|
+
klass, *args = middleware
|
|
331
|
+
app = klass.new(app, *args)
|
|
184
332
|
end
|
|
185
333
|
app
|
|
186
334
|
end
|
|
@@ -195,7 +343,6 @@ module Rack
|
|
|
195
343
|
Process.setsid
|
|
196
344
|
exit if fork
|
|
197
345
|
Dir.chdir "/"
|
|
198
|
-
::File.umask 0000
|
|
199
346
|
STDIN.reopen "/dev/null"
|
|
200
347
|
STDOUT.reopen "/dev/null", "a"
|
|
201
348
|
STDERR.reopen "/dev/null", "a"
|
|
@@ -205,8 +352,37 @@ module Rack
|
|
|
205
352
|
end
|
|
206
353
|
|
|
207
354
|
def write_pid
|
|
208
|
-
::File.open(options[:pid],
|
|
209
|
-
at_exit { ::
|
|
355
|
+
::File.open(options[:pid], ::File::CREAT | ::File::EXCL | ::File::WRONLY ){ |f| f.write("#{Process.pid}") }
|
|
356
|
+
at_exit { ::FileUtils.rm_f(options[:pid]) }
|
|
357
|
+
rescue Errno::EEXIST
|
|
358
|
+
check_pid!
|
|
359
|
+
retry
|
|
210
360
|
end
|
|
361
|
+
|
|
362
|
+
def check_pid!
|
|
363
|
+
case pidfile_process_status
|
|
364
|
+
when :running, :not_owned
|
|
365
|
+
$stderr.puts "A server is already running. Check #{options[:pid]}."
|
|
366
|
+
exit(1)
|
|
367
|
+
when :dead
|
|
368
|
+
::File.delete(options[:pid])
|
|
369
|
+
end
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
def pidfile_process_status
|
|
373
|
+
return :exited unless ::File.exist?(options[:pid])
|
|
374
|
+
|
|
375
|
+
pid = ::File.read(options[:pid]).to_i
|
|
376
|
+
return :dead if pid == 0
|
|
377
|
+
|
|
378
|
+
Process.kill(0, pid)
|
|
379
|
+
:running
|
|
380
|
+
rescue Errno::ESRCH
|
|
381
|
+
:dead
|
|
382
|
+
rescue Errno::EPERM
|
|
383
|
+
:not_owned
|
|
384
|
+
end
|
|
385
|
+
|
|
211
386
|
end
|
|
387
|
+
|
|
212
388
|
end
|