unicorn 4.1.1 → 4.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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)
|