unicorn 5.5.0 → 6.1.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.
- checksums.yaml +4 -4
- data/.manifest +8 -5
- data/.olddoc.yml +15 -7
- data/CONTRIBUTORS +6 -2
- data/Documentation/.gitignore +1 -3
- data/Documentation/unicorn.1 +222 -0
- data/Documentation/unicorn_rails.1 +207 -0
- data/FAQ +1 -1
- data/GIT-VERSION-FILE +1 -1
- data/GIT-VERSION-GEN +1 -1
- data/GNUmakefile +112 -57
- data/HACKING +2 -9
- data/ISSUES +24 -31
- data/KNOWN_ISSUES +2 -2
- data/LATEST +16 -22
- data/Links +5 -5
- data/NEWS +155 -0
- data/README +15 -9
- data/SIGNALS +1 -1
- data/Sandbox +3 -3
- data/archive/slrnpull.conf +1 -1
- data/bin/unicorn_rails +2 -2
- data/examples/big_app_gc.rb +1 -1
- data/examples/logrotate.conf +2 -2
- data/examples/nginx.conf +1 -1
- data/examples/unicorn.conf.minimal.rb +2 -2
- data/examples/unicorn.conf.rb +2 -2
- data/examples/unicorn@.service +7 -0
- data/ext/unicorn_http/c_util.h +5 -13
- data/ext/unicorn_http/common_field_optimization.h +0 -1
- data/ext/unicorn_http/epollexclusive.h +124 -0
- data/ext/unicorn_http/ext_help.h +0 -24
- data/ext/unicorn_http/extconf.rb +2 -6
- data/ext/unicorn_http/global_variables.h +1 -1
- data/ext/unicorn_http/httpdate.c +1 -0
- data/ext/unicorn_http/unicorn_http.c +258 -228
- data/ext/unicorn_http/unicorn_http.rl +48 -18
- data/lib/unicorn/configurator.rb +13 -3
- data/lib/unicorn/http_request.rb +11 -1
- data/lib/unicorn/http_server.rb +56 -29
- data/lib/unicorn/oob_gc.rb +5 -5
- data/lib/unicorn/select_waiter.rb +6 -0
- data/lib/unicorn/tmpio.rb +8 -2
- data/lib/unicorn/version.rb +1 -1
- data/lib/unicorn.rb +4 -3
- data/man/man1/unicorn.1 +89 -88
- data/man/man1/unicorn_rails.1 +78 -83
- data/t/GNUmakefile +3 -72
- data/t/README +1 -1
- data/t/test-lib.sh +2 -1
- 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 +14 -12
- data/test/test_helper.rb +38 -30
- data/test/unit/test_ccc.rb +4 -3
- data/test/unit/test_http_parser_ng.rb +81 -0
- data/test/unit/test_server.rb +81 -7
- data/test/unit/test_signals.rb +6 -6
- data/test/unit/test_socket_helper.rb +1 -1
- data/test/unit/test_upload.rb +9 -14
- data/test/unit/test_util.rb +5 -4
- data/test/unit/test_waiter.rb +34 -0
- data/unicorn.gemspec +8 -7
- metadata +16 -11
- data/Documentation/GNUmakefile +0 -30
- data/Documentation/unicorn.1.txt +0 -187
- data/Documentation/unicorn_rails.1.txt +0 -175
- data/t/hijack.ru +0 -55
- data/t/t0200-rack-hijack.sh +0 -51
@@ -12,6 +12,7 @@
|
|
12
12
|
#include "common_field_optimization.h"
|
13
13
|
#include "global_variables.h"
|
14
14
|
#include "c_util.h"
|
15
|
+
#include "epollexclusive.h"
|
15
16
|
|
16
17
|
void init_unicorn_httpdate(void);
|
17
18
|
|
@@ -62,19 +63,8 @@ struct http_parser {
|
|
62
63
|
} len;
|
63
64
|
};
|
64
65
|
|
65
|
-
static ID id_set_backtrace;
|
66
|
-
|
67
|
-
#ifdef HAVE_RB_HASH_CLEAR /* Ruby >= 2.0 */
|
68
|
-
# define my_hash_clear(h) (void)rb_hash_clear(h)
|
69
|
-
#else /* !HAVE_RB_HASH_CLEAR - Ruby <= 1.9.3 */
|
70
|
-
|
71
|
-
static ID id_clear;
|
72
|
-
|
73
|
-
static void my_hash_clear(VALUE h)
|
74
|
-
{
|
75
|
-
rb_funcall(h, id_clear, 0);
|
76
|
-
}
|
77
|
-
#endif /* HAVE_RB_HASH_CLEAR */
|
66
|
+
static ID id_set_backtrace, id_is_chunked_p;
|
67
|
+
static VALUE cHttpParser;
|
78
68
|
|
79
69
|
static void finalize_header(struct http_parser *hp);
|
80
70
|
|
@@ -220,6 +210,19 @@ static void write_cont_value(struct http_parser *hp,
|
|
220
210
|
rb_str_buf_cat(hp->cont, vptr, end + 1);
|
221
211
|
}
|
222
212
|
|
213
|
+
static int is_chunked(VALUE v)
|
214
|
+
{
|
215
|
+
/* common case first */
|
216
|
+
if (STR_CSTR_CASE_EQ(v, "chunked"))
|
217
|
+
return 1;
|
218
|
+
|
219
|
+
/*
|
220
|
+
* call Ruby function in unicorn/http_request.rb to deal with unlikely
|
221
|
+
* comma-delimited case
|
222
|
+
*/
|
223
|
+
return rb_funcall(cHttpParser, id_is_chunked_p, 1, v) != Qfalse;
|
224
|
+
}
|
225
|
+
|
223
226
|
static void write_value(struct http_parser *hp,
|
224
227
|
const char *buffer, const char *p)
|
225
228
|
{
|
@@ -246,7 +249,9 @@ static void write_value(struct http_parser *hp,
|
|
246
249
|
f = uncommon_field(field, flen);
|
247
250
|
} else if (f == g_http_connection) {
|
248
251
|
hp_keepalive_connection(hp, v);
|
249
|
-
} else if (f == g_content_length) {
|
252
|
+
} else if (f == g_content_length && !HP_FL_TEST(hp, CHUNKED)) {
|
253
|
+
if (hp->len.content)
|
254
|
+
parser_raise(eHttpParserError, "Content-Length already set");
|
250
255
|
hp->len.content = parse_length(RSTRING_PTR(v), RSTRING_LEN(v));
|
251
256
|
if (hp->len.content < 0)
|
252
257
|
parser_raise(eHttpParserError, "invalid Content-Length");
|
@@ -254,9 +259,30 @@ static void write_value(struct http_parser *hp,
|
|
254
259
|
HP_FL_SET(hp, HASBODY);
|
255
260
|
hp_invalid_if_trailer(hp);
|
256
261
|
} else if (f == g_http_transfer_encoding) {
|
257
|
-
if (
|
262
|
+
if (is_chunked(v)) {
|
263
|
+
if (HP_FL_TEST(hp, CHUNKED))
|
264
|
+
/*
|
265
|
+
* RFC 7230 3.3.1:
|
266
|
+
* A sender MUST NOT apply chunked more than once to a message body
|
267
|
+
* (i.e., chunking an already chunked message is not allowed).
|
268
|
+
*/
|
269
|
+
parser_raise(eHttpParserError, "Transfer-Encoding double chunked");
|
270
|
+
|
258
271
|
HP_FL_SET(hp, CHUNKED);
|
259
272
|
HP_FL_SET(hp, HASBODY);
|
273
|
+
|
274
|
+
/* RFC 7230 3.3.3, 3: favor chunked if Content-Length exists */
|
275
|
+
hp->len.content = 0;
|
276
|
+
} else if (HP_FL_TEST(hp, CHUNKED)) {
|
277
|
+
/*
|
278
|
+
* RFC 7230 3.3.3, point 3 states:
|
279
|
+
* If a Transfer-Encoding header field is present in a request and
|
280
|
+
* the chunked transfer coding is not the final encoding, the
|
281
|
+
* message body length cannot be determined reliably; the server
|
282
|
+
* MUST respond with the 400 (Bad Request) status code and then
|
283
|
+
* close the connection.
|
284
|
+
*/
|
285
|
+
parser_raise(eHttpParserError, "invalid Transfer-Encoding");
|
260
286
|
}
|
261
287
|
hp_invalid_if_trailer(hp);
|
262
288
|
} else if (f == g_http_trailer) {
|
@@ -487,7 +513,7 @@ static void set_url_scheme(VALUE env, VALUE *server_port)
|
|
487
513
|
* and X-Forwarded-Proto handling from this parser? We've had it
|
488
514
|
* forever and nobody has said anything against it, either.
|
489
515
|
* Anyways, please send comments to our public mailing list:
|
490
|
-
* unicorn-public@
|
516
|
+
* unicorn-public@yhbt.net (no HTML mail, no subscription necessary)
|
491
517
|
*/
|
492
518
|
scheme = rb_hash_aref(env, g_http_x_forwarded_ssl);
|
493
519
|
if (!NIL_P(scheme) && STR_CSTR_EQ(scheme, "on")) {
|
@@ -613,7 +639,7 @@ static VALUE HttpParser_clear(VALUE self)
|
|
613
639
|
return HttpParser_init(self);
|
614
640
|
|
615
641
|
http_parser_init(hp);
|
616
|
-
|
642
|
+
rb_hash_clear(hp->env);
|
617
643
|
|
618
644
|
return self;
|
619
645
|
}
|
@@ -931,7 +957,7 @@ static VALUE HttpParser_rssget(VALUE self)
|
|
931
957
|
|
932
958
|
void Init_unicorn_http(void)
|
933
959
|
{
|
934
|
-
VALUE mUnicorn
|
960
|
+
VALUE mUnicorn;
|
935
961
|
|
936
962
|
mUnicorn = rb_define_module("Unicorn");
|
937
963
|
cHttpParser = rb_define_class_under(mUnicorn, "HttpParser", rb_cObject);
|
@@ -942,6 +968,7 @@ void Init_unicorn_http(void)
|
|
942
968
|
e414 = rb_define_class_under(mUnicorn, "RequestURITooLongError",
|
943
969
|
eHttpParserError);
|
944
970
|
|
971
|
+
id_uminus = rb_intern("-@");
|
945
972
|
init_globals();
|
946
973
|
rb_define_alloc_func(cHttpParser, HttpParser_alloc);
|
947
974
|
rb_define_method(cHttpParser, "initialize", HttpParser_init, 0);
|
@@ -991,5 +1018,8 @@ void Init_unicorn_http(void)
|
|
991
1018
|
#ifndef HAVE_RB_HASH_CLEAR
|
992
1019
|
id_clear = rb_intern("clear");
|
993
1020
|
#endif
|
1021
|
+
id_is_chunked_p = rb_intern("is_chunked?");
|
1022
|
+
|
1023
|
+
init_epollexclusive(mUnicorn);
|
994
1024
|
}
|
995
1025
|
#undef SET_GLOBAL
|
data/lib/unicorn/configurator.rb
CHANGED
@@ -3,11 +3,11 @@ require 'logger'
|
|
3
3
|
|
4
4
|
# Implements a simple DSL for configuring a unicorn server.
|
5
5
|
#
|
6
|
-
# See https://
|
7
|
-
# https://
|
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://
|
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 @@ class Unicorn::Configurator
|
|
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
|
data/lib/unicorn/http_request.rb
CHANGED
@@ -62,7 +62,6 @@ class Unicorn::HttpParser
|
|
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 @@ class Unicorn::HttpParser
|
|
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
|
data/lib/unicorn/http_server.rb
CHANGED
@@ -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://
|
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,10 +587,29 @@ class Unicorn::HttpServer
|
|
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
|
594
|
-
# constant table sizes even for
|
612
|
+
# constant table sizes even for Ruby 2.0 users who'll hit extra
|
595
613
|
# allocations here.
|
596
614
|
client.write(@request.response_start_sent ?
|
597
615
|
"100 Continue\r\n\r\nHTTP/1.1 ".freeze :
|
@@ -602,7 +620,18 @@ class Unicorn::HttpServer
|
|
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
|
-
|
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 @@ class Unicorn::HttpServer
|
|
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)
|
@@ -654,7 +685,6 @@ class Unicorn::HttpServer
|
|
654
685
|
LISTENERS.each { |sock| sock.close_on_exec = true }
|
655
686
|
|
656
687
|
worker.user(*user) if user.kind_of?(Array) && ! worker.switched
|
657
|
-
self.timeout /= 2.0 # halve it for select()
|
658
688
|
@config = nil
|
659
689
|
build_app! unless preload_app
|
660
690
|
@after_fork = @listener_opts = @orig_app = nil
|
@@ -668,58 +698,55 @@ class Unicorn::HttpServer
|
|
668
698
|
logger.info "worker=#{worker_nr} reopening logs..."
|
669
699
|
Unicorn::Util.reopen_logs
|
670
700
|
logger.info "worker=#{worker_nr} done reopening logs"
|
701
|
+
false
|
671
702
|
rescue => e
|
672
703
|
logger.error(e) rescue nil
|
673
704
|
exit!(77) # EX_NOPERM in sysexits.h
|
674
705
|
end
|
675
706
|
|
707
|
+
def prep_readers(readers)
|
708
|
+
wtr = Unicorn::Waiter.prep_readers(readers)
|
709
|
+
@timeout *= 500 # to milliseconds for epoll, but halved
|
710
|
+
wtr
|
711
|
+
rescue
|
712
|
+
require_relative 'select_waiter'
|
713
|
+
@timeout /= 2.0 # halved for IO.select
|
714
|
+
Unicorn::SelectWaiter.new
|
715
|
+
end
|
716
|
+
|
676
717
|
# runs inside each forked worker, this sits around and waits
|
677
718
|
# for connections and doesn't die until the parent dies (or is
|
678
719
|
# given a INT, QUIT, or TERM signal)
|
679
720
|
def worker_loop(worker)
|
680
|
-
ppid = @master_pid
|
681
721
|
readers = init_worker_process(worker)
|
682
|
-
|
722
|
+
waiter = prep_readers(readers)
|
723
|
+
reopen = false
|
683
724
|
|
684
725
|
# this only works immediately if the master sent us the signal
|
685
726
|
# (which is the normal case)
|
686
|
-
trap(:USR1) {
|
727
|
+
trap(:USR1) { reopen = true }
|
687
728
|
|
688
729
|
ready = readers.dup
|
689
730
|
@after_worker_ready.call(self, worker)
|
690
731
|
|
691
732
|
begin
|
692
|
-
|
693
|
-
nr = 0
|
733
|
+
reopen = reopen_worker_logs(worker.nr) if reopen
|
694
734
|
worker.tick = time_now.to_i
|
695
|
-
|
696
|
-
while sock = tmp.shift
|
735
|
+
while sock = ready.shift
|
697
736
|
# Unicorn::Worker#kgio_tryaccept is not like accept(2) at all,
|
698
737
|
# but that will return false
|
699
738
|
if client = sock.kgio_tryaccept
|
700
739
|
process_client(client)
|
701
|
-
nr += 1
|
702
740
|
worker.tick = time_now.to_i
|
703
741
|
end
|
704
|
-
break if
|
742
|
+
break if reopen
|
705
743
|
end
|
706
744
|
|
707
|
-
#
|
708
|
-
# we're probably reasonably busy, so avoid calling select()
|
709
|
-
# and do a speculative non-blocking accept() on ready listeners
|
710
|
-
# before we sleep again in select().
|
711
|
-
unless nr == 0
|
712
|
-
tmp = ready.dup
|
713
|
-
redo
|
714
|
-
end
|
715
|
-
|
716
|
-
ppid == Process.ppid or return
|
717
|
-
|
718
|
-
# timeout used so we can detect parent death:
|
745
|
+
# timeout so we can .tick and keep parent from SIGKILL-ing us
|
719
746
|
worker.tick = time_now.to_i
|
720
|
-
|
747
|
+
waiter.get_readers(ready, readers, @timeout)
|
721
748
|
rescue => e
|
722
|
-
redo if
|
749
|
+
redo if reopen && readers[0]
|
723
750
|
Unicorn.log_error(@logger, "listen loop error", e) if readers[0]
|
724
751
|
end while readers[0]
|
725
752
|
end
|
data/lib/unicorn/oob_gc.rb
CHANGED
@@ -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://
|
47
|
-
# * https://
|
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 @@ module Unicorn::OobGC
|
|
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 @@ module Unicorn::OobGC
|
|
68
67
|
#:stopdoc:
|
69
68
|
def process_client(client)
|
70
69
|
super(client) # Unicorn::HttpServer#process_client
|
71
|
-
|
70
|
+
env = instance_variable_get(:@request).env
|
71
|
+
if OOBGC_PATH =~ env['PATH_INFO'] && ((@@nr -= 1) <= 0)
|
72
72
|
@@nr = OOBGC_INTERVAL
|
73
|
-
|
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
|
-
|
19
|
+
path = "#{Dir::tmpdir}/#{rand}"
|
20
|
+
super(path, RDWR|CREAT|EXCL, 0600)
|
16
21
|
rescue Errno::EEXIST
|
17
22
|
retry
|
18
23
|
end
|
19
|
-
|
24
|
+
|
25
|
+
unlink(path)
|
20
26
|
fp.binmode
|
21
27
|
fp.sync = true
|
22
28
|
fp
|
data/lib/unicorn/version.rb
CHANGED
@@ -1 +1 @@
|
|
1
|
-
Unicorn::Const::UNICORN_VERSION = '
|
1
|
+
Unicorn::Const::UNICORN_VERSION = '6.1.0'
|
data/lib/unicorn.rb
CHANGED
@@ -96,7 +96,7 @@ module Unicorn
|
|
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://
|
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)
|
@@ -114,8 +114,6 @@ module Unicorn
|
|
114
114
|
|
115
115
|
def self.pipe # :nodoc:
|
116
116
|
Kgio::Pipe.new.each do |io|
|
117
|
-
io.close_on_exec = true # remove this when we only support Ruby >= 2.0
|
118
|
-
|
119
117
|
# shrink pipes to minimize impact on /proc/sys/fs/pipe-user-pages-soft
|
120
118
|
# limits.
|
121
119
|
if defined?(F_SETPIPE_SZ)
|
@@ -123,6 +121,9 @@ module Unicorn
|
|
123
121
|
io.fcntl(F_SETPIPE_SZ, Raindrops::PAGE_SIZE)
|
124
122
|
rescue Errno::EINVAL
|
125
123
|
# old kernel
|
124
|
+
rescue Errno::EPERM
|
125
|
+
# resizes fail if Linux is close to the pipe limit for the user
|
126
|
+
# or if the user does not have permissions to resize
|
126
127
|
end
|
127
128
|
end
|
128
129
|
end
|