unicorn 4.9.0 → 6.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitattributes +5 -0
- data/.olddoc.yml +13 -6
- data/Application_Timeouts +7 -7
- data/DESIGN +2 -4
- data/Documentation/.gitignore +1 -3
- data/Documentation/unicorn.1 +222 -0
- data/Documentation/unicorn_rails.1 +207 -0
- data/FAQ +17 -8
- data/GIT-VERSION-GEN +1 -1
- data/GNUmakefile +121 -56
- data/HACKING +1 -2
- data/ISSUES +40 -41
- data/KNOWN_ISSUES +11 -11
- data/LICENSE +2 -2
- data/Links +24 -25
- data/PHILOSOPHY +0 -6
- data/README +46 -39
- data/SIGNALS +2 -2
- data/Sandbox +10 -9
- data/TODO +0 -2
- data/TUNING +30 -9
- data/archive/slrnpull.conf +1 -1
- data/bin/unicorn +4 -2
- data/bin/unicorn_rails +3 -3
- data/examples/big_app_gc.rb +1 -1
- data/examples/init.sh +36 -8
- data/examples/logrotate.conf +17 -2
- data/examples/nginx.conf +14 -14
- data/examples/unicorn.conf.minimal.rb +2 -2
- data/examples/unicorn.conf.rb +3 -6
- data/examples/unicorn.socket +11 -0
- data/examples/unicorn@.service +40 -0
- data/ext/unicorn_http/common_field_optimization.h +23 -5
- data/ext/unicorn_http/ext_help.h +0 -20
- data/ext/unicorn_http/extconf.rb +37 -1
- data/ext/unicorn_http/global_variables.h +1 -1
- data/ext/unicorn_http/httpdate.c +2 -2
- data/ext/unicorn_http/unicorn_http.rl +167 -170
- data/ext/unicorn_http/unicorn_http_common.rl +1 -1
- data/lib/unicorn.rb +66 -46
- data/lib/unicorn/configurator.rb +110 -44
- data/lib/unicorn/const.rb +2 -25
- data/lib/unicorn/http_request.rb +110 -31
- data/lib/unicorn/http_response.rb +17 -31
- data/lib/unicorn/http_server.rb +238 -157
- data/lib/unicorn/launcher.rb +1 -1
- data/lib/unicorn/oob_gc.rb +6 -6
- data/lib/unicorn/socket_helper.rb +58 -78
- data/lib/unicorn/stream_input.rb +8 -7
- data/lib/unicorn/tee_input.rb +8 -10
- data/lib/unicorn/tmpio.rb +8 -7
- data/lib/unicorn/util.rb +5 -4
- data/lib/unicorn/worker.rb +36 -23
- data/t/GNUmakefile +3 -72
- data/t/README +4 -4
- data/t/t0011-active-unix-socket.sh +1 -1
- data/t/t0012-reload-empty-config.sh +2 -1
- data/t/t0301-no-default-middleware-ignored-in-config.sh +25 -0
- data/t/t0301.ru +13 -0
- data/t/test-lib.sh +2 -2
- data/test/benchmark/README +14 -4
- data/test/benchmark/ddstream.ru +50 -0
- data/test/benchmark/readinput.ru +40 -0
- data/test/benchmark/uconnect.perl +66 -0
- data/test/exec/test_exec.rb +73 -19
- data/test/test_helper.rb +40 -31
- data/test/unit/test_ccc.rb +91 -0
- data/test/unit/test_droplet.rb +1 -1
- data/test/unit/test_http_parser.rb +46 -16
- data/test/unit/test_http_parser_ng.rb +97 -114
- data/test/unit/test_request.rb +10 -10
- data/test/unit/test_response.rb +28 -16
- data/test/unit/test_server.rb +86 -12
- data/test/unit/test_signals.rb +8 -8
- data/test/unit/test_socket_helper.rb +14 -10
- data/test/unit/test_upload.rb +9 -14
- data/test/unit/test_util.rb +27 -2
- data/unicorn.gemspec +27 -19
- metadata +24 -45
- data/Documentation/GNUmakefile +0 -30
- data/Documentation/unicorn.1.txt +0 -185
- data/Documentation/unicorn_rails.1.txt +0 -175
- data/examples/git.ru +0 -13
- data/lib/unicorn/app/exec_cgi.rb +0 -154
- data/lib/unicorn/app/inetd.rb +0 -109
- data/lib/unicorn/ssl_client.rb +0 -11
- data/lib/unicorn/ssl_configurator.rb +0 -104
- data/lib/unicorn/ssl_server.rb +0 -42
- data/t/hijack.ru +0 -42
- data/t/t0016-trust-x-forwarded-false.sh +0 -30
- data/t/t0017-trust-x-forwarded-true.sh +0 -30
- data/t/t0200-rack-hijack.sh +0 -27
- data/test/unit/test_http_parser_xftrust.rb +0 -38
- data/test/unit/test_sni_hostnames.rb +0 -47
data/lib/unicorn/ssl_client.rb
DELETED
@@ -1,11 +0,0 @@
|
|
1
|
-
# -*- encoding: binary -*-
|
2
|
-
# :stopdoc:
|
3
|
-
class Unicorn::SSLClient < Kgio::SSL
|
4
|
-
alias write kgio_write
|
5
|
-
alias close kgio_close
|
6
|
-
|
7
|
-
# this is no-op for now, to be fixed in kgio-monkey if people care
|
8
|
-
# about SSL support...
|
9
|
-
def shutdown(how = nil)
|
10
|
-
end
|
11
|
-
end
|
@@ -1,104 +0,0 @@
|
|
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 unicorn-public@bogomips.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
|
data/lib/unicorn/ssl_server.rb
DELETED
@@ -1,42 +0,0 @@
|
|
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/t/hijack.ru
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
use Rack::Lint
|
2
|
-
use Rack::ContentLength
|
3
|
-
use Rack::ContentType, "text/plain"
|
4
|
-
class DieIfUsed
|
5
|
-
def each
|
6
|
-
abort "body.each called after response hijack\n"
|
7
|
-
end
|
8
|
-
|
9
|
-
def close
|
10
|
-
abort "body.close called after response hijack\n"
|
11
|
-
end
|
12
|
-
end
|
13
|
-
run lambda { |env|
|
14
|
-
case env["PATH_INFO"]
|
15
|
-
when "/hijack_req"
|
16
|
-
if env["rack.hijack?"]
|
17
|
-
io = env["rack.hijack"].call
|
18
|
-
if io.respond_to?(:read_nonblock) &&
|
19
|
-
env["rack.hijack_io"].respond_to?(:read_nonblock)
|
20
|
-
|
21
|
-
# exercise both, since we Rack::Lint may use different objects
|
22
|
-
env["rack.hijack_io"].write("HTTP/1.0 200 OK\r\n\r\n")
|
23
|
-
io.write("request.hijacked")
|
24
|
-
io.close
|
25
|
-
return [ 500, {}, DieIfUsed.new ]
|
26
|
-
end
|
27
|
-
end
|
28
|
-
[ 500, {}, [ "hijack BAD\n" ] ]
|
29
|
-
when "/hijack_res"
|
30
|
-
r = "response.hijacked"
|
31
|
-
[ 200,
|
32
|
-
{
|
33
|
-
"Content-Length" => r.bytesize.to_s,
|
34
|
-
"rack.hijack" => proc do |io|
|
35
|
-
io.write(r)
|
36
|
-
io.close
|
37
|
-
end
|
38
|
-
},
|
39
|
-
DieIfUsed.new
|
40
|
-
]
|
41
|
-
end
|
42
|
-
}
|
@@ -1,30 +0,0 @@
|
|
1
|
-
#!/bin/sh
|
2
|
-
. ./test-lib.sh
|
3
|
-
t_plan 5 "trust_x_forwarded=false configuration test"
|
4
|
-
|
5
|
-
t_begin "setup and start" && {
|
6
|
-
unicorn_setup
|
7
|
-
echo "trust_x_forwarded false" >> $unicorn_config
|
8
|
-
unicorn -D -c $unicorn_config env.ru
|
9
|
-
unicorn_wait_start
|
10
|
-
}
|
11
|
-
|
12
|
-
t_begin "spoofed request with X-Forwarded-Proto does not trigger" && {
|
13
|
-
curl -H 'X-Forwarded-Proto: https' http://$listen/ | \
|
14
|
-
grep -F '"rack.url_scheme"=>"http"'
|
15
|
-
}
|
16
|
-
|
17
|
-
t_begin "spoofed request with X-Forwarded-SSL does not trigger" && {
|
18
|
-
curl -H 'X-Forwarded-SSL: on' http://$listen/ | \
|
19
|
-
grep -F '"rack.url_scheme"=>"http"'
|
20
|
-
}
|
21
|
-
|
22
|
-
t_begin "killing succeeds" && {
|
23
|
-
kill $unicorn_pid
|
24
|
-
}
|
25
|
-
|
26
|
-
t_begin "check stderr has no errors" && {
|
27
|
-
check_stderr
|
28
|
-
}
|
29
|
-
|
30
|
-
t_done
|
@@ -1,30 +0,0 @@
|
|
1
|
-
#!/bin/sh
|
2
|
-
. ./test-lib.sh
|
3
|
-
t_plan 5 "trust_x_forwarded=true configuration test"
|
4
|
-
|
5
|
-
t_begin "setup and start" && {
|
6
|
-
unicorn_setup
|
7
|
-
echo "trust_x_forwarded true " >> $unicorn_config
|
8
|
-
unicorn -D -c $unicorn_config env.ru
|
9
|
-
unicorn_wait_start
|
10
|
-
}
|
11
|
-
|
12
|
-
t_begin "spoofed request with X-Forwarded-Proto sets 'https'" && {
|
13
|
-
curl -H 'X-Forwarded-Proto: https' http://$listen/ | \
|
14
|
-
grep -F '"rack.url_scheme"=>"https"'
|
15
|
-
}
|
16
|
-
|
17
|
-
t_begin "spoofed request with X-Forwarded-SSL sets 'https'" && {
|
18
|
-
curl -H 'X-Forwarded-SSL: on' http://$listen/ | \
|
19
|
-
grep -F '"rack.url_scheme"=>"https"'
|
20
|
-
}
|
21
|
-
|
22
|
-
t_begin "killing succeeds" && {
|
23
|
-
kill $unicorn_pid
|
24
|
-
}
|
25
|
-
|
26
|
-
t_begin "check stderr has no errors" && {
|
27
|
-
check_stderr
|
28
|
-
}
|
29
|
-
|
30
|
-
t_done
|
data/t/t0200-rack-hijack.sh
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
#!/bin/sh
|
2
|
-
. ./test-lib.sh
|
3
|
-
t_plan 5 "rack.hijack tests (Rack 1.5+ (Rack::VERSION >= [ 1,2]))"
|
4
|
-
|
5
|
-
t_begin "setup and start" && {
|
6
|
-
unicorn_setup
|
7
|
-
unicorn -D -c $unicorn_config hijack.ru
|
8
|
-
unicorn_wait_start
|
9
|
-
}
|
10
|
-
|
11
|
-
t_begin "check request hijack" && {
|
12
|
-
test "xrequest.hijacked" = x"$(curl -sSfv http://$listen/hijack_req)"
|
13
|
-
}
|
14
|
-
|
15
|
-
t_begin "check response hijack" && {
|
16
|
-
test "xresponse.hijacked" = x"$(curl -sSfv http://$listen/hijack_res)"
|
17
|
-
}
|
18
|
-
|
19
|
-
t_begin "killing succeeds" && {
|
20
|
-
kill $unicorn_pid
|
21
|
-
}
|
22
|
-
|
23
|
-
t_begin "check stderr" && {
|
24
|
-
check_stderr
|
25
|
-
}
|
26
|
-
|
27
|
-
t_done
|
@@ -1,38 +0,0 @@
|
|
1
|
-
# -*- encoding: binary -*-
|
2
|
-
require './test/test_helper'
|
3
|
-
|
4
|
-
include Unicorn
|
5
|
-
|
6
|
-
class HttpParserXFTrustTest < Test::Unit::TestCase
|
7
|
-
def setup
|
8
|
-
assert HttpParser.trust_x_forwarded?
|
9
|
-
end
|
10
|
-
|
11
|
-
def test_xf_trust_false_xfp
|
12
|
-
HttpParser.trust_x_forwarded = false
|
13
|
-
parser = HttpParser.new
|
14
|
-
parser.buf << "GET / HTTP/1.1\r\nHost: foo:\r\n" \
|
15
|
-
"X-Forwarded-Proto: https\r\n\r\n"
|
16
|
-
env = parser.parse
|
17
|
-
assert_kind_of Hash, env
|
18
|
-
assert_equal 'foo', env['SERVER_NAME']
|
19
|
-
assert_equal '80', env['SERVER_PORT']
|
20
|
-
assert_equal 'http', env['rack.url_scheme']
|
21
|
-
end
|
22
|
-
|
23
|
-
def test_xf_trust_false_xfs
|
24
|
-
HttpParser.trust_x_forwarded = false
|
25
|
-
parser = HttpParser.new
|
26
|
-
parser.buf << "GET / HTTP/1.1\r\nHost: foo:\r\n" \
|
27
|
-
"X-Forwarded-SSL: on\r\n\r\n"
|
28
|
-
env = parser.parse
|
29
|
-
assert_kind_of Hash, env
|
30
|
-
assert_equal 'foo', env['SERVER_NAME']
|
31
|
-
assert_equal '80', env['SERVER_PORT']
|
32
|
-
assert_equal 'http', env['rack.url_scheme']
|
33
|
-
end
|
34
|
-
|
35
|
-
def teardown
|
36
|
-
HttpParser.trust_x_forwarded = true
|
37
|
-
end
|
38
|
-
end
|
@@ -1,47 +0,0 @@
|
|
1
|
-
# -*- encoding: binary -*-
|
2
|
-
require "test/unit"
|
3
|
-
require "unicorn"
|
4
|
-
|
5
|
-
# this tests an implementation detail, it may change so this test
|
6
|
-
# can be removed later.
|
7
|
-
class TestSniHostnames < Test::Unit::TestCase
|
8
|
-
include Unicorn::SSLServer
|
9
|
-
|
10
|
-
def setup
|
11
|
-
GC.start
|
12
|
-
end
|
13
|
-
|
14
|
-
def teardown
|
15
|
-
GC.start
|
16
|
-
end
|
17
|
-
|
18
|
-
def test_host_name_detect_one
|
19
|
-
app = Rack::Builder.new do
|
20
|
-
map "http://sni1.example.com/" do
|
21
|
-
use Rack::ContentLength
|
22
|
-
use Rack::ContentType, "text/plain"
|
23
|
-
run lambda { |env| [ 200, {}, [] ] }
|
24
|
-
end
|
25
|
-
end.to_app
|
26
|
-
hostnames = rack_sni_hostnames(app)
|
27
|
-
assert hostnames.include?("sni1.example.com")
|
28
|
-
end
|
29
|
-
|
30
|
-
def test_host_name_detect_multiple
|
31
|
-
app = Rack::Builder.new do
|
32
|
-
map "http://sni2.example.com/" do
|
33
|
-
use Rack::ContentLength
|
34
|
-
use Rack::ContentType, "text/plain"
|
35
|
-
run lambda { |env| [ 200, {}, [] ] }
|
36
|
-
end
|
37
|
-
map "http://sni3.example.com/" do
|
38
|
-
use Rack::ContentLength
|
39
|
-
use Rack::ContentType, "text/plain"
|
40
|
-
run lambda { |env| [ 200, {}, [] ] }
|
41
|
-
end
|
42
|
-
end.to_app
|
43
|
-
hostnames = rack_sni_hostnames(app)
|
44
|
-
assert hostnames.include?("sni2.example.com")
|
45
|
-
assert hostnames.include?("sni3.example.com")
|
46
|
-
end
|
47
|
-
end
|