unicorn 4.7.0 → 6.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (119) hide show
  1. checksums.yaml +7 -0
  2. data/.document +0 -1
  3. data/.gitattributes +5 -0
  4. data/.gitignore +2 -2
  5. data/.manifest +14 -21
  6. data/.olddoc.yml +22 -0
  7. data/Application_Timeouts +7 -7
  8. data/DESIGN +2 -4
  9. data/Documentation/.gitignore +1 -3
  10. data/Documentation/unicorn.1 +222 -0
  11. data/Documentation/unicorn_rails.1 +207 -0
  12. data/FAQ +23 -6
  13. data/GIT-VERSION-FILE +1 -1
  14. data/GIT-VERSION-GEN +1 -1
  15. data/GNUmakefile +139 -92
  16. data/HACKING +13 -28
  17. data/ISSUES +82 -19
  18. data/KNOWN_ISSUES +18 -18
  19. data/LATEST +22 -44
  20. data/LICENSE +2 -2
  21. data/Links +24 -22
  22. data/NEWS +729 -0
  23. data/PHILOSOPHY +0 -6
  24. data/README +50 -48
  25. data/Rakefile +0 -44
  26. data/SIGNALS +12 -3
  27. data/Sandbox +11 -10
  28. data/TODO +0 -2
  29. data/TUNING +30 -9
  30. data/archive/.gitignore +3 -0
  31. data/archive/slrnpull.conf +4 -0
  32. data/bin/unicorn +4 -2
  33. data/bin/unicorn_rails +3 -3
  34. data/examples/big_app_gc.rb +1 -1
  35. data/examples/init.sh +36 -8
  36. data/examples/logrotate.conf +17 -2
  37. data/examples/nginx.conf +14 -14
  38. data/examples/unicorn.conf.minimal.rb +2 -2
  39. data/examples/unicorn.conf.rb +14 -6
  40. data/examples/unicorn.socket +11 -0
  41. data/examples/unicorn@.service +40 -0
  42. data/ext/unicorn_http/common_field_optimization.h +23 -5
  43. data/ext/unicorn_http/ext_help.h +0 -20
  44. data/ext/unicorn_http/extconf.rb +37 -1
  45. data/ext/unicorn_http/global_variables.h +1 -1
  46. data/ext/unicorn_http/httpdate.c +2 -2
  47. data/ext/unicorn_http/unicorn_http.c +940 -644
  48. data/ext/unicorn_http/unicorn_http.rl +167 -170
  49. data/ext/unicorn_http/unicorn_http_common.rl +1 -1
  50. data/lib/unicorn/configurator.rb +110 -46
  51. data/lib/unicorn/const.rb +2 -25
  52. data/lib/unicorn/http_request.rb +110 -31
  53. data/lib/unicorn/http_response.rb +17 -31
  54. data/lib/unicorn/http_server.rb +292 -199
  55. data/lib/unicorn/launcher.rb +1 -1
  56. data/lib/unicorn/oob_gc.rb +16 -6
  57. data/lib/unicorn/socket_helper.rb +58 -78
  58. data/lib/unicorn/stream_input.rb +9 -11
  59. data/lib/unicorn/tee_input.rb +16 -11
  60. data/lib/unicorn/tmpio.rb +10 -6
  61. data/lib/unicorn/util.rb +5 -4
  62. data/lib/unicorn/version.rb +1 -1
  63. data/lib/unicorn/worker.rb +99 -22
  64. data/lib/unicorn.rb +69 -42
  65. data/man/man1/unicorn.1 +124 -122
  66. data/man/man1/unicorn_rails.1 +113 -127
  67. data/t/.gitignore +0 -1
  68. data/t/GNUmakefile +3 -80
  69. data/t/README +4 -4
  70. data/t/t0002-parser-error.sh +3 -3
  71. data/t/t0011-active-unix-socket.sh +1 -1
  72. data/t/t0012-reload-empty-config.sh +2 -1
  73. data/t/t0300-no-default-middleware.sh +6 -1
  74. data/t/t0301-no-default-middleware-ignored-in-config.sh +25 -0
  75. data/t/t0301.ru +13 -0
  76. data/t/test-lib.sh +2 -2
  77. data/test/benchmark/README +14 -4
  78. data/test/benchmark/ddstream.ru +50 -0
  79. data/test/benchmark/readinput.ru +40 -0
  80. data/test/benchmark/uconnect.perl +66 -0
  81. data/test/exec/test_exec.rb +74 -20
  82. data/test/test_helper.rb +42 -33
  83. data/test/unit/test_ccc.rb +91 -0
  84. data/test/unit/test_droplet.rb +1 -1
  85. data/test/unit/test_http_parser.rb +49 -19
  86. data/test/unit/test_http_parser_ng.rb +98 -115
  87. data/test/unit/test_request.rb +11 -11
  88. data/test/unit/test_response.rb +31 -19
  89. data/test/unit/test_server.rb +89 -15
  90. data/test/unit/test_signals.rb +9 -9
  91. data/test/unit/test_socket_helper.rb +20 -14
  92. data/test/unit/test_tee_input.rb +10 -0
  93. data/test/unit/test_upload.rb +10 -15
  94. data/test/unit/test_util.rb +28 -3
  95. data/unicorn.gemspec +28 -23
  96. data/unicorn_1 +1 -0
  97. data/unicorn_rails_1 +1 -0
  98. metadata +64 -134
  99. data/.wrongdoc.yml +0 -10
  100. data/ChangeLog +0 -4694
  101. data/Documentation/GNUmakefile +0 -30
  102. data/Documentation/unicorn.1.txt +0 -178
  103. data/Documentation/unicorn_rails.1.txt +0 -175
  104. data/examples/git.ru +0 -13
  105. data/lib/unicorn/app/exec_cgi.rb +0 -154
  106. data/lib/unicorn/app/inetd.rb +0 -109
  107. data/lib/unicorn/ssl_client.rb +0 -11
  108. data/lib/unicorn/ssl_configurator.rb +0 -104
  109. data/lib/unicorn/ssl_server.rb +0 -42
  110. data/local.mk.sample +0 -59
  111. data/script/isolate_for_tests +0 -32
  112. data/t/hijack.ru +0 -42
  113. data/t/sslgen.sh +0 -71
  114. data/t/t0016-trust-x-forwarded-false.sh +0 -30
  115. data/t/t0017-trust-x-forwarded-true.sh +0 -30
  116. data/t/t0200-rack-hijack.sh +0 -27
  117. data/t/t0600-https-server-basic.sh +0 -48
  118. data/test/unit/test_http_parser_xftrust.rb +0 -38
  119. 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
- # Unicorn or Rainbows! servers. Generally these configuration settings
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 neither
48
- # Unicorn nor Rainbows! is optimized for it at the moment
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 http://wiki.nginx.org/NginxHttpGzipModule
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 Unicorn/Rainbows!
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 Unicorn master nukes a
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
- # http://bogomips.org/unicorn.git/tree/examples/nginx.conf?id=v3.3.1#n127
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
- # http://en.wikipedia.org/wiki/X-Forwarded-For
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 "proxy_buffering off" *only* for Rainbows! when doing
136
- # Comet/long-poll/streaming. It's also safe to set if you're using
137
- # only serving fast clients with Unicorn + nginx, but not slow
138
- # clients. You normally want nginx to buffer responses to slow
139
- # clients, even with Rails 3.1 streaming because otherwise a slow
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 http://unicorn.bogomips.org/Unicorn/Configurator.html for complete
4
+ # See https://yhbt.net/unicorn/Unicorn/Configurator.html for complete
5
5
  # documentation.
6
- # See also http://unicorn.bogomips.org/examples/unicorn.conf.rb for
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
@@ -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
- # http://unicorn.bogomips.org/examples/unicorn.conf.minimal.rb
5
+ # https://yhbt.net/unicorn/examples/unicorn.conf.minimal.rb
6
6
  # for a much simpler configuration file.
7
7
  #
8
- # See http://unicorn.bogomips.org/Unicorn/Configurator.html for complete
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.0dev or REE with "preload_app true" for memory savings
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,11 @@
1
+ # ==> /etc/systemd/system/unicorn.socket <==
2
+ [Unit]
3
+ Description = unicorn sockets
4
+
5
+ [Socket]
6
+ ListenStream = 127.0.0.1:8080
7
+ ListenStream = /tmp/path/to/.unicorn.sock
8
+ Service = unicorn@1.service
9
+
10
+ [Install]
11
+ WantedBy = sockets.target
@@ -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 = rb_str_new(cf->name, cf->len);
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 = rb_str_new(tmp, HTTP_PREFIX_LEN + cf->len);
96
+ cf->value = str_new_dd_freeze(tmp, HTTP_PREFIX_LEN + cf->len);
78
97
  }
79
- cf->value = rb_obj_freeze(cf->value);
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 rb_obj_freeze(f);
126
+ return HASH_ASET_DEDUPE ? f : str_dd_freeze(f);
109
127
  }
110
128
 
111
129
  #endif /* common_field_optimization_h */
@@ -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")
@@ -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
- rb_global_variable(&g_##N); \
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.*/
@@ -66,11 +66,11 @@ static VALUE httpdate(VALUE self)
66
66
 
67
67
  void init_unicorn_httpdate(void)
68
68
  {
69
- VALUE mod = rb_const_get(rb_cObject, rb_intern("Unicorn"));
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
- rb_global_variable(&buf);
73
+ rb_gc_register_mark_object(buf);
74
74
  buf_ptr = RSTRING_PTR(buf);
75
75
  httpdate(Qnil);
76
76