unicorn 4.1.1 → 4.2.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/COPYING +617 -282
- data/DESIGN +3 -3
- data/GIT-VERSION-GEN +1 -1
- data/LICENSE +13 -4
- data/Links +3 -0
- data/README +3 -3
- data/Rakefile +1 -1
- data/examples/unicorn.conf.rb +1 -1
- data/ext/unicorn_http/unicorn_http.rl +2 -1
- data/lib/unicorn/app/inetd.rb +2 -1
- data/lib/unicorn/app/old_rails.rb +2 -1
- data/lib/unicorn/app/old_rails/static.rb +2 -1
- data/lib/unicorn/cgi_wrapper.rb +2 -1
- data/lib/unicorn/configurator.rb +11 -5
- data/lib/unicorn/const.rb +1 -1
- data/lib/unicorn/http_server.rb +7 -4
- data/lib/unicorn/oob_gc.rb +2 -0
- data/lib/unicorn/socket_helper.rb +4 -1
- data/lib/unicorn/ssl_client.rb +6 -0
- data/lib/unicorn/ssl_configurator.rb +104 -0
- data/lib/unicorn/ssl_server.rb +42 -0
- data/script/isolate_for_tests +7 -4
- data/t/.gitignore +3 -0
- data/t/GNUmakefile +5 -1
- data/t/bin/sha1sum.rb +1 -7
- data/t/sslgen.sh +71 -0
- data/t/t0011-active-unix-socket.sh +1 -1
- data/t/t0600-https-server-basic.sh +48 -0
- data/t/test-lib.sh +12 -9
- data/test/rails/test_rails.rb +4 -1
- data/test/test_helper.rb +3 -1
- data/test/unit/test_http_parser.rb +2 -1
- data/test/unit/test_http_parser_ng.rb +8 -0
- data/test/unit/test_request.rb +2 -1
- data/test/unit/test_response.rb +2 -1
- data/test/unit/test_server.rb +2 -1
- data/test/unit/test_signals.rb +2 -1
- data/test/unit/test_sni_hostnames.rb +47 -0
- data/unicorn.gemspec +4 -4
- metadata +25 -17
data/DESIGN
CHANGED
@@ -31,9 +31,9 @@
|
|
31
31
|
* One master process spawns and reaps worker processes. The
|
32
32
|
Rack application itself is called only within the worker process (but
|
33
33
|
can be loaded within the master). A copy-on-write friendly garbage
|
34
|
-
collector like
|
35
|
-
usage along with the "preload_app true"
|
36
|
-
Unicorn::Configurator).
|
34
|
+
collector like the one found in Ruby 2.0.0dev or Ruby Enterprise Edition
|
35
|
+
can be used to minimize memory usage along with the "preload_app true"
|
36
|
+
directive (see Unicorn::Configurator).
|
37
37
|
|
38
38
|
* The number of worker processes should be scaled to the number of
|
39
39
|
CPUs, memory or even spindles you have. If you have an existing
|
data/GIT-VERSION-GEN
CHANGED
data/LICENSE
CHANGED
@@ -1,8 +1,17 @@
|
|
1
1
|
Unicorn is copyrighted free software by all contributors, see logs in
|
2
|
-
revision control for names and email addresses of all of them.
|
3
|
-
|
4
|
-
|
5
|
-
the
|
2
|
+
revision control for names and email addresses of all of them.
|
3
|
+
|
4
|
+
You can redistribute it and/or modify it under either the terms of the
|
5
|
+
GNU General Public License (GPL) as published by the Free Software
|
6
|
+
Foundation (FSF), version {3.0}[http://www.gnu.org/licenses/gpl-3.0.txt]
|
7
|
+
or version {2.0}[http://www.gnu.org/licenses/gpl-2.0.txt]
|
8
|
+
or the Ruby-specific license terms (see below).
|
9
|
+
|
10
|
+
The unicorn project leader (Eric Wong) reserves the right to add future
|
11
|
+
versions of the GPL (and no other licenses) as published by the FSF to
|
12
|
+
the licensing terms.
|
13
|
+
|
14
|
+
=== Ruby-specific terms (if you're not using the GPLv2 or GPLv3)
|
6
15
|
|
7
16
|
1. You may make and give away verbatim copies of the source form of the
|
8
17
|
software without restriction, provided that you duplicate all of the
|
data/Links
CHANGED
@@ -26,6 +26,9 @@ or services behind them.
|
|
26
26
|
* {raindrops}[http://raindrops.bogomips.org/] - real-time stats for
|
27
27
|
preforking Rack servers
|
28
28
|
|
29
|
+
* {UnXF}[http://bogomips.org/unxf/] Un-X-Forward* the Rack environment,
|
30
|
+
useful since unicorn is designed to be deployed behind a reverse proxy.
|
31
|
+
|
29
32
|
=== \Unicorn is written to work with
|
30
33
|
|
31
34
|
* {Rack}[http://rack.rubyforge.org/] - a minimal interface between webservers
|
data/README
CHANGED
@@ -62,9 +62,9 @@ both the the request and response in between \Unicorn and slow clients.
|
|
62
62
|
\Unicorn is copyright 2009 by all contributors (see logs in git).
|
63
63
|
It is based on Mongrel 1.1.5 and carries the same license.
|
64
64
|
|
65
|
-
Mongrel is copyright 2007 Zed A. Shaw and contributors. It is
|
66
|
-
under
|
67
|
-
for details.
|
65
|
+
Mongrel is copyright 2007 Zed A. Shaw and contributors. It is
|
66
|
+
tri-licensed under (your choice) of the GPLv3, GPLv2 or Ruby-specific
|
67
|
+
terms. See the included LICENSE file for details.
|
68
68
|
|
69
69
|
\Unicorn is 100% Free Software.
|
70
70
|
|
data/Rakefile
CHANGED
@@ -49,7 +49,7 @@ task :fm_update do
|
|
49
49
|
require 'net/netrc'
|
50
50
|
require 'json'
|
51
51
|
version = ENV['VERSION'] or abort "VERSION= needed"
|
52
|
-
uri = URI.parse('http://
|
52
|
+
uri = URI.parse('http://freecode.com/projects/unicorn/releases.json')
|
53
53
|
rc = Net::Netrc.locate('unicorn-fm') or abort "~/.netrc not found"
|
54
54
|
api_token = rc.password
|
55
55
|
_, subject, body = `git cat-file tag v#{version}`.split(/\n\n/, 3)
|
data/examples/unicorn.conf.rb
CHANGED
@@ -40,7 +40,7 @@ pid "/path/to/app/shared/pids/unicorn.pid"
|
|
40
40
|
stderr_path "/path/to/app/shared/log/unicorn.stderr.log"
|
41
41
|
stdout_path "/path/to/app/shared/log/unicorn.stdout.log"
|
42
42
|
|
43
|
-
# combine REE with "preload_app true" for memory savings
|
43
|
+
# combine Ruby 2.0.0dev or REE with "preload_app true" for memory savings
|
44
44
|
# http://rubyenterpriseedition.com/faq.html#adapt_apps_for_cow
|
45
45
|
preload_app true
|
46
46
|
GC.respond_to?(:copy_on_write_friendly=) and
|
@@ -1,7 +1,8 @@
|
|
1
1
|
/**
|
2
2
|
* Copyright (c) 2009 Eric Wong (all bugs are Eric's fault)
|
3
3
|
* Copyright (c) 2005 Zed A. Shaw
|
4
|
-
* You can redistribute it and/or modify it under the same terms as Ruby.
|
4
|
+
* You can redistribute it and/or modify it under the same terms as Ruby 1.8 or
|
5
|
+
* the GPLv3
|
5
6
|
*/
|
6
7
|
#include "ruby.h"
|
7
8
|
#include "ext_help.h"
|
data/lib/unicorn/app/inetd.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
# -*- encoding: binary -*-
|
2
2
|
# :enddoc:
|
3
3
|
# Copyright (c) 2009 Eric Wong
|
4
|
-
# You can redistribute it and/or modify it under the same terms as Ruby.
|
4
|
+
# You can redistribute it and/or modify it under the same terms as Ruby 1.8 or
|
5
|
+
# the GPLv3
|
5
6
|
|
6
7
|
# this class *must* be used with Rack::Chunked
|
7
8
|
module Unicorn::App
|
@@ -4,7 +4,8 @@
|
|
4
4
|
# This code is based on the original Rails handler in Mongrel
|
5
5
|
# Copyright (c) 2005 Zed A. Shaw
|
6
6
|
# Copyright (c) 2009 Eric Wong
|
7
|
-
# You can redistribute it and/or modify it under the same terms as Ruby.
|
7
|
+
# You can redistribute it and/or modify it under the same terms as Ruby 1.8 or
|
8
|
+
# the GPLv3
|
8
9
|
# Additional work donated by contributors. See CONTRIBUTORS for more info.
|
9
10
|
require 'unicorn/cgi_wrapper'
|
10
11
|
require 'dispatcher'
|
@@ -3,7 +3,8 @@
|
|
3
3
|
# This code is based on the original Rails handler in Mongrel
|
4
4
|
# Copyright (c) 2005 Zed A. Shaw
|
5
5
|
# Copyright (c) 2009 Eric Wong
|
6
|
-
# You can redistribute it and/or modify it under the same terms as Ruby.
|
6
|
+
# You can redistribute it and/or modify it under the same terms as Ruby 1.8 or
|
7
|
+
# the GPLv3
|
7
8
|
|
8
9
|
# Static file handler for Rails < 2.3. This handler is only provided
|
9
10
|
# as a convenience for developers. Performance-minded deployments should
|
data/lib/unicorn/cgi_wrapper.rb
CHANGED
@@ -4,7 +4,8 @@
|
|
4
4
|
# This code is based on the original CGIWrapper from Mongrel
|
5
5
|
# Copyright (c) 2005 Zed A. Shaw
|
6
6
|
# Copyright (c) 2009 Eric Wong
|
7
|
-
# You can redistribute it and/or modify it under the same terms as Ruby.
|
7
|
+
# You can redistribute it and/or modify it under the same terms as Ruby 1.8 or
|
8
|
+
# the GPLv3
|
8
9
|
#
|
9
10
|
# Additional work donated by contributors. See CONTRIBUTORS for more info.
|
10
11
|
|
data/lib/unicorn/configurator.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# -*- encoding: binary -*-
|
2
2
|
require 'logger'
|
3
|
+
require 'unicorn/ssl_configurator'
|
3
4
|
|
4
5
|
# Implements a simple DSL for configuring a \Unicorn server.
|
5
6
|
#
|
@@ -12,6 +13,7 @@ require 'logger'
|
|
12
13
|
# See the link:/TUNING.html document for more information on tuning unicorn.
|
13
14
|
class Unicorn::Configurator
|
14
15
|
include Unicorn
|
16
|
+
include Unicorn::SSLConfigurator
|
15
17
|
|
16
18
|
# :stopdoc:
|
17
19
|
attr_accessor :set, :config_file, :after_reload
|
@@ -186,7 +188,8 @@ class Unicorn::Configurator
|
|
186
188
|
# }
|
187
189
|
def timeout(seconds)
|
188
190
|
set_int(:timeout, seconds, 3)
|
189
|
-
|
191
|
+
# POSIX says 31 days is the smallest allowed maximum timeout for select()
|
192
|
+
max = 30 * 60 * 60 * 24
|
190
193
|
set[:timeout] = seconds > max ? max : seconds
|
191
194
|
end
|
192
195
|
|
@@ -563,13 +566,16 @@ private
|
|
563
566
|
end
|
564
567
|
end
|
565
568
|
|
566
|
-
def
|
569
|
+
def check_bool(var, bool) # :nodoc:
|
567
570
|
case bool
|
568
571
|
when true, false
|
569
|
-
|
570
|
-
else
|
571
|
-
raise ArgumentError, "#{var}=#{bool.inspect} not a boolean"
|
572
|
+
return bool
|
572
573
|
end
|
574
|
+
raise ArgumentError, "#{var}=#{bool.inspect} not a boolean"
|
575
|
+
end
|
576
|
+
|
577
|
+
def set_bool(var, bool) #:nodoc:
|
578
|
+
set[var] = check_bool(var, bool)
|
573
579
|
end
|
574
580
|
|
575
581
|
def set_hook(var, my_proc, req_arity = 2) #:nodoc:
|
data/lib/unicorn/const.rb
CHANGED
data/lib/unicorn/http_server.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# -*- encoding: binary -*-
|
2
|
+
require "unicorn/ssl_server"
|
2
3
|
|
3
4
|
# This is the process manager of Unicorn. This manages worker
|
4
5
|
# processes which in turn handle the I/O and application process.
|
@@ -19,6 +20,7 @@ class Unicorn::HttpServer
|
|
19
20
|
attr_reader :pid, :logger
|
20
21
|
include Unicorn::SocketHelper
|
21
22
|
include Unicorn::HttpResponse
|
23
|
+
include Unicorn::SSLServer
|
22
24
|
|
23
25
|
# backwards compatibility with 1.x
|
24
26
|
Worker = Unicorn::Worker
|
@@ -282,7 +284,7 @@ class Unicorn::HttpServer
|
|
282
284
|
when :USR2 # exec binary, stay alive in case something went wrong
|
283
285
|
reexec
|
284
286
|
when :WINCH
|
285
|
-
if
|
287
|
+
if Unicorn::Configurator::RACKUP[:daemonized]
|
286
288
|
respawn = false
|
287
289
|
logger.info "gracefully stopping all workers"
|
288
290
|
kill_each_worker(:QUIT)
|
@@ -445,7 +447,7 @@ class Unicorn::HttpServer
|
|
445
447
|
now = Time.now.to_i
|
446
448
|
WORKERS.dup.each_pair do |wpid, worker|
|
447
449
|
tick = worker.tick
|
448
|
-
0 == tick and next # skip workers that
|
450
|
+
0 == tick and next # skip workers that haven't processed any clients
|
449
451
|
diff = now - tick
|
450
452
|
tmp = @timeout - diff
|
451
453
|
if tmp >= 0
|
@@ -563,6 +565,8 @@ class Unicorn::HttpServer
|
|
563
565
|
self.timeout /= 2.0 # halve it for select()
|
564
566
|
@config = nil
|
565
567
|
build_app! unless preload_app
|
568
|
+
ssl_enable!
|
569
|
+
@after_fork = @listener_opts = @orig_app = nil
|
566
570
|
end
|
567
571
|
|
568
572
|
def reopen_worker_logs(worker_nr)
|
@@ -618,9 +622,8 @@ class Unicorn::HttpServer
|
|
618
622
|
# timeout used so we can detect parent death:
|
619
623
|
worker.tick = Time.now.to_i
|
620
624
|
ret = IO.select(l, nil, SELF_PIPE, @timeout) and ready = ret[0]
|
621
|
-
rescue Errno::EBADF
|
622
|
-
nr < 0 or return
|
623
625
|
rescue => e
|
626
|
+
redo if nr < 0 && (Errno::EBADF === e || IOError === e) # reopen logs
|
624
627
|
Unicorn.log_error(@logger, "listen loop error", e) if worker
|
625
628
|
end while worker
|
626
629
|
end
|
data/lib/unicorn/oob_gc.rb
CHANGED
@@ -51,7 +51,10 @@ module Unicorn
|
|
51
51
|
end
|
52
52
|
|
53
53
|
def set_tcp_sockopt(sock, opt)
|
54
|
-
#
|
54
|
+
# just in case, even LANs can break sometimes. Linux sysadmins
|
55
|
+
# can lower net.ipv4.tcp_keepalive_* sysctl knobs to very low values.
|
56
|
+
sock.setsockopt(SOL_SOCKET, SO_KEEPALIVE, 1) if defined?(SO_KEEPALIVE)
|
57
|
+
|
55
58
|
if defined?(TCP_NODELAY)
|
56
59
|
val = opt[:tcp_nodelay]
|
57
60
|
val = DEFAULTS[:tcp_nodelay] if nil == val
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# -*- encoding: binary -*-
|
2
|
+
# :stopdoc:
|
3
|
+
# This module is included in Unicorn::Configurator
|
4
|
+
# :startdoc:
|
5
|
+
#
|
6
|
+
module Unicorn::SSLConfigurator
|
7
|
+
def ssl(&block)
|
8
|
+
ssl_require!
|
9
|
+
before = @set[:listeners].dup
|
10
|
+
opts = @set[:ssl_opts] = {}
|
11
|
+
yield
|
12
|
+
(@set[:listeners] - before).each do |address|
|
13
|
+
(@set[:listener_opts][address] ||= {})[:ssl_opts] = opts
|
14
|
+
end
|
15
|
+
ensure
|
16
|
+
@set.delete(:ssl_opts)
|
17
|
+
end
|
18
|
+
|
19
|
+
def ssl_certificate(file)
|
20
|
+
ssl_set(:ssl_certificate, file)
|
21
|
+
end
|
22
|
+
|
23
|
+
def ssl_certificate_key(file)
|
24
|
+
ssl_set(:ssl_certificate_key, file)
|
25
|
+
end
|
26
|
+
|
27
|
+
def ssl_client_certificate(file)
|
28
|
+
ssl_set(:ssl_client_certificate, file)
|
29
|
+
end
|
30
|
+
|
31
|
+
def ssl_dhparam(file)
|
32
|
+
ssl_set(:ssl_dhparam, file)
|
33
|
+
end
|
34
|
+
|
35
|
+
def ssl_ciphers(openssl_cipherlist_spec)
|
36
|
+
ssl_set(:ssl_ciphers, openssl_cipherlist_spec)
|
37
|
+
end
|
38
|
+
|
39
|
+
def ssl_crl(file)
|
40
|
+
ssl_set(:ssl_crl, file)
|
41
|
+
end
|
42
|
+
|
43
|
+
def ssl_prefer_server_ciphers(bool)
|
44
|
+
ssl_set(:ssl_prefer_server_ciphers, check_bool(bool))
|
45
|
+
end
|
46
|
+
|
47
|
+
def ssl_protocols(list)
|
48
|
+
ssl_set(:ssl_protocols, list)
|
49
|
+
end
|
50
|
+
|
51
|
+
def ssl_verify_client(on_off_optional)
|
52
|
+
ssl_set(:ssl_verify_client, on_off_optional)
|
53
|
+
end
|
54
|
+
|
55
|
+
def ssl_session_timeout(seconds)
|
56
|
+
ssl_set(:ssl_session_timeout, seconds)
|
57
|
+
end
|
58
|
+
|
59
|
+
def ssl_verify_depth(depth)
|
60
|
+
ssl_set(:ssl_verify_depth, depth)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Allows specifying an engine for OpenSSL to use. We have not been
|
64
|
+
# able to successfully test this feature due to a lack of hardware,
|
65
|
+
# Reports of success or patches to mongrel-unicorn@rubyforge.org is
|
66
|
+
# greatly appreciated.
|
67
|
+
def ssl_engine(engine)
|
68
|
+
ssl_warn_global(:ssl_engine)
|
69
|
+
ssl_require!
|
70
|
+
OpenSSL::Engine.load
|
71
|
+
OpenSSL::Engine.by_id(engine)
|
72
|
+
@set[:ssl_engine] = engine
|
73
|
+
end
|
74
|
+
|
75
|
+
def ssl_compression(bool)
|
76
|
+
# OpenSSL uses the SSL_OP_NO_COMPRESSION flag, Flipper follows suit
|
77
|
+
# with :ssl_no_compression, but we negate it to avoid exposing double
|
78
|
+
# negatives to the user.
|
79
|
+
ssl_set(:ssl_no_compression, check_bool(:ssl_compression, ! bool))
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
def ssl_warn_global(func) # :nodoc:
|
85
|
+
Hash === @set[:ssl_opts] or return
|
86
|
+
warn("`#{func}' affects all SSL contexts in this process, " \
|
87
|
+
"not just this block")
|
88
|
+
end
|
89
|
+
|
90
|
+
def ssl_set(key, value) # :nodoc:
|
91
|
+
cur = @set[:ssl_opts]
|
92
|
+
Hash === cur or
|
93
|
+
raise ArgumentError, "#{key} must be called inside an `ssl' block"
|
94
|
+
cur[key] = value
|
95
|
+
end
|
96
|
+
|
97
|
+
def ssl_require! # :nodoc:
|
98
|
+
require "flipper"
|
99
|
+
require "unicorn/ssl_client"
|
100
|
+
rescue LoadError
|
101
|
+
warn "install 'kgio-monkey' for SSL support"
|
102
|
+
raise
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# -*- encoding: binary -*-
|
2
|
+
# :stopdoc:
|
3
|
+
# this module is meant to be included in Unicorn::HttpServer
|
4
|
+
# It is an implementation detail and NOT meant for users.
|
5
|
+
module Unicorn::SSLServer
|
6
|
+
attr_accessor :ssl_engine
|
7
|
+
|
8
|
+
def ssl_enable!
|
9
|
+
sni_hostnames = rack_sni_hostnames(@app)
|
10
|
+
seen = {} # we map a single SSLContext to multiple listeners
|
11
|
+
listener_ctx = {}
|
12
|
+
@listener_opts.each do |address, address_opts|
|
13
|
+
ssl_opts = address_opts[:ssl_opts] or next
|
14
|
+
listener_ctx[address] = seen[ssl_opts.object_id] ||= begin
|
15
|
+
unless sni_hostnames.empty?
|
16
|
+
ssl_opts = ssl_opts.dup
|
17
|
+
ssl_opts[:sni_hostnames] = sni_hostnames
|
18
|
+
end
|
19
|
+
ctx = Flipper.ssl_context(ssl_opts)
|
20
|
+
# FIXME: make configurable
|
21
|
+
ctx.session_cache_mode = OpenSSL::SSL::SSLContext::SESSION_CACHE_OFF
|
22
|
+
ctx
|
23
|
+
end
|
24
|
+
end
|
25
|
+
Unicorn::HttpServer::LISTENERS.each do |listener|
|
26
|
+
ctx = listener_ctx[sock_name(listener)] or next
|
27
|
+
listener.extend(Kgio::SSLServer)
|
28
|
+
listener.ssl_ctx = ctx
|
29
|
+
listener.kgio_ssl_class = Unicorn::SSLClient
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# ugh, this depends on Rack internals...
|
34
|
+
def rack_sni_hostnames(rack_app) # :nodoc:
|
35
|
+
hostnames = {}
|
36
|
+
if Rack::URLMap === rack_app
|
37
|
+
mapping = rack_app.instance_variable_get(:@mapping)
|
38
|
+
mapping.each { |hostname,_,_,_| hostnames[hostname] = true }
|
39
|
+
end
|
40
|
+
hostnames.keys
|
41
|
+
end
|
42
|
+
end
|
data/script/isolate_for_tests
CHANGED
@@ -16,10 +16,13 @@ opts = {
|
|
16
16
|
|
17
17
|
pid = fork do
|
18
18
|
Isolate.now!(opts) do
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
gem '
|
19
|
+
if RUBY_VERSION.to_f < 2.0
|
20
|
+
gem 'sqlite3-ruby', '1.2.5'
|
21
|
+
end
|
22
|
+
gem 'raindrops', '0.8.0'
|
23
|
+
gem 'kgio-monkey', '0.3.0'
|
24
|
+
gem 'kgio', '2.7.2'
|
25
|
+
gem 'rack', '1.4.1'
|
23
26
|
end
|
24
27
|
end
|
25
28
|
_, status = Process.waitpid2(pid)
|