unicorn 4.7.0 → 6.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.document +0 -1
- data/.gitattributes +5 -0
- data/.gitignore +2 -2
- data/.manifest +14 -21
- data/.olddoc.yml +22 -0
- 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 +23 -6
- data/GIT-VERSION-FILE +1 -1
- data/GIT-VERSION-GEN +1 -1
- data/GNUmakefile +139 -92
- data/HACKING +13 -28
- data/ISSUES +82 -19
- data/KNOWN_ISSUES +18 -18
- data/LATEST +22 -44
- data/LICENSE +2 -2
- data/Links +24 -22
- data/NEWS +729 -0
- data/PHILOSOPHY +0 -6
- data/README +50 -48
- data/Rakefile +0 -44
- data/SIGNALS +12 -3
- data/Sandbox +11 -10
- data/TODO +0 -2
- data/TUNING +30 -9
- data/archive/.gitignore +3 -0
- data/archive/slrnpull.conf +4 -0
- 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 +14 -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.c +940 -644
- data/ext/unicorn_http/unicorn_http.rl +167 -170
- data/ext/unicorn_http/unicorn_http_common.rl +1 -1
- data/lib/unicorn/configurator.rb +110 -46
- 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 +292 -199
- data/lib/unicorn/launcher.rb +1 -1
- data/lib/unicorn/oob_gc.rb +16 -6
- data/lib/unicorn/socket_helper.rb +58 -78
- data/lib/unicorn/stream_input.rb +9 -11
- data/lib/unicorn/tee_input.rb +16 -11
- data/lib/unicorn/tmpio.rb +10 -6
- data/lib/unicorn/util.rb +5 -4
- data/lib/unicorn/version.rb +1 -1
- data/lib/unicorn/worker.rb +99 -22
- data/lib/unicorn.rb +69 -42
- data/man/man1/unicorn.1 +124 -122
- data/man/man1/unicorn_rails.1 +113 -127
- data/t/.gitignore +0 -1
- data/t/GNUmakefile +3 -80
- data/t/README +4 -4
- data/t/t0002-parser-error.sh +3 -3
- data/t/t0011-active-unix-socket.sh +1 -1
- data/t/t0012-reload-empty-config.sh +2 -1
- data/t/t0300-no-default-middleware.sh +6 -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 +74 -20
- data/test/test_helper.rb +42 -33
- data/test/unit/test_ccc.rb +91 -0
- data/test/unit/test_droplet.rb +1 -1
- data/test/unit/test_http_parser.rb +49 -19
- data/test/unit/test_http_parser_ng.rb +98 -115
- data/test/unit/test_request.rb +11 -11
- data/test/unit/test_response.rb +31 -19
- data/test/unit/test_server.rb +89 -15
- data/test/unit/test_signals.rb +9 -9
- data/test/unit/test_socket_helper.rb +20 -14
- data/test/unit/test_tee_input.rb +10 -0
- data/test/unit/test_upload.rb +10 -15
- data/test/unit/test_util.rb +28 -3
- data/unicorn.gemspec +28 -23
- data/unicorn_1 +1 -0
- data/unicorn_rails_1 +1 -0
- metadata +64 -134
- data/.wrongdoc.yml +0 -10
- data/ChangeLog +0 -4694
- data/Documentation/GNUmakefile +0 -30
- data/Documentation/unicorn.1.txt +0 -178
- 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/local.mk.sample +0 -59
- data/script/isolate_for_tests +0 -32
- data/t/hijack.ru +0 -42
- data/t/sslgen.sh +0 -71
- 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/t/t0600-https-server-basic.sh +0 -48
- data/test/unit/test_http_parser_xftrust.rb +0 -38
- data/test/unit/test_sni_hostnames.rb +0 -47
data/examples/nginx.conf
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# This is example contains the bare mininum to get nginx going with
|
2
|
-
#
|
2
|
+
# unicorn servers. Generally these configuration settings
|
3
3
|
# are applicable to other HTTP application servers (and not just Ruby
|
4
4
|
# ones), so if you have one working well for proxying another app
|
5
5
|
# server, feel free to continue using it.
|
@@ -44,8 +44,8 @@ http {
|
|
44
44
|
# click tracking!
|
45
45
|
access_log /path/to/nginx.access.log combined;
|
46
46
|
|
47
|
-
# you generally want to serve static files with nginx since
|
48
|
-
#
|
47
|
+
# you generally want to serve static files with nginx since
|
48
|
+
# unicorn is not and will never be optimized for it
|
49
49
|
sendfile on;
|
50
50
|
|
51
51
|
tcp_nopush on; # off may be better for *some* Comet/long-poll stuff
|
@@ -56,7 +56,8 @@ http {
|
|
56
56
|
# to configure it all in one place here for static files and also
|
57
57
|
# to disable gzip for clients who don't get gzip/deflate right.
|
58
58
|
# There are other gzip settings that may be needed used to deal with
|
59
|
-
# bad clients out there, see
|
59
|
+
# bad clients out there, see
|
60
|
+
# https://nginx.org/en/docs/http/ngx_http_gzip_module.html
|
60
61
|
gzip on;
|
61
62
|
gzip_http_version 1.0;
|
62
63
|
gzip_proxied any;
|
@@ -67,10 +68,10 @@ http {
|
|
67
68
|
text/javascript application/x-javascript
|
68
69
|
application/atom+xml;
|
69
70
|
|
70
|
-
# this can be any application server, not just
|
71
|
+
# this can be any application server, not just unicorn
|
71
72
|
upstream app_server {
|
72
73
|
# fail_timeout=0 means we always retry an upstream even if it failed
|
73
|
-
# to return a good HTTP response (in case the
|
74
|
+
# to return a good HTTP response (in case the unicorn master nukes a
|
74
75
|
# single worker for timing out).
|
75
76
|
|
76
77
|
# for UNIX domain socket setups:
|
@@ -112,12 +113,12 @@ http {
|
|
112
113
|
# try_files directive appeared in in nginx 0.7.27 and has stabilized
|
113
114
|
# over time. Older versions of nginx (e.g. 0.6.x) requires
|
114
115
|
# "if (!-f $request_filename)" which was less efficient:
|
115
|
-
#
|
116
|
+
# https://yhbt.net/unicorn.git/tree/examples/nginx.conf?id=v3.3.1#n127
|
116
117
|
try_files $uri/index.html $uri.html $uri @app;
|
117
118
|
|
118
119
|
location @app {
|
119
120
|
# an HTTP header important enough to have its own Wikipedia entry:
|
120
|
-
#
|
121
|
+
# https://en.wikipedia.org/wiki/X-Forwarded-For
|
121
122
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
122
123
|
|
123
124
|
# enable this if you forward HTTPS traffic to unicorn,
|
@@ -132,12 +133,11 @@ http {
|
|
132
133
|
# redirects, we set the Host: header above already.
|
133
134
|
proxy_redirect off;
|
134
135
|
|
135
|
-
# set
|
136
|
-
#
|
137
|
-
#
|
138
|
-
#
|
139
|
-
#
|
140
|
-
# client can become a bottleneck of Unicorn.
|
136
|
+
# It's also safe to set if you're using only serving fast clients
|
137
|
+
# with unicorn + nginx, but not slow clients. You normally want
|
138
|
+
# nginx to buffer responses to slow clients, even with Rails 3.1
|
139
|
+
# streaming because otherwise a slow client can become a bottleneck
|
140
|
+
# of unicorn.
|
141
141
|
#
|
142
142
|
# The Rack application may also set "X-Accel-Buffering (yes|no)"
|
143
143
|
# in the response headers do disable/enable buffering on a
|
@@ -1,9 +1,9 @@
|
|
1
1
|
# Minimal sample configuration file for Unicorn (not Rack) when used
|
2
2
|
# with daemonization (unicorn -D) started in your working directory.
|
3
3
|
#
|
4
|
-
# See
|
4
|
+
# See https://yhbt.net/unicorn/Unicorn/Configurator.html for complete
|
5
5
|
# documentation.
|
6
|
-
# See also
|
6
|
+
# See also https://yhbt.net/unicorn/examples/unicorn.conf.rb for
|
7
7
|
# a more verbose configuration using more features.
|
8
8
|
|
9
9
|
listen 2007 # by default Unicorn listens on port 8080
|
data/examples/unicorn.conf.rb
CHANGED
@@ -2,10 +2,10 @@
|
|
2
2
|
#
|
3
3
|
# This configuration file documents many features of Unicorn
|
4
4
|
# that may not be needed for some applications. See
|
5
|
-
#
|
5
|
+
# https://yhbt.net/unicorn/examples/unicorn.conf.minimal.rb
|
6
6
|
# for a much simpler configuration file.
|
7
7
|
#
|
8
|
-
# See
|
8
|
+
# See https://yhbt.net/unicorn/Unicorn/Configurator.html for complete
|
9
9
|
# documentation.
|
10
10
|
|
11
11
|
# Use at least one worker per core if you're on a dedicated server,
|
@@ -40,11 +40,8 @@ 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 Ruby 2.0.
|
44
|
-
# http://rubyenterpriseedition.com/faq.html#adapt_apps_for_cow
|
43
|
+
# combine Ruby 2.0.0+ with "preload_app true" for memory savings
|
45
44
|
preload_app true
|
46
|
-
GC.respond_to?(:copy_on_write_friendly=) and
|
47
|
-
GC.copy_on_write_friendly = true
|
48
45
|
|
49
46
|
# Enable this flag to have unicorn test client connections by writing the
|
50
47
|
# beginning of the HTTP headers before calling the application. This
|
@@ -54,12 +51,23 @@ GC.respond_to?(:copy_on_write_friendly=) and
|
|
54
51
|
# fast LAN.
|
55
52
|
check_client_connection false
|
56
53
|
|
54
|
+
# local variable to guard against running a hook multiple times
|
55
|
+
run_once = true
|
56
|
+
|
57
57
|
before_fork do |server, worker|
|
58
58
|
# the following is highly recomended for Rails + "preload_app true"
|
59
59
|
# as there's no need for the master process to hold a connection
|
60
60
|
defined?(ActiveRecord::Base) and
|
61
61
|
ActiveRecord::Base.connection.disconnect!
|
62
62
|
|
63
|
+
# Occasionally, it may be necessary to run non-idempotent code in the
|
64
|
+
# master before forking. Keep in mind the above disconnect! example
|
65
|
+
# is idempotent and does not need a guard.
|
66
|
+
if run_once
|
67
|
+
# do_something_once_here ...
|
68
|
+
run_once = false # prevent from firing again
|
69
|
+
end
|
70
|
+
|
63
71
|
# The following is only recommended for memory/DB-constrained
|
64
72
|
# installations. It is not needed if your system can house
|
65
73
|
# twice as many worker_processes as you have configured.
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# ==> /etc/systemd/system/unicorn@.service <==
|
2
|
+
# Since SIGUSR2 upgrades do not work under systemd, this service file
|
3
|
+
# allows starting two simultaneous services during upgrade time
|
4
|
+
# (e.g. unicorn@1 unicorn@2) with the intention that they take
|
5
|
+
# turns running in-between upgrades. This should allow upgrading
|
6
|
+
# without downtime.
|
7
|
+
|
8
|
+
[Unit]
|
9
|
+
Description = unicorn Rack application server %i
|
10
|
+
Wants = unicorn.socket
|
11
|
+
After = unicorn.socket
|
12
|
+
|
13
|
+
[Service]
|
14
|
+
# bundler users must use the "--keep-file-descriptors" switch, here:
|
15
|
+
# ExecStart = bundle exec --keep-file-descriptors unicorn -c ...
|
16
|
+
ExecStart = /usr/bin/unicorn -c /path/to/unicorn.conf.rb /path/to/config.ru
|
17
|
+
|
18
|
+
# NonBlocking MUST be true if using socket activation with unicorn.
|
19
|
+
# Otherwise, there's a small window in-between when the non-blocking
|
20
|
+
# flag is set by us and our accept4 call where systemd can momentarily
|
21
|
+
# make the socket blocking, causing us to block on accept4:
|
22
|
+
NonBlocking = true
|
23
|
+
Sockets = unicorn.socket
|
24
|
+
|
25
|
+
KillSignal = SIGQUIT
|
26
|
+
User = nobody
|
27
|
+
Group = nogroup
|
28
|
+
ExecReload = /bin/kill -HUP $MAINPID
|
29
|
+
|
30
|
+
# This is based on the Unicorn::Configurator#timeout directive,
|
31
|
+
# adding a few seconds for scheduling differences:
|
32
|
+
TimeoutStopSec = 62
|
33
|
+
|
34
|
+
# Only kill the master process, it may be harmful to signal
|
35
|
+
# workers via default "control-group" setting since some
|
36
|
+
# Ruby extensions and applications misbehave on interrupts
|
37
|
+
KillMode = process
|
38
|
+
|
39
|
+
[Install]
|
40
|
+
WantedBy = multi-user.target
|
@@ -58,6 +58,23 @@ static struct common_field common_http_fields[] = {
|
|
58
58
|
|
59
59
|
#define HTTP_PREFIX "HTTP_"
|
60
60
|
#define HTTP_PREFIX_LEN (sizeof(HTTP_PREFIX) - 1)
|
61
|
+
static ID id_uminus;
|
62
|
+
|
63
|
+
/* this dedupes under Ruby 2.5+ (December 2017) */
|
64
|
+
static VALUE str_dd_freeze(VALUE str)
|
65
|
+
{
|
66
|
+
if (STR_UMINUS_DEDUPE)
|
67
|
+
return rb_funcall(str, id_uminus, 0);
|
68
|
+
|
69
|
+
/* freeze,since it speeds up older MRI slightly */
|
70
|
+
OBJ_FREEZE(str);
|
71
|
+
return str;
|
72
|
+
}
|
73
|
+
|
74
|
+
static VALUE str_new_dd_freeze(const char *ptr, long len)
|
75
|
+
{
|
76
|
+
return str_dd_freeze(rb_str_new(ptr, len));
|
77
|
+
}
|
61
78
|
|
62
79
|
/* this function is not performance-critical, called only at load time */
|
63
80
|
static void init_common_fields(void)
|
@@ -65,19 +82,20 @@ static void init_common_fields(void)
|
|
65
82
|
int i;
|
66
83
|
struct common_field *cf = common_http_fields;
|
67
84
|
char tmp[64];
|
85
|
+
|
86
|
+
id_uminus = rb_intern("-@");
|
68
87
|
memcpy(tmp, HTTP_PREFIX, HTTP_PREFIX_LEN);
|
69
88
|
|
70
89
|
for(i = ARRAY_SIZE(common_http_fields); --i >= 0; cf++) {
|
71
90
|
/* Rack doesn't like certain headers prefixed with "HTTP_" */
|
72
91
|
if (!strcmp("CONTENT_LENGTH", cf->name) ||
|
73
92
|
!strcmp("CONTENT_TYPE", cf->name)) {
|
74
|
-
cf->value =
|
93
|
+
cf->value = str_new_dd_freeze(cf->name, cf->len);
|
75
94
|
} else {
|
76
95
|
memcpy(tmp + HTTP_PREFIX_LEN, cf->name, cf->len + 1);
|
77
|
-
cf->value =
|
96
|
+
cf->value = str_new_dd_freeze(tmp, HTTP_PREFIX_LEN + cf->len);
|
78
97
|
}
|
79
|
-
|
80
|
-
rb_global_variable(&cf->value);
|
98
|
+
rb_gc_register_mark_object(cf->value);
|
81
99
|
}
|
82
100
|
}
|
83
101
|
|
@@ -105,7 +123,7 @@ static VALUE uncommon_field(const char *field, size_t flen)
|
|
105
123
|
memcpy(RSTRING_PTR(f) + HTTP_PREFIX_LEN, field, flen);
|
106
124
|
assert(*(RSTRING_PTR(f) + RSTRING_LEN(f)) == '\0' &&
|
107
125
|
"string didn't end with \\0"); /* paranoia */
|
108
|
-
return
|
126
|
+
return HASH_ASET_DEDUPE ? f : str_dd_freeze(f);
|
109
127
|
}
|
110
128
|
|
111
129
|
#endif /* common_field_optimization_h */
|
data/ext/unicorn_http/ext_help.h
CHANGED
@@ -1,26 +1,6 @@
|
|
1
1
|
#ifndef ext_help_h
|
2
2
|
#define ext_help_h
|
3
3
|
|
4
|
-
#ifndef RSTRING_PTR
|
5
|
-
#define RSTRING_PTR(s) (RSTRING(s)->ptr)
|
6
|
-
#endif /* !defined(RSTRING_PTR) */
|
7
|
-
#ifndef RSTRING_LEN
|
8
|
-
#define RSTRING_LEN(s) (RSTRING(s)->len)
|
9
|
-
#endif /* !defined(RSTRING_LEN) */
|
10
|
-
|
11
|
-
#ifndef HAVE_RB_STR_SET_LEN
|
12
|
-
# ifdef RUBINIUS
|
13
|
-
# error we should never get here with current Rubinius (1.x)
|
14
|
-
# endif
|
15
|
-
/* this is taken from Ruby 1.8.7, 1.8.6 may not have it */
|
16
|
-
static void rb_18_str_set_len(VALUE str, long len)
|
17
|
-
{
|
18
|
-
RSTRING(str)->len = len;
|
19
|
-
RSTRING(str)->ptr[len] = '\0';
|
20
|
-
}
|
21
|
-
# define rb_str_set_len(str,len) rb_18_str_set_len(str,len)
|
22
|
-
#endif /* !defined(HAVE_RB_STR_SET_LEN) */
|
23
|
-
|
24
4
|
/* not all Ruby implementations support frozen objects (Rubinius does not) */
|
25
5
|
#if defined(OBJ_FROZEN)
|
26
6
|
# define assert_frozen(f) assert(OBJ_FROZEN(f) && "unfrozen object")
|
data/ext/unicorn_http/extconf.rb
CHANGED
@@ -1,10 +1,46 @@
|
|
1
1
|
# -*- encoding: binary -*-
|
2
2
|
require 'mkmf'
|
3
3
|
|
4
|
+
unless RUBY_VERSION < '3.1'
|
5
|
+
warn "Unicorn was only tested against MRI up to 3.0.\n" \
|
6
|
+
"It might not properly work with #{RUBY_VERSION}"
|
7
|
+
end
|
8
|
+
|
4
9
|
have_macro("SIZEOF_OFF_T", "ruby.h") or check_sizeof("off_t", "sys/types.h")
|
5
10
|
have_macro("SIZEOF_SIZE_T", "ruby.h") or check_sizeof("size_t", "sys/types.h")
|
6
11
|
have_macro("SIZEOF_LONG", "ruby.h") or check_sizeof("long", "sys/types.h")
|
7
|
-
have_func("rb_str_set_len", "ruby.h")
|
12
|
+
have_func("rb_str_set_len", "ruby.h") or abort 'Ruby 1.9.3+ required'
|
13
|
+
have_func("rb_hash_clear", "ruby.h") # Ruby 2.0+
|
8
14
|
have_func("gmtime_r", "time.h")
|
9
15
|
|
16
|
+
message('checking if String#-@ (str_uminus) dedupes... ')
|
17
|
+
begin
|
18
|
+
a = -(%w(t e s t).join)
|
19
|
+
b = -(%w(t e s t).join)
|
20
|
+
if a.equal?(b)
|
21
|
+
$CPPFLAGS += ' -DSTR_UMINUS_DEDUPE=1 '
|
22
|
+
message("yes\n")
|
23
|
+
else
|
24
|
+
$CPPFLAGS += ' -DSTR_UMINUS_DEDUPE=0 '
|
25
|
+
message("no, needs Ruby 2.5+\n")
|
26
|
+
end
|
27
|
+
rescue NoMethodError
|
28
|
+
$CPPFLAGS += ' -DSTR_UMINUS_DEDUPE=0 '
|
29
|
+
message("no, String#-@ not available\n")
|
30
|
+
end
|
31
|
+
|
32
|
+
message('checking if Hash#[]= (rb_hash_aset) dedupes... ')
|
33
|
+
h = {}
|
34
|
+
x = {}
|
35
|
+
r = rand.to_s
|
36
|
+
h[%W(#{r}).join('')] = :foo
|
37
|
+
x[%W(#{r}).join('')] = :foo
|
38
|
+
if x.keys[0].equal?(h.keys[0])
|
39
|
+
$CPPFLAGS += ' -DHASH_ASET_DEDUPE=1 '
|
40
|
+
message("yes\n")
|
41
|
+
else
|
42
|
+
$CPPFLAGS += ' -DHASH_ASET_DEDUPE=0 '
|
43
|
+
message("no, needs Ruby 2.6+\n")
|
44
|
+
end
|
45
|
+
|
10
46
|
create_makefile("unicorn_http")
|
@@ -56,7 +56,7 @@ NORETURN(static void parser_raise(VALUE klass, const char *));
|
|
56
56
|
/** Defines global strings in the init method. */
|
57
57
|
#define DEF_GLOBAL(N, val) do { \
|
58
58
|
g_##N = rb_obj_freeze(rb_str_new(val, sizeof(val) - 1)); \
|
59
|
-
|
59
|
+
rb_gc_register_mark_object(g_##N); \
|
60
60
|
} while (0)
|
61
61
|
|
62
62
|
/* Defines the maximum allowed lengths for various input elements.*/
|
data/ext/unicorn_http/httpdate.c
CHANGED
@@ -66,11 +66,11 @@ static VALUE httpdate(VALUE self)
|
|
66
66
|
|
67
67
|
void init_unicorn_httpdate(void)
|
68
68
|
{
|
69
|
-
VALUE mod =
|
69
|
+
VALUE mod = rb_define_module("Unicorn");
|
70
70
|
mod = rb_define_module_under(mod, "HttpResponse");
|
71
71
|
|
72
72
|
buf = rb_str_new(0, buf_capa - 1);
|
73
|
-
|
73
|
+
rb_gc_register_mark_object(buf);
|
74
74
|
buf_ptr = RSTRING_PTR(buf);
|
75
75
|
httpdate(Qnil);
|
76
76
|
|