unicorn 5.5.0 → 6.0.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.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.olddoc.yml +12 -7
  3. data/Documentation/.gitignore +1 -3
  4. data/Documentation/unicorn.1 +222 -0
  5. data/Documentation/unicorn_rails.1 +207 -0
  6. data/FAQ +1 -1
  7. data/GIT-VERSION-GEN +1 -1
  8. data/GNUmakefile +112 -57
  9. data/HACKING +1 -1
  10. data/ISSUES +16 -21
  11. data/KNOWN_ISSUES +2 -2
  12. data/Links +5 -5
  13. data/README +13 -6
  14. data/SIGNALS +1 -1
  15. data/Sandbox +2 -2
  16. data/archive/slrnpull.conf +1 -1
  17. data/bin/unicorn_rails +2 -2
  18. data/examples/big_app_gc.rb +1 -1
  19. data/examples/logrotate.conf +2 -2
  20. data/examples/nginx.conf +1 -1
  21. data/examples/unicorn.conf.minimal.rb +2 -2
  22. data/examples/unicorn.conf.rb +2 -2
  23. data/examples/unicorn@.service +7 -0
  24. data/ext/unicorn_http/extconf.rb +5 -0
  25. data/ext/unicorn_http/unicorn_http.rl +43 -5
  26. data/lib/unicorn.rb +4 -1
  27. data/lib/unicorn/configurator.rb +13 -3
  28. data/lib/unicorn/http_request.rb +11 -1
  29. data/lib/unicorn/http_server.rb +37 -5
  30. data/lib/unicorn/oob_gc.rb +5 -5
  31. data/lib/unicorn/tmpio.rb +8 -2
  32. data/t/GNUmakefile +3 -72
  33. data/test/benchmark/README +14 -4
  34. data/test/benchmark/ddstream.ru +50 -0
  35. data/test/benchmark/readinput.ru +40 -0
  36. data/test/benchmark/uconnect.perl +66 -0
  37. data/test/exec/test_exec.rb +14 -12
  38. data/test/test_helper.rb +38 -30
  39. data/test/unit/test_ccc.rb +4 -3
  40. data/test/unit/test_http_parser_ng.rb +81 -0
  41. data/test/unit/test_server.rb +81 -7
  42. data/test/unit/test_signals.rb +6 -6
  43. data/test/unit/test_socket_helper.rb +1 -1
  44. data/test/unit/test_upload.rb +9 -14
  45. data/test/unit/test_util.rb +1 -1
  46. data/unicorn.gemspec +8 -7
  47. metadata +12 -11
  48. data/Documentation/GNUmakefile +0 -30
  49. data/Documentation/unicorn.1.txt +0 -187
  50. data/Documentation/unicorn_rails.1.txt +0 -175
  51. data/t/hijack.ru +0 -55
  52. data/t/t0200-rack-hijack.sh +0 -51
data/Sandbox CHANGED
@@ -34,7 +34,7 @@ is the primary issue with sandboxing tools such as Bundler and Isolate.
34
34
  If you're bundling unicorn, use "bundle exec unicorn" (or "bundle exec
35
35
  unicorn_rails") to start unicorn with the correct environment variables
36
36
 
37
- ref: https://bogomips.org/unicorn-public/9ECF07C4-5216-47BE-961D-AFC0F0C82060@internetfamo.us/
37
+ ref: https://yhbt.net/unicorn-public/9ECF07C4-5216-47BE-961D-AFC0F0C82060@internetfamo.us/
38
38
 
39
39
  Otherwise (if you choose to not sandbox your unicorn installation), we
40
40
  expect the tips for Isolate (below) apply, too.
@@ -44,7 +44,7 @@ expect the tips for Isolate (below) apply, too.
44
44
  This is no longer be an issue as of bundler 0.9.17
45
45
 
46
46
  ref:
47
- https://bogomips.org/unicorn-public/8FC34B23-5994-41CC-B5AF-7198EF06909E@tramchase.com/
47
+ https://yhbt.net/unicorn-public/8FC34B23-5994-41CC-B5AF-7198EF06909E@tramchase.com/
48
48
 
49
49
  === BUNDLE_GEMFILE for Capistrano users
50
50
 
@@ -1,4 +1,4 @@
1
1
  # group_name max expire headers_only
2
2
  gmane.comp.lang.ruby.unicorn.general 1000000000 1000000000 0
3
3
 
4
- # usage: slrnpull -d $PWD -h news.gmane.org --no-post
4
+ # usage: slrnpull -d $PWD -h news.gmane.io --no-post
data/bin/unicorn_rails CHANGED
@@ -132,11 +132,11 @@ def rails_builder(ru, op, daemonize)
132
132
 
133
133
  # this lambda won't run until after forking if preload_app is false
134
134
  # this runs after config file reloading
135
- lambda do ||
135
+ lambda do |x, server|
136
136
  # Rails 3 includes a config.ru, use it if we find it after
137
137
  # working_directory is bound.
138
138
  ::File.exist?('config.ru') and
139
- return Unicorn.builder('config.ru', op).call
139
+ return Unicorn.builder('config.ru', op).call(x, server)
140
140
 
141
141
  # Load Rails and (possibly) the private version of Rack it bundles.
142
142
  begin
@@ -1,2 +1,2 @@
1
- # see {Unicorn::OobGC}[https://bogomips.org/unicorn/Unicorn/OobGC.html]
1
+ # see {Unicorn::OobGC}[https://yhbt.net/unicorn/Unicorn/OobGC.html]
2
2
  # Unicorn::OobGC was broken in Unicorn v3.3.1 - v3.6.1 and fixed in v3.6.2
@@ -5,7 +5,7 @@
5
5
  # https://linux.die.net/man/8/logrotate
6
6
  #
7
7
  # public logrotate-related discussion in our archives:
8
- # https://bogomips.org/unicorn-public/?q=logrotate
8
+ # https://yhbt.net/unicorn-public/?q=logrotate
9
9
 
10
10
  # Modify the following glob to match the logfiles your app writes to:
11
11
  /var/log/unicorn_app/*.log {
@@ -33,7 +33,7 @@
33
33
  systemctl kill -s SIGUSR1 unicorn@2.service
34
34
 
35
35
  # Examples for other process management systems appreciated
36
- # Mail us at unicorn-public@bogomips.org
36
+ # Mail us at unicorn-public@yhbt.net
37
37
  # (see above for archives)
38
38
 
39
39
  # If you use a pid file and assuming your pid file
data/examples/nginx.conf CHANGED
@@ -113,7 +113,7 @@ http {
113
113
  # try_files directive appeared in in nginx 0.7.27 and has stabilized
114
114
  # over time. Older versions of nginx (e.g. 0.6.x) requires
115
115
  # "if (!-f $request_filename)" which was less efficient:
116
- # https://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
117
117
  try_files $uri/index.html $uri.html $uri @app;
118
118
 
119
119
  location @app {
@@ -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 https://bogomips.org/unicorn/Unicorn/Configurator.html for complete
4
+ # See https://yhbt.net/unicorn/Unicorn/Configurator.html for complete
5
5
  # documentation.
6
- # See also https://bogomips.org/unicorn/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
- # https://bogomips.org/unicorn/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 https://bogomips.org/unicorn/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,
@@ -14,7 +14,14 @@ After = unicorn.socket
14
14
  # bundler users must use the "--keep-file-descriptors" switch, here:
15
15
  # ExecStart = bundle exec --keep-file-descriptors unicorn -c ...
16
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
17
23
  Sockets = unicorn.socket
24
+
18
25
  KillSignal = SIGQUIT
19
26
  User = nobody
20
27
  Group = nogroup
@@ -1,6 +1,11 @@
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")
@@ -62,7 +62,8 @@ struct http_parser {
62
62
  } len;
63
63
  };
64
64
 
65
- static ID id_set_backtrace;
65
+ static ID id_set_backtrace, id_is_chunked_p;
66
+ static VALUE cHttpParser;
66
67
 
67
68
  #ifdef HAVE_RB_HASH_CLEAR /* Ruby >= 2.0 */
68
69
  # define my_hash_clear(h) (void)rb_hash_clear(h)
@@ -220,6 +221,19 @@ static void write_cont_value(struct http_parser *hp,
220
221
  rb_str_buf_cat(hp->cont, vptr, end + 1);
221
222
  }
222
223
 
224
+ static int is_chunked(VALUE v)
225
+ {
226
+ /* common case first */
227
+ if (STR_CSTR_CASE_EQ(v, "chunked"))
228
+ return 1;
229
+
230
+ /*
231
+ * call Ruby function in unicorn/http_request.rb to deal with unlikely
232
+ * comma-delimited case
233
+ */
234
+ return rb_funcall(cHttpParser, id_is_chunked_p, 1, v) != Qfalse;
235
+ }
236
+
223
237
  static void write_value(struct http_parser *hp,
224
238
  const char *buffer, const char *p)
225
239
  {
@@ -246,7 +260,9 @@ static void write_value(struct http_parser *hp,
246
260
  f = uncommon_field(field, flen);
247
261
  } else if (f == g_http_connection) {
248
262
  hp_keepalive_connection(hp, v);
249
- } else if (f == g_content_length) {
263
+ } else if (f == g_content_length && !HP_FL_TEST(hp, CHUNKED)) {
264
+ if (hp->len.content)
265
+ parser_raise(eHttpParserError, "Content-Length already set");
250
266
  hp->len.content = parse_length(RSTRING_PTR(v), RSTRING_LEN(v));
251
267
  if (hp->len.content < 0)
252
268
  parser_raise(eHttpParserError, "invalid Content-Length");
@@ -254,9 +270,30 @@ static void write_value(struct http_parser *hp,
254
270
  HP_FL_SET(hp, HASBODY);
255
271
  hp_invalid_if_trailer(hp);
256
272
  } else if (f == g_http_transfer_encoding) {
257
- if (STR_CSTR_CASE_EQ(v, "chunked")) {
273
+ if (is_chunked(v)) {
274
+ if (HP_FL_TEST(hp, CHUNKED))
275
+ /*
276
+ * RFC 7230 3.3.1:
277
+ * A sender MUST NOT apply chunked more than once to a message body
278
+ * (i.e., chunking an already chunked message is not allowed).
279
+ */
280
+ parser_raise(eHttpParserError, "Transfer-Encoding double chunked");
281
+
258
282
  HP_FL_SET(hp, CHUNKED);
259
283
  HP_FL_SET(hp, HASBODY);
284
+
285
+ /* RFC 7230 3.3.3, 3: favor chunked if Content-Length exists */
286
+ hp->len.content = 0;
287
+ } else if (HP_FL_TEST(hp, CHUNKED)) {
288
+ /*
289
+ * RFC 7230 3.3.3, point 3 states:
290
+ * If a Transfer-Encoding header field is present in a request and
291
+ * the chunked transfer coding is not the final encoding, the
292
+ * message body length cannot be determined reliably; the server
293
+ * MUST respond with the 400 (Bad Request) status code and then
294
+ * close the connection.
295
+ */
296
+ parser_raise(eHttpParserError, "invalid Transfer-Encoding");
260
297
  }
261
298
  hp_invalid_if_trailer(hp);
262
299
  } else if (f == g_http_trailer) {
@@ -487,7 +524,7 @@ static void set_url_scheme(VALUE env, VALUE *server_port)
487
524
  * and X-Forwarded-Proto handling from this parser? We've had it
488
525
  * forever and nobody has said anything against it, either.
489
526
  * Anyways, please send comments to our public mailing list:
490
- * unicorn-public@bogomips.org (no HTML mail, no subscription necessary)
527
+ * unicorn-public@yhbt.net (no HTML mail, no subscription necessary)
491
528
  */
492
529
  scheme = rb_hash_aref(env, g_http_x_forwarded_ssl);
493
530
  if (!NIL_P(scheme) && STR_CSTR_EQ(scheme, "on")) {
@@ -931,7 +968,7 @@ static VALUE HttpParser_rssget(VALUE self)
931
968
 
932
969
  void Init_unicorn_http(void)
933
970
  {
934
- VALUE mUnicorn, cHttpParser;
971
+ VALUE mUnicorn;
935
972
 
936
973
  mUnicorn = rb_define_module("Unicorn");
937
974
  cHttpParser = rb_define_class_under(mUnicorn, "HttpParser", rb_cObject);
@@ -991,5 +1028,6 @@ void Init_unicorn_http(void)
991
1028
  #ifndef HAVE_RB_HASH_CLEAR
992
1029
  id_clear = rb_intern("clear");
993
1030
  #endif
1031
+ id_is_chunked_p = rb_intern("is_chunked?");
994
1032
  }
995
1033
  #undef SET_GLOBAL
data/lib/unicorn.rb CHANGED
@@ -96,7 +96,7 @@ def self.builder(ru, op)
96
96
 
97
97
  # returns an array of strings representing TCP listen socket addresses
98
98
  # and Unix domain socket paths. This is useful for use with
99
- # Raindrops::Middleware under Linux: https://bogomips.org/raindrops/
99
+ # Raindrops::Middleware under Linux: https://yhbt.net/raindrops/
100
100
  def self.listener_names
101
101
  Unicorn::HttpServer::LISTENERS.map do |io|
102
102
  Unicorn::SocketHelper.sock_name(io)
@@ -123,6 +123,9 @@ def self.pipe # :nodoc:
123
123
  io.fcntl(F_SETPIPE_SZ, Raindrops::PAGE_SIZE)
124
124
  rescue Errno::EINVAL
125
125
  # old kernel
126
+ rescue Errno::EPERM
127
+ # resizes fail if Linux is close to the pipe limit for the user
128
+ # or if the user does not have permissions to resize
126
129
  end
127
130
  end
128
131
  end
@@ -3,11 +3,11 @@
3
3
 
4
4
  # Implements a simple DSL for configuring a unicorn server.
5
5
  #
6
- # See https://bogomips.org/unicorn/examples/unicorn.conf.rb and
7
- # https://bogomips.org/unicorn/examples/unicorn.conf.minimal.rb
6
+ # See https://yhbt.net/unicorn/examples/unicorn.conf.rb and
7
+ # https://yhbt.net/unicorn/examples/unicorn.conf.minimal.rb
8
8
  # example configuration files. An example config file for use with
9
9
  # nginx is also available at
10
- # https://bogomips.org/unicorn/examples/nginx.conf
10
+ # https://yhbt.net/unicorn/examples/nginx.conf
11
11
  #
12
12
  # See the link:/TUNING.html document for more information on tuning unicorn.
13
13
  class Unicorn::Configurator
@@ -53,6 +53,7 @@ class Unicorn::Configurator
53
53
  server.logger.info("worker=#{worker.nr} ready")
54
54
  },
55
55
  :pid => nil,
56
+ :early_hints => false,
56
57
  :worker_exec => false,
57
58
  :preload_app => false,
58
59
  :check_client_connection => false,
@@ -276,6 +277,15 @@ def default_middleware(bool)
276
277
  set_bool(:default_middleware, bool)
277
278
  end
278
279
 
280
+ # sets whether to enable the proposed early hints Rack API.
281
+ # If enabled, Rails 5.2+ will automatically send a 103 Early Hint
282
+ # for all the `javascript_include_tag` and `stylesheet_link_tag`
283
+ # in your response. See: https://api.rubyonrails.org/v5.2/classes/ActionDispatch/Request.html#method-i-send_early_hints
284
+ # See also https://tools.ietf.org/html/rfc8297
285
+ def early_hints(bool)
286
+ set_bool(:early_hints, bool)
287
+ end
288
+
279
289
  # sets listeners to the given +addresses+, replacing or augmenting the
280
290
  # current set. This is for the global listener pool shared by all
281
291
  # worker processes. For per-worker listeners, see the after_fork example
@@ -62,7 +62,6 @@ def self.check_client_connection=(bool)
62
62
  # This does minimal exception trapping and it is up to the caller
63
63
  # to handle any socket errors (e.g. user aborted upload).
64
64
  def read(socket)
65
- clear
66
65
  e = env
67
66
 
68
67
  # From https://www.ietf.org/rfc/rfc3875:
@@ -188,4 +187,15 @@ def write_http_header(socket) # :nodoc:
188
187
  HTTP_RESPONSE_START.each { |c| socket.write(c) }
189
188
  end
190
189
  end
190
+
191
+ # called by ext/unicorn_http/unicorn_http.rl via rb_funcall
192
+ def self.is_chunked?(v) # :nodoc:
193
+ vals = v.split(/[ \t]*,[ \t]*/).map!(&:downcase)
194
+ if vals.pop == 'chunked'.freeze
195
+ return true unless vals.include?('chunked'.freeze)
196
+ raise Unicorn::HttpParserError, 'double chunked', []
197
+ end
198
+ return false unless vals.include?('chunked'.freeze)
199
+ raise Unicorn::HttpParserError, 'chunked not last', []
200
+ end
191
201
  end
@@ -6,7 +6,7 @@
6
6
  # forked worker children.
7
7
  #
8
8
  # Users do not need to know the internals of this class, but reading the
9
- # {source}[https://bogomips.org/unicorn.git/tree/lib/unicorn/http_server.rb]
9
+ # {source}[https://yhbt.net/unicorn.git/tree/lib/unicorn/http_server.rb]
10
10
  # is education for programmers wishing to learn how unicorn works.
11
11
  # See Unicorn::Configurator for information on how to configure unicorn.
12
12
  class Unicorn::HttpServer
@@ -15,7 +15,7 @@ class Unicorn::HttpServer
15
15
  :before_fork, :after_fork, :before_exec,
16
16
  :listener_opts, :preload_app,
17
17
  :orig_app, :config, :ready_pipe, :user,
18
- :default_middleware
18
+ :default_middleware, :early_hints
19
19
  attr_writer :after_worker_exit, :after_worker_ready, :worker_exec
20
20
 
21
21
  attr_reader :pid, :logger
@@ -69,7 +69,6 @@ class Unicorn::HttpServer
69
69
  # incoming requests on the socket.
70
70
  def initialize(app, options = {})
71
71
  @app = app
72
- @request = Unicorn::HttpRequest.new
73
72
  @reexec_pid = 0
74
73
  @default_middleware = true
75
74
  options = options.dup
@@ -588,6 +587,25 @@ def handle_error(client, e)
588
587
  rescue
589
588
  end
590
589
 
590
+ def e103_response_write(client, headers)
591
+ response = if @request.response_start_sent
592
+ "103 Early Hints\r\n"
593
+ else
594
+ "HTTP/1.1 103 Early Hints\r\n"
595
+ end
596
+
597
+ headers.each_pair do |k, vs|
598
+ next if !vs || vs.empty?
599
+ values = vs.to_s.split("\n".freeze)
600
+ values.each do |v|
601
+ response << "#{k}: #{v}\r\n"
602
+ end
603
+ end
604
+ response << "\r\n".freeze
605
+ response << "HTTP/1.1 ".freeze if @request.response_start_sent
606
+ client.write(response)
607
+ end
608
+
591
609
  def e100_response_write(client, env)
592
610
  # We use String#freeze to avoid allocations under Ruby 2.1+
593
611
  # Not many users hit this code path, so it's better to reduce the
@@ -602,7 +620,18 @@ def e100_response_write(client, env)
602
620
  # once a client is accepted, it is processed in its entirety here
603
621
  # in 3 easy steps: read request, call app, write app response
604
622
  def process_client(client)
605
- status, headers, body = @app.call(env = @request.read(client))
623
+ @request = Unicorn::HttpRequest.new
624
+ env = @request.read(client)
625
+
626
+ if early_hints
627
+ env["rack.early_hints"] = lambda do |headers|
628
+ e103_response_write(client, headers)
629
+ end
630
+ end
631
+
632
+ env["rack.after_reply"] = []
633
+
634
+ status, headers, body = @app.call(env)
606
635
 
607
636
  begin
608
637
  return if @request.hijacked?
@@ -624,6 +653,8 @@ def process_client(client)
624
653
  end
625
654
  rescue => e
626
655
  handle_error(client, e)
656
+ ensure
657
+ env["rack.after_reply"].each(&:call) if env
627
658
  end
628
659
 
629
660
  def nuke_listeners!(readers)
@@ -686,6 +717,7 @@ def worker_loop(worker)
686
717
  trap(:USR1) { nr = -65536 }
687
718
 
688
719
  ready = readers.dup
720
+ nr_listeners = readers.size
689
721
  @after_worker_ready.call(self, worker)
690
722
 
691
723
  begin
@@ -708,7 +740,7 @@ def worker_loop(worker)
708
740
  # we're probably reasonably busy, so avoid calling select()
709
741
  # and do a speculative non-blocking accept() on ready listeners
710
742
  # before we sleep again in select().
711
- unless nr == 0
743
+ if nr == nr_listeners
712
744
  tmp = ready.dup
713
745
  redo
714
746
  end
@@ -43,8 +43,8 @@
43
43
  # use Unicorn::OobGC, 2, %r{\A/(?:expensive/foo|more_expensive/foo)}
44
44
  #
45
45
  # Feedback from users of early implementations of this module:
46
- # * https://bogomips.org/unicorn-public/0BFC98E9-072B-47EE-9A70-05478C20141B@lukemelia.com/
47
- # * https://bogomips.org/unicorn-public/AANLkTilUbgdyDv9W1bi-s_W6kq9sOhWfmuYkKLoKGOLj@mail.gmail.com/
46
+ # * https://yhbt.net/unicorn-public/0BFC98E9-072B-47EE-9A70-05478C20141B@lukemelia.com/
47
+ # * https://yhbt.net/unicorn-public/AANLkTilUbgdyDv9W1bi-s_W6kq9sOhWfmuYkKLoKGOLj@mail.gmail.com/
48
48
 
49
49
  module Unicorn::OobGC
50
50
 
@@ -60,7 +60,6 @@ def self.new(app, interval = 5, path = %r{\A/})
60
60
  self.const_set :OOBGC_INTERVAL, interval
61
61
  ObjectSpace.each_object(Unicorn::HttpServer) do |s|
62
62
  s.extend(self)
63
- self.const_set :OOBGC_ENV, s.instance_variable_get(:@request).env
64
63
  end
65
64
  app # pretend to be Rack middleware since it was in the past
66
65
  end
@@ -68,9 +67,10 @@ def self.new(app, interval = 5, path = %r{\A/})
68
67
  #:stopdoc:
69
68
  def process_client(client)
70
69
  super(client) # Unicorn::HttpServer#process_client
71
- if OOBGC_PATH =~ OOBGC_ENV['PATH_INFO'] && ((@@nr -= 1) <= 0)
70
+ env = instance_variable_get(:@request).env
71
+ if OOBGC_PATH =~ env['PATH_INFO'] && ((@@nr -= 1) <= 0)
72
72
  @@nr = OOBGC_INTERVAL
73
- OOBGC_ENV.clear
73
+ env.clear
74
74
  disabled = GC.enable
75
75
  GC.start
76
76
  GC.disable if disabled
data/lib/unicorn/tmpio.rb CHANGED
@@ -11,12 +11,18 @@ class Unicorn::TmpIO < File
11
11
  # immediately, switched to binary mode, and userspace output
12
12
  # buffering is disabled
13
13
  def self.new
14
+ path = nil
15
+
16
+ # workaround File#path being tainted:
17
+ # https://bugs.ruby-lang.org/issues/14485
14
18
  fp = begin
15
- super("#{Dir::tmpdir}/#{rand}", RDWR|CREAT|EXCL, 0600)
19
+ path = "#{Dir::tmpdir}/#{rand}"
20
+ super(path, RDWR|CREAT|EXCL, 0600)
16
21
  rescue Errno::EEXIST
17
22
  retry
18
23
  end
19
- unlink(fp.path)
24
+
25
+ unlink(path)
20
26
  fp.binmode
21
27
  fp.sync = true
22
28
  fp