unicorn 4.6.3 → 4.7.0
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.
- data/GIT-VERSION-GEN +1 -1
- data/GNUmakefile +0 -1
- data/LICENSE +10 -7
- data/README +3 -2
- data/Rakefile +0 -37
- data/Sandbox +7 -0
- data/bin/unicorn +3 -3
- data/bin/unicorn_rails +3 -3
- data/ext/unicorn_http/unicorn_http.rl +1 -1
- data/lib/unicorn/app/inetd.rb +1 -1
- data/lib/unicorn/app/old_rails.rb +1 -1
- data/lib/unicorn/cgi_wrapper.rb +1 -1
- data/lib/unicorn/configurator.rb +20 -1
- data/lib/unicorn/http_server.rb +49 -21
- data/lib/unicorn/socket_helper.rb +32 -9
- data/lib/unicorn/util.rb +22 -2
- data/script/isolate_for_tests +3 -3
- data/t/oob_gc.ru +1 -2
- data/t/oob_gc_path.ru +1 -2
- data/test/test_helper.rb +1 -1
- data/test/unit/test_http_parser.rb +1 -1
- data/test/unit/test_request.rb +1 -1
- data/test/unit/test_response.rb +1 -1
- data/test/unit/test_server.rb +1 -1
- data/test/unit/test_signals.rb +1 -1
- data/test/unit/test_socket_helper.rb +8 -0
- data/test/unit/test_util.rb +8 -2
- data/unicorn.gemspec +1 -1
- metadata +3 -5
data/GIT-VERSION-GEN
CHANGED
data/GNUmakefile
CHANGED
|
@@ -256,7 +256,6 @@ release: verify package $(release_notes) $(release_changes)
|
|
|
256
256
|
# in case of gem downloads from RubyForge releases page
|
|
257
257
|
-rubyforge add_file \
|
|
258
258
|
$(rfproject) $(rfpackage) $(VERSION) $(pkggem)
|
|
259
|
-
$(RAKE) raa_update VERSION=$(VERSION)
|
|
260
259
|
$(RAKE) fm_update VERSION=$(VERSION)
|
|
261
260
|
else
|
|
262
261
|
gem install-gem: GIT-VERSION-FILE
|
data/LICENSE
CHANGED
|
@@ -3,15 +3,18 @@ revision control for names and email addresses of all of them.
|
|
|
3
3
|
|
|
4
4
|
You can redistribute it and/or modify it under either the terms of the
|
|
5
5
|
GNU General Public License (GPL) as published by the Free Software
|
|
6
|
-
Foundation (FSF), version
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
Foundation (FSF), either version 2 of the License, or (at your option)
|
|
7
|
+
any later version. We currently prefer the GPLv3 or later for
|
|
8
|
+
derivative works, but the GPLv2 is fine.
|
|
9
9
|
|
|
10
|
-
The
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
The complete texts of the GPLv2 and GPLv3 are below:
|
|
11
|
+
GPLv2 - http://www.gnu.org/licenses/gpl-2.0.txt
|
|
12
|
+
GPLv3 - http://www.gnu.org/licenses/gpl-3.0.txt
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
You may (against our _preference_) also use the Ruby 1.8 license terms
|
|
15
|
+
which we inherited from the original Mongrel project when we forked it:
|
|
16
|
+
|
|
17
|
+
=== Ruby 1.8-specific terms (if you're not using the GPL)
|
|
15
18
|
|
|
16
19
|
1. You may make and give away verbatim copies of the source form of the
|
|
17
20
|
software without restriction, provided that you duplicate all of the
|
data/README
CHANGED
|
@@ -63,8 +63,9 @@ both the the request and response in between \Unicorn and slow clients.
|
|
|
63
63
|
It is based on Mongrel 1.1.5.
|
|
64
64
|
Mongrel is copyright 2007 Zed A. Shaw and contributors.
|
|
65
65
|
|
|
66
|
-
\Unicorn is
|
|
67
|
-
Ruby (1.8)-specific terms.
|
|
66
|
+
\Unicorn is licensed under (your choice) of the GPLv2 or later
|
|
67
|
+
(GPLv3+ preferred), or Ruby (1.8)-specific terms.
|
|
68
|
+
See the included LICENSE file for details.
|
|
68
69
|
|
|
69
70
|
\Unicorn is 100% Free Software.
|
|
70
71
|
|
data/Rakefile
CHANGED
|
@@ -5,43 +5,6 @@ require 'wrongdoc'
|
|
|
5
5
|
cgit_url = Wrongdoc.config[:cgit_url]
|
|
6
6
|
git_url = Wrongdoc.config[:git_url]
|
|
7
7
|
|
|
8
|
-
desc "post to RAA"
|
|
9
|
-
task :raa_update do
|
|
10
|
-
require 'net/http'
|
|
11
|
-
require 'net/netrc'
|
|
12
|
-
rc = Net::Netrc.locate('unicorn-raa') or abort "~/.netrc not found"
|
|
13
|
-
password = rc.password
|
|
14
|
-
|
|
15
|
-
s = Gem::Specification.load('unicorn.gemspec')
|
|
16
|
-
desc = [ s.description.strip ]
|
|
17
|
-
desc << ""
|
|
18
|
-
desc << "* #{s.email}"
|
|
19
|
-
desc << "* #{git_url}"
|
|
20
|
-
desc << "* #{cgit_url}"
|
|
21
|
-
desc = desc.join("\n")
|
|
22
|
-
uri = URI.parse('http://raa.ruby-lang.org/regist.rhtml')
|
|
23
|
-
form = {
|
|
24
|
-
:name => s.name,
|
|
25
|
-
:short_description => s.summary,
|
|
26
|
-
:version => s.version.to_s,
|
|
27
|
-
:status => 'stable',
|
|
28
|
-
:owner => s.authors.first,
|
|
29
|
-
:email => s.email,
|
|
30
|
-
:category_major => 'Library',
|
|
31
|
-
:category_minor => 'Web',
|
|
32
|
-
:url => s.homepage,
|
|
33
|
-
:download => "http://rubyforge.org/frs/?group_id=1306",
|
|
34
|
-
:license => "Ruby's",
|
|
35
|
-
:description_style => 'Plain',
|
|
36
|
-
:description => desc,
|
|
37
|
-
:pass => password,
|
|
38
|
-
:submit => "Update",
|
|
39
|
-
}
|
|
40
|
-
res = Net::HTTP.post_form(uri, form)
|
|
41
|
-
p res
|
|
42
|
-
puts res.body
|
|
43
|
-
end
|
|
44
|
-
|
|
45
8
|
desc "post to FM"
|
|
46
9
|
task :fm_update do
|
|
47
10
|
require 'tempfile'
|
data/Sandbox
CHANGED
|
@@ -60,6 +60,13 @@ If you're using an older Bundler version (0.9.x), you may need to set or
|
|
|
60
60
|
reset GEM_HOME, GEM_PATH and PATH environment variables in the
|
|
61
61
|
before_exec hook as illustrated by http://gist.github.com/534668
|
|
62
62
|
|
|
63
|
+
=== Ruby 2.0.0 close-on-exec and SIGUSR2 incompatibility
|
|
64
|
+
|
|
65
|
+
Ruby 2.0.0 enforces FD_CLOEXEC on file descriptors by default. unicorn
|
|
66
|
+
has been prepared for this behavior since unicorn 4.1.0, but we forgot
|
|
67
|
+
to remind the Bundler developers. This issue is being tracked here:
|
|
68
|
+
https://github.com/bundler/bundler/issues/2628
|
|
69
|
+
|
|
63
70
|
== Isolate
|
|
64
71
|
|
|
65
72
|
=== Running
|
data/bin/unicorn
CHANGED
|
@@ -47,9 +47,9 @@ op = OptionParser.new("", 24, ' ') do |opts|
|
|
|
47
47
|
rackup_opts[:set_listener] = true
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
-
opts.on("-p", "--port PORT",
|
|
51
|
-
"use PORT (default: #{Unicorn::Const::DEFAULT_PORT})") do |
|
|
52
|
-
rackup_opts[:port] =
|
|
50
|
+
opts.on("-p", "--port PORT", Integer,
|
|
51
|
+
"use PORT (default: #{Unicorn::Const::DEFAULT_PORT})") do |port|
|
|
52
|
+
rackup_opts[:port] = port
|
|
53
53
|
rackup_opts[:set_listener] = true
|
|
54
54
|
end
|
|
55
55
|
|
data/bin/unicorn_rails
CHANGED
|
@@ -48,9 +48,9 @@ op = OptionParser.new("", 24, ' ') do |opts|
|
|
|
48
48
|
rackup_opts[:set_listener] = true
|
|
49
49
|
end
|
|
50
50
|
|
|
51
|
-
opts.on("-p", "--port PORT",
|
|
52
|
-
"use PORT (default: #{Unicorn::Const::DEFAULT_PORT})") do |
|
|
53
|
-
rackup_opts[:port] =
|
|
51
|
+
opts.on("-p", "--port PORT", Integer,
|
|
52
|
+
"use PORT (default: #{Unicorn::Const::DEFAULT_PORT})") do |port|
|
|
53
|
+
rackup_opts[:port] = port
|
|
54
54
|
rackup_opts[:set_listener] = true
|
|
55
55
|
end
|
|
56
56
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Copyright (c) 2009 Eric Wong (all bugs are Eric's fault)
|
|
3
3
|
* Copyright (c) 2005 Zed A. Shaw
|
|
4
4
|
* You can redistribute it and/or modify it under the same terms as Ruby 1.8 or
|
|
5
|
-
* the GPLv3
|
|
5
|
+
* the GPLv2+ (GPLv3+ preferred)
|
|
6
6
|
*/
|
|
7
7
|
#include "ruby.h"
|
|
8
8
|
#include "ext_help.h"
|
data/lib/unicorn/app/inetd.rb
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
# Copyright (c) 2005 Zed A. Shaw
|
|
6
6
|
# Copyright (c) 2009 Eric Wong
|
|
7
7
|
# You can redistribute it and/or modify it under the same terms as Ruby 1.8 or
|
|
8
|
-
# the GPLv3
|
|
8
|
+
# the GPLv2+ (GPLv3+ preferred)
|
|
9
9
|
# Additional work donated by contributors. See CONTRIBUTORS for more info.
|
|
10
10
|
require 'unicorn/cgi_wrapper'
|
|
11
11
|
require 'dispatcher'
|
data/lib/unicorn/cgi_wrapper.rb
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
# Copyright (c) 2005 Zed A. Shaw
|
|
6
6
|
# Copyright (c) 2009 Eric Wong
|
|
7
7
|
# You can redistribute it and/or modify it under the same terms as Ruby 1.8 or
|
|
8
|
-
# the GPLv3
|
|
8
|
+
# the GPLv2+ (GPLv3+ preferred)
|
|
9
9
|
#
|
|
10
10
|
# Additional work donated by contributors. See CONTRIBUTORS for more info.
|
|
11
11
|
|
data/lib/unicorn/configurator.rb
CHANGED
|
@@ -319,6 +319,25 @@ class Unicorn::Configurator
|
|
|
319
319
|
#
|
|
320
320
|
# Default: Operating-system dependent
|
|
321
321
|
#
|
|
322
|
+
# [:reuseport => true or false]
|
|
323
|
+
#
|
|
324
|
+
# This enables multiple, independently-started unicorn instances to
|
|
325
|
+
# bind to the same port (as long as all the processes enable this).
|
|
326
|
+
#
|
|
327
|
+
# This option must be used when unicorn first binds the listen socket.
|
|
328
|
+
# It cannot be enabled when a socket is inherited via SIGUSR2
|
|
329
|
+
# (but it will remain on if inherited), and it cannot be enabled
|
|
330
|
+
# directly via SIGHUP.
|
|
331
|
+
#
|
|
332
|
+
# Note: there is a chance of connections being dropped if
|
|
333
|
+
# one of the unicorn instances is stopped while using this.
|
|
334
|
+
#
|
|
335
|
+
# This is supported on *BSD systems and Linux 3.9 or later.
|
|
336
|
+
#
|
|
337
|
+
# ref: https://lwn.net/Articles/542629/
|
|
338
|
+
#
|
|
339
|
+
# Default: false (unset)
|
|
340
|
+
#
|
|
322
341
|
# [:tries => Integer]
|
|
323
342
|
#
|
|
324
343
|
# Times to retry binding a socket if it is already in use
|
|
@@ -396,7 +415,7 @@ class Unicorn::Configurator
|
|
|
396
415
|
Integer === value or
|
|
397
416
|
raise ArgumentError, "not an integer: #{key}=#{value.inspect}"
|
|
398
417
|
end
|
|
399
|
-
[ :tcp_nodelay, :tcp_nopush, :ipv6only ].each do |key|
|
|
418
|
+
[ :tcp_nodelay, :tcp_nopush, :ipv6only, :reuseport ].each do |key|
|
|
400
419
|
(value = options[key]).nil? and next
|
|
401
420
|
TrueClass === value || FalseClass === value or
|
|
402
421
|
raise ArgumentError, "not boolean: #{key}=#{value.inspect}"
|
data/lib/unicorn/http_server.rb
CHANGED
|
@@ -134,11 +134,22 @@ class Unicorn::HttpServer
|
|
|
134
134
|
# Note that signals don't actually get handled until the #join method
|
|
135
135
|
QUEUE_SIGS.each { |sig| trap(sig) { SIG_QUEUE << sig; awaken_master } }
|
|
136
136
|
trap(:CHLD) { awaken_master }
|
|
137
|
-
|
|
137
|
+
|
|
138
|
+
# write pid early for Mongrel compatibility if we're not inheriting sockets
|
|
139
|
+
# This was needed for compatibility with some health checker a long time
|
|
140
|
+
# ago. This unfortunately has the side effect of clobbering valid PID
|
|
141
|
+
# files.
|
|
142
|
+
self.pid = config[:pid] unless ENV["UNICORN_FD"]
|
|
138
143
|
|
|
139
144
|
self.master_pid = $$
|
|
140
145
|
build_app! if preload_app
|
|
141
146
|
bind_new_listeners!
|
|
147
|
+
|
|
148
|
+
# Assuming preload_app==false, we drop the pid file after the app is ready
|
|
149
|
+
# to process requests. If binding or build_app! fails with
|
|
150
|
+
# preload_app==true, we'll never get here and the parent will recover
|
|
151
|
+
self.pid = config[:pid] if ENV["UNICORN_FD"]
|
|
152
|
+
|
|
142
153
|
spawn_missing_workers
|
|
143
154
|
self
|
|
144
155
|
end
|
|
@@ -180,6 +191,21 @@ class Unicorn::HttpServer
|
|
|
180
191
|
Unicorn::HttpRequest::DEFAULTS["rack.logger"] = @logger = obj
|
|
181
192
|
end
|
|
182
193
|
|
|
194
|
+
def clobber_pid(path)
|
|
195
|
+
unlink_pid_safe(@pid) if @pid
|
|
196
|
+
if path
|
|
197
|
+
fp = begin
|
|
198
|
+
tmp = "#{File.dirname(path)}/#{rand}.#$$"
|
|
199
|
+
File.open(tmp, File::RDWR|File::CREAT|File::EXCL, 0644)
|
|
200
|
+
rescue Errno::EEXIST
|
|
201
|
+
retry
|
|
202
|
+
end
|
|
203
|
+
fp.syswrite("#$$\n")
|
|
204
|
+
File.rename(fp.path, path)
|
|
205
|
+
fp.close
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
|
|
183
209
|
# sets the path for the PID file of the master process
|
|
184
210
|
def pid=(path)
|
|
185
211
|
if path
|
|
@@ -194,18 +220,18 @@ class Unicorn::HttpServer
|
|
|
194
220
|
"(or pid=#{path} is stale)"
|
|
195
221
|
end
|
|
196
222
|
end
|
|
197
|
-
unlink_pid_safe(pid) if pid
|
|
198
223
|
|
|
199
|
-
if
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
File.
|
|
203
|
-
rescue Errno::
|
|
204
|
-
|
|
224
|
+
# rename the old pid if possible
|
|
225
|
+
if @pid && path
|
|
226
|
+
begin
|
|
227
|
+
File.rename(@pid, path)
|
|
228
|
+
rescue Errno::ENOENT, Errno::EXDEV
|
|
229
|
+
# a user may have accidentally removed the original,
|
|
230
|
+
# obviously cross-FS renames don't work, either.
|
|
231
|
+
clobber_pid(path)
|
|
205
232
|
end
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
fp.close
|
|
233
|
+
else
|
|
234
|
+
clobber_pid(path)
|
|
209
235
|
end
|
|
210
236
|
@pid = path
|
|
211
237
|
end
|
|
@@ -228,7 +254,7 @@ class Unicorn::HttpServer
|
|
|
228
254
|
begin
|
|
229
255
|
io = bind_listen(address, opt)
|
|
230
256
|
unless Kgio::TCPServer === io || Kgio::UNIXServer === io
|
|
231
|
-
|
|
257
|
+
prevent_autoclose(io)
|
|
232
258
|
io = server_cast(io)
|
|
233
259
|
end
|
|
234
260
|
logger.info "listening on addr=#{sock_name(io)} fd=#{io.fileno}"
|
|
@@ -423,13 +449,14 @@ class Unicorn::HttpServer
|
|
|
423
449
|
end
|
|
424
450
|
|
|
425
451
|
self.reexec_pid = fork do
|
|
426
|
-
listener_fds =
|
|
452
|
+
listener_fds = {}
|
|
453
|
+
LISTENERS.each do |sock|
|
|
427
454
|
# IO#close_on_exec= will be available on any future version of
|
|
428
455
|
# Ruby that sets FD_CLOEXEC by default on new file descriptors
|
|
429
456
|
# ref: http://redmine.ruby-lang.org/issues/5041
|
|
430
457
|
sock.close_on_exec = false if sock.respond_to?(:close_on_exec=)
|
|
431
|
-
[
|
|
432
|
-
end
|
|
458
|
+
listener_fds[sock.fileno] = sock
|
|
459
|
+
end
|
|
433
460
|
ENV['UNICORN_FD'] = listener_fds.keys.join(',')
|
|
434
461
|
Dir.chdir(START_CTX[:cwd])
|
|
435
462
|
cmd = [ START_CTX[0] ].concat(START_CTX[:argv])
|
|
@@ -440,7 +467,7 @@ class Unicorn::HttpServer
|
|
|
440
467
|
(3..1024).each do |io|
|
|
441
468
|
next if listener_fds.include?(io)
|
|
442
469
|
io = IO.for_fd(io) rescue next
|
|
443
|
-
|
|
470
|
+
prevent_autoclose(io)
|
|
444
471
|
io.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
|
445
472
|
end
|
|
446
473
|
|
|
@@ -520,9 +547,8 @@ class Unicorn::HttpServer
|
|
|
520
547
|
# the socket is closed at the end of this function
|
|
521
548
|
def handle_error(client, e)
|
|
522
549
|
code = case e
|
|
523
|
-
when EOFError,Errno::ECONNRESET,Errno::EPIPE,Errno::
|
|
524
|
-
|
|
525
|
-
500
|
|
550
|
+
when EOFError,Errno::ECONNRESET,Errno::EPIPE,Errno::ENOTCONN
|
|
551
|
+
# client disconnected on us and there's nothing we can do
|
|
526
552
|
when Unicorn::RequestURITooLongError
|
|
527
553
|
414
|
|
528
554
|
when Unicorn::RequestEntityTooLargeError
|
|
@@ -533,7 +559,9 @@ class Unicorn::HttpServer
|
|
|
533
559
|
Unicorn.log_error(@logger, "app error", e)
|
|
534
560
|
500
|
|
535
561
|
end
|
|
536
|
-
|
|
562
|
+
if code
|
|
563
|
+
client.kgio_trywrite(err_response(code, @request.response_start_sent))
|
|
564
|
+
end
|
|
537
565
|
client.close
|
|
538
566
|
rescue
|
|
539
567
|
end
|
|
@@ -745,7 +773,7 @@ class Unicorn::HttpServer
|
|
|
745
773
|
inherited = ENV['UNICORN_FD'].to_s.split(/,/).map do |fd|
|
|
746
774
|
io = Socket.for_fd(fd.to_i)
|
|
747
775
|
set_server_sockopt(io, listener_opts[sock_name(io)])
|
|
748
|
-
|
|
776
|
+
prevent_autoclose(io)
|
|
749
777
|
logger.info "inherited addr=#{sock_name(io)} fd=#{fd}"
|
|
750
778
|
server_cast(io)
|
|
751
779
|
end
|
|
@@ -8,6 +8,7 @@ module Unicorn
|
|
|
8
8
|
include Socket::Constants
|
|
9
9
|
|
|
10
10
|
# prevents IO objects in here from being GC-ed
|
|
11
|
+
# kill this when we drop 1.8 support
|
|
11
12
|
IO_PURGATORY = []
|
|
12
13
|
|
|
13
14
|
# internal interface, only used by Rainbows!/Zbatery
|
|
@@ -41,6 +42,15 @@ module Unicorn
|
|
|
41
42
|
|
|
42
43
|
# do not send out partial frames (Linux)
|
|
43
44
|
TCP_CORK = 3 unless defined?(TCP_CORK)
|
|
45
|
+
|
|
46
|
+
# Linux got SO_REUSEPORT in 3.9, BSDs have had it for ages
|
|
47
|
+
unless defined?(SO_REUSEPORT)
|
|
48
|
+
if RUBY_PLATFORM =~ /(?:alpha|mips|parisc|sparc)/
|
|
49
|
+
SO_REUSEPORT = 0x0200 # untested
|
|
50
|
+
else
|
|
51
|
+
SO_REUSEPORT = 15 # only tested on x86_64 and i686
|
|
52
|
+
end
|
|
53
|
+
end
|
|
44
54
|
when /freebsd/
|
|
45
55
|
# do not send out partial frames (FreeBSD)
|
|
46
56
|
TCP_NOPUSH = 4 unless defined?(TCP_NOPUSH)
|
|
@@ -50,6 +60,14 @@ module Unicorn
|
|
|
50
60
|
end if defined?(SO_ACCEPTFILTER)
|
|
51
61
|
end
|
|
52
62
|
|
|
63
|
+
def prevent_autoclose(io)
|
|
64
|
+
if io.respond_to?(:autoclose=)
|
|
65
|
+
io.autoclose = false
|
|
66
|
+
else
|
|
67
|
+
IO_PURGATORY << io
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
53
71
|
def set_tcp_sockopt(sock, opt)
|
|
54
72
|
# just in case, even LANs can break sometimes. Linux sysadmins
|
|
55
73
|
# can lower net.ipv4.tcp_keepalive_* sysctl knobs to very low values.
|
|
@@ -142,9 +160,9 @@ module Unicorn
|
|
|
142
160
|
File.umask(old_umask)
|
|
143
161
|
end
|
|
144
162
|
elsif /\A\[([a-fA-F0-9:]+)\]:(\d+)\z/ =~ address
|
|
145
|
-
|
|
163
|
+
new_tcp_server($1, $2.to_i, opt.merge(:ipv6=>true))
|
|
146
164
|
elsif /\A(\d+\.\d+\.\d+\.\d+):(\d+)\z/ =~ address
|
|
147
|
-
|
|
165
|
+
new_tcp_server($1, $2.to_i, opt)
|
|
148
166
|
else
|
|
149
167
|
raise ArgumentError, "Don't know how to bind: #{address}"
|
|
150
168
|
end
|
|
@@ -152,15 +170,20 @@ module Unicorn
|
|
|
152
170
|
sock
|
|
153
171
|
end
|
|
154
172
|
|
|
155
|
-
def
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
173
|
+
def new_tcp_server(addr, port, opt)
|
|
174
|
+
# n.b. we set FD_CLOEXEC in the workers
|
|
175
|
+
sock = Socket.new(opt[:ipv6] ? AF_INET6 : AF_INET, SOCK_STREAM, 0)
|
|
176
|
+
if opt.key?(:ipv6only)
|
|
177
|
+
defined?(IPV6_V6ONLY) or
|
|
178
|
+
abort "Socket::IPV6_V6ONLY not defined, upgrade Ruby and/or your OS"
|
|
179
|
+
sock.setsockopt(IPPROTO_IPV6, IPV6_V6ONLY, opt[:ipv6only] ? 1 : 0)
|
|
180
|
+
end
|
|
161
181
|
sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
|
|
182
|
+
if defined?(SO_REUSEPORT) && opt[:reuseport]
|
|
183
|
+
sock.setsockopt(SOL_SOCKET, SO_REUSEPORT, 1)
|
|
184
|
+
end
|
|
162
185
|
sock.bind(Socket.pack_sockaddr_in(port, addr))
|
|
163
|
-
|
|
186
|
+
prevent_autoclose(sock)
|
|
164
187
|
Kgio::TCPServer.for_fd(sock.fileno)
|
|
165
188
|
end
|
|
166
189
|
|
data/lib/unicorn/util.rb
CHANGED
|
@@ -39,7 +39,7 @@ module Unicorn::Util
|
|
|
39
39
|
to_reopen.each do |fp|
|
|
40
40
|
orig_st = begin
|
|
41
41
|
fp.stat
|
|
42
|
-
rescue IOError, Errno::EBADF
|
|
42
|
+
rescue IOError, Errno::EBADF # race
|
|
43
43
|
next
|
|
44
44
|
end
|
|
45
45
|
|
|
@@ -50,8 +50,28 @@ module Unicorn::Util
|
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
begin
|
|
53
|
-
|
|
53
|
+
# stdin, stdout, stderr are special. The following dance should
|
|
54
|
+
# guarantee there is no window where `fp' is unwritable in MRI
|
|
55
|
+
# (or any correct Ruby implementation).
|
|
56
|
+
#
|
|
57
|
+
# Fwiw, GVL has zero bearing here. This is tricky because of
|
|
58
|
+
# the unavoidable existence of stdio FILE * pointers for
|
|
59
|
+
# std{in,out,err} in all programs which may use the standard C library
|
|
60
|
+
if fp.fileno <= 2
|
|
61
|
+
# We do not want to hit fclose(3)->dup(2) window for std{in,out,err}
|
|
62
|
+
# MRI will use freopen(3) here internally on std{in,out,err}
|
|
63
|
+
fp.reopen(fp.path, "a")
|
|
64
|
+
else
|
|
65
|
+
# We should not need this workaround, Ruby can be fixed:
|
|
66
|
+
# http://bugs.ruby-lang.org/issues/9036
|
|
67
|
+
# MRI will not call call fclose(3) or freopen(3) here
|
|
68
|
+
# since there's no associated std{in,out,err} FILE * pointer
|
|
69
|
+
# This should atomically use dup3(2) (or dup2(2)) syscall
|
|
70
|
+
File.open(fp.path, "a") { |tmpfp| fp.reopen(tmpfp) }
|
|
71
|
+
end
|
|
72
|
+
|
|
54
73
|
fp.sync = true
|
|
74
|
+
fp.flush # IO#sync=true may not implicitly flush
|
|
55
75
|
new_st = fp.stat
|
|
56
76
|
|
|
57
77
|
# this should only happen in the master:
|
data/script/isolate_for_tests
CHANGED
|
@@ -16,10 +16,10 @@ opts = {
|
|
|
16
16
|
|
|
17
17
|
pid = fork do
|
|
18
18
|
Isolate.now!(opts) do
|
|
19
|
-
gem 'raindrops', '0.
|
|
19
|
+
gem 'raindrops', '0.12.0'
|
|
20
20
|
gem 'kgio-monkey', '0.4.0'
|
|
21
|
-
gem 'kgio', '2.8.
|
|
22
|
-
gem 'rack', '1.5.
|
|
21
|
+
gem 'kgio', '2.8.1'
|
|
22
|
+
gem 'rack', '1.5.2'
|
|
23
23
|
end
|
|
24
24
|
end
|
|
25
25
|
_, status = Process.waitpid2(pid)
|
data/t/oob_gc.ru
CHANGED
|
@@ -7,8 +7,7 @@ $gc_started = false
|
|
|
7
7
|
|
|
8
8
|
# Mock GC.start
|
|
9
9
|
def GC.start
|
|
10
|
-
ObjectSpace.each_object(
|
|
11
|
-
next if Unicorn::HttpServer::LISTENERS.include?(x)
|
|
10
|
+
ObjectSpace.each_object(Kgio::Socket) do |x|
|
|
12
11
|
x.closed? or abort "not closed #{x}"
|
|
13
12
|
end
|
|
14
13
|
$gc_started = true
|
data/t/oob_gc_path.ru
CHANGED
|
@@ -7,8 +7,7 @@ $gc_started = false
|
|
|
7
7
|
|
|
8
8
|
# Mock GC.start
|
|
9
9
|
def GC.start
|
|
10
|
-
ObjectSpace.each_object(
|
|
11
|
-
next if Unicorn::HttpServer::LISTENERS.include?(x)
|
|
10
|
+
ObjectSpace.each_object(Kgio::Socket) do |x|
|
|
12
11
|
x.closed? or abort "not closed #{x}"
|
|
13
12
|
end
|
|
14
13
|
$gc_started = true
|
data/test/test_helper.rb
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# Copyright (c) 2005 Zed A. Shaw
|
|
4
4
|
# You can redistribute it and/or modify it under the same terms as Ruby 1.8 or
|
|
5
|
-
# the GPLv3
|
|
5
|
+
# the GPLv2+ (GPLv3+ preferred)
|
|
6
6
|
#
|
|
7
7
|
# Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html
|
|
8
8
|
# for more information.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# Copyright (c) 2005 Zed A. Shaw
|
|
4
4
|
# You can redistribute it and/or modify it under the same terms as Ruby 1.8 or
|
|
5
|
-
# the GPLv3
|
|
5
|
+
# the GPLv2+ (GPLv3+ preferred)
|
|
6
6
|
#
|
|
7
7
|
# Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html
|
|
8
8
|
# for more information.
|
data/test/unit/test_request.rb
CHANGED
data/test/unit/test_response.rb
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# Copyright (c) 2005 Zed A. Shaw
|
|
4
4
|
# You can redistribute it and/or modify it under the same terms as Ruby 1.8 or
|
|
5
|
-
# the GPLv3
|
|
5
|
+
# the GPLv2+ (GPLv3+ preferred)
|
|
6
6
|
#
|
|
7
7
|
# Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html
|
|
8
8
|
# for more information.
|
data/test/unit/test_server.rb
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# Copyright (c) 2005 Zed A. Shaw
|
|
4
4
|
# You can redistribute it and/or modify it under the same terms as Ruby 1.8 or
|
|
5
|
-
# the GPLv3
|
|
5
|
+
# the GPLv2+ (GPLv3+ preferred)
|
|
6
6
|
#
|
|
7
7
|
# Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html
|
|
8
8
|
# for more information.
|
data/test/unit/test_signals.rb
CHANGED
|
@@ -184,4 +184,12 @@ class TestSocketHelper < Test::Unit::TestCase
|
|
|
184
184
|
assert_equal 1, cur
|
|
185
185
|
rescue Errno::EAFNOSUPPORT
|
|
186
186
|
end if RUBY_VERSION >= "1.9.2"
|
|
187
|
+
|
|
188
|
+
def test_reuseport
|
|
189
|
+
port = unused_port @test_addr
|
|
190
|
+
name = "#@test_addr:#{port}"
|
|
191
|
+
sock = bind_listen(name, :reuseport => true)
|
|
192
|
+
cur = sock.getsockopt(Socket::SOL_SOCKET, SO_REUSEPORT).unpack('i')[0]
|
|
193
|
+
assert_equal 1, cur
|
|
194
|
+
end if defined?(SO_REUSEPORT)
|
|
187
195
|
end
|
data/test/unit/test_util.rb
CHANGED
|
@@ -80,7 +80,11 @@ class TestUtil < Test::Unit::TestCase
|
|
|
80
80
|
File.open(tmp_path, "a:#{ext.to_s}:#{int.to_s}") { |fp|
|
|
81
81
|
fp.sync = true
|
|
82
82
|
assert_equal ext, fp.external_encoding
|
|
83
|
-
|
|
83
|
+
|
|
84
|
+
if ext != Encoding::BINARY
|
|
85
|
+
assert_equal int, fp.internal_encoding
|
|
86
|
+
end
|
|
87
|
+
|
|
84
88
|
File.unlink(tmp_path)
|
|
85
89
|
assert ! File.exist?(tmp_path)
|
|
86
90
|
Unicorn::Util.reopen_logs
|
|
@@ -88,7 +92,9 @@ class TestUtil < Test::Unit::TestCase
|
|
|
88
92
|
assert File.exist?(tmp_path)
|
|
89
93
|
assert_equal fp.stat.inspect, File.stat(tmp_path).inspect
|
|
90
94
|
assert_equal ext, fp.external_encoding
|
|
91
|
-
|
|
95
|
+
if ext != Encoding::BINARY
|
|
96
|
+
assert_equal int, fp.internal_encoding
|
|
97
|
+
end
|
|
92
98
|
assert_equal(EXPECT_FLAGS, EXPECT_FLAGS & fp.fcntl(Fcntl::F_GETFL))
|
|
93
99
|
assert fp.sync
|
|
94
100
|
}
|
data/unicorn.gemspec
CHANGED
metadata
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: !binary |-
|
|
3
3
|
dW5pY29ybg==
|
|
4
4
|
version: !ruby/object:Gem::Version
|
|
5
|
-
version: 4.
|
|
5
|
+
version: 4.7.0
|
|
6
6
|
prerelease:
|
|
7
7
|
platform: ruby
|
|
8
8
|
authors:
|
|
@@ -10,7 +10,7 @@ authors:
|
|
|
10
10
|
autorequire:
|
|
11
11
|
bindir: bin
|
|
12
12
|
cert_chain: []
|
|
13
|
-
date: 2013-
|
|
13
|
+
date: 2013-11-04 00:00:00.000000000 Z
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|
|
16
16
|
name: !binary |-
|
|
@@ -331,9 +331,7 @@ files:
|
|
|
331
331
|
homepage: http://unicorn.bogomips.org/
|
|
332
332
|
licenses:
|
|
333
333
|
- !binary |-
|
|
334
|
-
|
|
335
|
-
- !binary |-
|
|
336
|
-
R1BMdjM=
|
|
334
|
+
R1BMdjIr
|
|
337
335
|
- !binary |-
|
|
338
336
|
UnVieSAxLjg=
|
|
339
337
|
post_install_message:
|