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/lib/rack/server.rb
CHANGED
@@ -1,7 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'optparse'
|
4
|
+
require 'fileutils'
|
5
|
+
|
6
|
+
require_relative 'core_ext/regexp'
|
2
7
|
|
3
8
|
module Rack
|
9
|
+
|
4
10
|
class Server
|
11
|
+
using ::Rack::RegexpExtensions
|
12
|
+
|
5
13
|
class Options
|
6
14
|
def parse!(args)
|
7
15
|
options = {}
|
@@ -23,6 +31,9 @@ module Rack
|
|
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|
|
@@ -36,11 +47,15 @@ module Rack
|
|
36
47
|
|
37
48
|
opts.separator ""
|
38
49
|
opts.separator "Rack options:"
|
39
|
-
opts.on("-
|
50
|
+
opts.on("-b", "--builder BUILDER_LINE", "evaluate a BUILDER_LINE of code as a builder script") { |line|
|
51
|
+
options[:builder] = line
|
52
|
+
}
|
53
|
+
|
54
|
+
opts.on("-s", "--server SERVER", "serve using SERVER (thin/puma/webrick)") { |s|
|
40
55
|
options[:server] = s
|
41
56
|
}
|
42
57
|
|
43
|
-
opts.on("-o", "--host HOST", "listen on HOST (default:
|
58
|
+
opts.on("-o", "--host HOST", "listen on HOST (default: localhost)") { |host|
|
44
59
|
options[:Host] = host
|
45
60
|
}
|
46
61
|
|
@@ -62,10 +77,28 @@ module Rack
|
|
62
77
|
options[:daemonize] = d ? true : false
|
63
78
|
}
|
64
79
|
|
65
|
-
opts.on("-P", "--pid FILE", "file to store PID
|
80
|
+
opts.on("-P", "--pid FILE", "file to store PID") { |f|
|
66
81
|
options[:pid] = ::File.expand_path(f)
|
67
82
|
}
|
68
83
|
|
84
|
+
opts.separator ""
|
85
|
+
opts.separator "Profiling options:"
|
86
|
+
|
87
|
+
opts.on("--heap HEAPFILE", "Build the application, then dump the heap to HEAPFILE") do |e|
|
88
|
+
options[:heapfile] = e
|
89
|
+
end
|
90
|
+
|
91
|
+
opts.on("--profile PROFILE", "Dump CPU or Memory profile to PROFILE (defaults to a tempfile)") do |e|
|
92
|
+
options[:profile_file] = e
|
93
|
+
end
|
94
|
+
|
95
|
+
opts.on("--profile-mode MODE", "Profile mode (cpu|wall|object)") do |e|
|
96
|
+
{ cpu: true, wall: true, object: true }.fetch(e.to_sym) do
|
97
|
+
raise OptionParser::InvalidOption, "unknown profile mode: #{e}"
|
98
|
+
end
|
99
|
+
options[:profile_mode] = e.to_sym
|
100
|
+
end
|
101
|
+
|
69
102
|
opts.separator ""
|
70
103
|
opts.separator "Common options:"
|
71
104
|
|
@@ -89,21 +122,21 @@ module Rack
|
|
89
122
|
abort opt_parser.to_s
|
90
123
|
end
|
91
124
|
|
92
|
-
options[:config] = args.last if args.last
|
125
|
+
options[:config] = args.last if args.last && !args.last.empty?
|
93
126
|
options
|
94
127
|
end
|
95
128
|
|
96
129
|
def handler_opts(options)
|
97
130
|
begin
|
98
131
|
info = []
|
99
|
-
server = Rack::Handler.get(options[:server]) || Rack::Handler.default
|
132
|
+
server = Rack::Handler.get(options[:server]) || Rack::Handler.default
|
100
133
|
if server && server.respond_to?(:valid_options)
|
101
134
|
info << ""
|
102
135
|
info << "Server-specific options for #{server.name}:"
|
103
136
|
|
104
137
|
has_options = false
|
105
138
|
server.valid_options.each do |name, description|
|
106
|
-
next if
|
139
|
+
next if /^(Host|Port)[^a-zA-Z]/.match?(name.to_s) # ignore handler's host and port options, we do our own.
|
107
140
|
info << " -O %-21s %s" % [name, description]
|
108
141
|
has_options = true
|
109
142
|
end
|
@@ -141,7 +174,9 @@ module Rack
|
|
141
174
|
|
142
175
|
# Options may include:
|
143
176
|
# * :app
|
144
|
-
# a rack application to run (overrides :config)
|
177
|
+
# a rack application to run (overrides :config and :builder)
|
178
|
+
# * :builder
|
179
|
+
# a string to evaluate a Rack::Builder from
|
145
180
|
# * :config
|
146
181
|
# a rackup configuration file path to load (.ru)
|
147
182
|
# * :environment
|
@@ -162,7 +197,7 @@ module Rack
|
|
162
197
|
# * :Port
|
163
198
|
# the port to bind to (used by supporting Rack::Handler)
|
164
199
|
# * :AccessLog
|
165
|
-
# webrick
|
200
|
+
# webrick access log options (or supporting Rack::Handler)
|
166
201
|
# * :debug
|
167
202
|
# turn on debug output ($DEBUG = true)
|
168
203
|
# * :warn
|
@@ -171,55 +206,79 @@ module Rack
|
|
171
206
|
# add given paths to $LOAD_PATH
|
172
207
|
# * :require
|
173
208
|
# require the given libraries
|
209
|
+
#
|
210
|
+
# Additional options for profiling app initialization include:
|
211
|
+
# * :heapfile
|
212
|
+
# location for ObjectSpace.dump_all to write the output to
|
213
|
+
# * :profile_file
|
214
|
+
# location for CPU/Memory (StackProf) profile output (defaults to a tempfile)
|
215
|
+
# * :profile_mode
|
216
|
+
# StackProf profile mode (cpu|wall|object)
|
174
217
|
def initialize(options = nil)
|
175
|
-
@
|
176
|
-
|
218
|
+
@ignore_options = []
|
219
|
+
|
220
|
+
if options
|
221
|
+
@use_default_options = false
|
222
|
+
@options = options
|
223
|
+
@app = options[:app] if options[:app]
|
224
|
+
else
|
225
|
+
argv = defined?(SPEC_ARGV) ? SPEC_ARGV : ARGV
|
226
|
+
@use_default_options = true
|
227
|
+
@options = parse_options(argv)
|
228
|
+
end
|
177
229
|
end
|
178
230
|
|
179
231
|
def options
|
180
|
-
@
|
232
|
+
merged_options = @use_default_options ? default_options.merge(@options) : @options
|
233
|
+
merged_options.reject { |k, v| @ignore_options.include?(k) }
|
181
234
|
end
|
182
235
|
|
183
236
|
def default_options
|
237
|
+
environment = ENV['RACK_ENV'] || 'development'
|
238
|
+
default_host = environment == 'development' ? 'localhost' : '0.0.0.0'
|
239
|
+
|
184
240
|
{
|
185
|
-
:environment
|
186
|
-
:
|
187
|
-
:
|
188
|
-
:
|
189
|
-
:
|
190
|
-
:
|
241
|
+
environment: environment,
|
242
|
+
pid: nil,
|
243
|
+
Port: 9292,
|
244
|
+
Host: default_host,
|
245
|
+
AccessLog: [],
|
246
|
+
config: "config.ru"
|
191
247
|
}
|
192
248
|
end
|
193
249
|
|
194
250
|
def app
|
195
|
-
@app ||=
|
196
|
-
if !::File.exist? options[:config]
|
197
|
-
abort "configuration #{options[:config]} not found"
|
198
|
-
end
|
199
|
-
|
200
|
-
app, options = Rack::Builder.parse_file(self.options[:config], opt_parser)
|
201
|
-
self.options.merge! options
|
202
|
-
app
|
203
|
-
end
|
251
|
+
@app ||= options[:builder] ? build_app_from_string : build_app_and_options_from_config
|
204
252
|
end
|
205
253
|
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
254
|
+
class << self
|
255
|
+
def logging_middleware
|
256
|
+
lambda { |server|
|
257
|
+
/CGI/.match?(server.server.name) || server.options[:quiet] ? nil : [Rack::CommonLogger, $stderr]
|
258
|
+
}
|
259
|
+
end
|
211
260
|
|
212
|
-
|
213
|
-
|
214
|
-
m
|
215
|
-
|
261
|
+
def default_middleware_by_environment
|
262
|
+
m = Hash.new {|h, k| h[k] = []}
|
263
|
+
m["deployment"] = [
|
264
|
+
[Rack::ContentLength],
|
265
|
+
logging_middleware,
|
266
|
+
[Rack::TempfileReaper]
|
267
|
+
]
|
268
|
+
m["development"] = [
|
216
269
|
[Rack::ContentLength],
|
217
|
-
|
218
|
-
|
270
|
+
logging_middleware,
|
271
|
+
[Rack::ShowExceptions],
|
272
|
+
[Rack::Lint],
|
273
|
+
[Rack::TempfileReaper]
|
219
274
|
]
|
220
|
-
|
275
|
+
|
221
276
|
m
|
222
277
|
end
|
278
|
+
|
279
|
+
def middleware
|
280
|
+
default_middleware_by_environment
|
281
|
+
end
|
223
282
|
end
|
224
283
|
|
225
284
|
def middleware
|
@@ -251,7 +310,9 @@ module Rack
|
|
251
310
|
|
252
311
|
# Touch the wrapped app, so that the config.ru is loaded before
|
253
312
|
# daemonization (i.e. before chdir, etc).
|
254
|
-
|
313
|
+
handle_profiling(options[:heapfile], options[:profile_mode], options[:profile_file]) do
|
314
|
+
wrapped_app
|
315
|
+
end
|
255
316
|
|
256
317
|
daemonize_app if options[:daemonize]
|
257
318
|
|
@@ -269,21 +330,80 @@ module Rack
|
|
269
330
|
end
|
270
331
|
|
271
332
|
def server
|
272
|
-
@_server ||= Rack::Handler.get(options[:server])
|
333
|
+
@_server ||= Rack::Handler.get(options[:server])
|
334
|
+
|
335
|
+
unless @_server
|
336
|
+
@_server = Rack::Handler.default
|
337
|
+
|
338
|
+
# We already speak FastCGI
|
339
|
+
@ignore_options = [:File, :Port] if @_server.to_s == 'Rack::Handler::FastCGI'
|
340
|
+
end
|
341
|
+
|
342
|
+
@_server
|
273
343
|
end
|
274
344
|
|
275
345
|
private
|
276
|
-
def
|
277
|
-
|
346
|
+
def build_app_and_options_from_config
|
347
|
+
if !::File.exist? options[:config]
|
348
|
+
abort "configuration #{options[:config]} not found"
|
349
|
+
end
|
350
|
+
|
351
|
+
app, options = Rack::Builder.parse_file(self.options[:config], opt_parser)
|
352
|
+
@options.merge!(options) { |key, old, new| old }
|
353
|
+
app
|
354
|
+
end
|
278
355
|
|
356
|
+
def handle_profiling(heapfile, profile_mode, filename)
|
357
|
+
if heapfile
|
358
|
+
require "objspace"
|
359
|
+
ObjectSpace.trace_object_allocations_start
|
360
|
+
yield
|
361
|
+
GC.start
|
362
|
+
::File.open(heapfile, "w") { |f| ObjectSpace.dump_all(output: f) }
|
363
|
+
exit
|
364
|
+
end
|
365
|
+
|
366
|
+
if profile_mode
|
367
|
+
require "stackprof"
|
368
|
+
require "tempfile"
|
369
|
+
|
370
|
+
make_profile_name(filename) do |filename|
|
371
|
+
::File.open(filename, "w") do |f|
|
372
|
+
StackProf.run(mode: profile_mode, out: f) do
|
373
|
+
yield
|
374
|
+
end
|
375
|
+
puts "Profile written to: #{filename}"
|
376
|
+
end
|
377
|
+
end
|
378
|
+
exit
|
379
|
+
end
|
380
|
+
|
381
|
+
yield
|
382
|
+
end
|
383
|
+
|
384
|
+
def make_profile_name(filename)
|
385
|
+
if filename
|
386
|
+
yield filename
|
387
|
+
else
|
388
|
+
::Dir::Tmpname.create("profile.dump") do |tmpname, _, _|
|
389
|
+
yield tmpname
|
390
|
+
end
|
391
|
+
end
|
392
|
+
end
|
393
|
+
|
394
|
+
def build_app_from_string
|
395
|
+
Rack::Builder.new_from_string(self.options[:builder])
|
396
|
+
end
|
397
|
+
|
398
|
+
def parse_options(args)
|
279
399
|
# Don't evaluate CGI ISINDEX parameters.
|
280
400
|
# http://www.meb.uni-bonn.de/docs/cgi/cl.html
|
281
|
-
args.clear if ENV.include?(
|
401
|
+
args.clear if ENV.include?(REQUEST_METHOD)
|
282
402
|
|
283
|
-
options
|
284
|
-
options[:config] = ::File.expand_path(options[:config])
|
403
|
+
@options = opt_parser.parse!(args)
|
404
|
+
@options[:config] = ::File.expand_path(options[:config])
|
285
405
|
ENV["RACK_ENV"] = options[:environment]
|
286
|
-
options
|
406
|
+
@options
|
287
407
|
end
|
288
408
|
|
289
409
|
def opt_parser
|
@@ -294,8 +414,8 @@ module Rack
|
|
294
414
|
middleware[options[:environment]].reverse_each do |middleware|
|
295
415
|
middleware = middleware.call(self) if middleware.respond_to?(:call)
|
296
416
|
next unless middleware
|
297
|
-
klass = middleware
|
298
|
-
app = klass.new(app, *
|
417
|
+
klass, *args = middleware
|
418
|
+
app = klass.new(app, *args)
|
299
419
|
end
|
300
420
|
app
|
301
421
|
end
|
@@ -305,22 +425,15 @@ module Rack
|
|
305
425
|
end
|
306
426
|
|
307
427
|
def daemonize_app
|
308
|
-
|
309
|
-
exit if fork
|
310
|
-
Process.setsid
|
311
|
-
exit if fork
|
312
|
-
Dir.chdir "/"
|
313
|
-
STDIN.reopen "/dev/null"
|
314
|
-
STDOUT.reopen "/dev/null", "a"
|
315
|
-
STDERR.reopen "/dev/null", "a"
|
316
|
-
else
|
317
|
-
Process.daemon
|
318
|
-
end
|
428
|
+
Process.daemon
|
319
429
|
end
|
320
430
|
|
321
431
|
def write_pid
|
322
|
-
::File.open(options[:pid],
|
323
|
-
at_exit { ::
|
432
|
+
::File.open(options[:pid], ::File::CREAT | ::File::EXCL | ::File::WRONLY ){ |f| f.write("#{Process.pid}") }
|
433
|
+
at_exit { ::FileUtils.rm_f(options[:pid]) }
|
434
|
+
rescue Errno::EEXIST
|
435
|
+
check_pid!
|
436
|
+
retry
|
324
437
|
end
|
325
438
|
|
326
439
|
def check_pid!
|
@@ -348,4 +461,5 @@ module Rack
|
|
348
461
|
end
|
349
462
|
|
350
463
|
end
|
464
|
+
|
351
465
|
end
|