unicorn-shopify 5.2.0.6 → 5.3.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/.olddoc.yml +0 -1
- data/GIT-VERSION-GEN +1 -1
- data/HACKING +0 -1
- data/ISSUES +12 -6
- data/Links +1 -1
- data/lib/unicorn.rb +1 -1
- data/lib/unicorn/configurator.rb +22 -7
- data/lib/unicorn/http_request.rb +35 -15
- data/lib/unicorn/http_server.rb +61 -17
- data/lib/unicorn/socket_helper.rb +5 -2
- data/lib/unicorn/stream_input.rb +5 -4
- data/lib/unicorn/tee_input.rb +7 -7
- data/lib/unicorn/worker.rb +7 -3
- data/t/test-lib.sh +2 -2
- data/test/exec/test_exec.rb +6 -5
- data/test/unit/test_http_parser.rb +0 -18
- data/test/unit/test_socket_helper.rb +8 -4
- data/test/unit/test_util.rb +2 -2
- data/unicorn.gemspec +10 -12
- metadata +3 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b4f49b8a39233e5173cd9449ac97280d9981fbaf
|
4
|
+
data.tar.gz: 7d59709e0d4a4670a1d549f930e6f1557b3b986e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ef1af3b1aec6f855844103eefef52848fae3af4dd2ecb73dc47a3df0da6d826a436a790a52935a31d9af22d6506148411dc5d08fe981a3ffb9c73500ddfbb240
|
7
|
+
data.tar.gz: 9b6af6386d99ab1cbc9b872b5a296240e11f68e59e12966a6d546c0d373749b884b1ba3bee3c49ef99777937ef879cf3bb0179ee78b3e2bd082c032c4d6deef4
|
data/.olddoc.yml
CHANGED
@@ -12,7 +12,6 @@ noindex:
|
|
12
12
|
- TODO
|
13
13
|
- unicorn_rails_1
|
14
14
|
public_email: unicorn-public@bogomips.org
|
15
|
-
private_email: unicorn@bogomips.org
|
16
15
|
nntp_url:
|
17
16
|
- nntp://news.public-inbox.org/inbox.comp.lang.ruby.unicorn
|
18
17
|
- nntp://news.gmane.org/gmane.comp.lang.ruby.unicorn.general
|
data/GIT-VERSION-GEN
CHANGED
data/HACKING
CHANGED
@@ -104,7 +104,6 @@ don't email the git mailing list or maintainer with Unicorn patches :)
|
|
104
104
|
|
105
105
|
In order to build the gem, you must install the following components:
|
106
106
|
|
107
|
-
* olddoc (RubyGem)
|
108
107
|
* pandoc
|
109
108
|
|
110
109
|
You can build the Unicorn gem with the following command:
|
data/ISSUES
CHANGED
@@ -9,14 +9,16 @@ submit patches and/or obtain support after you have searched the
|
|
9
9
|
* Cc: all participants in a thread or commit, as subscription is optional
|
10
10
|
* Do not {top post}[http://catb.org/jargon/html/T/top-post.html] in replies
|
11
11
|
* Quote as little as possible of the message you're replying to
|
12
|
-
* Do not send HTML mail or images,
|
13
|
-
|
12
|
+
* Do not send HTML mail or images,
|
13
|
+
they hurt reader privacy and will be flagged as spam
|
14
|
+
* Anonymous and pseudonymous messages will ALWAYS be welcome
|
14
15
|
* The email submission port (587) is enabled on the bogomips.org MX:
|
15
16
|
https://bogomips.org/unicorn-public/20141004232241.GA23908@dcvr.yhbt.net/t/
|
16
17
|
|
17
18
|
If your issue is of a sensitive nature or you're just shy in public,
|
18
|
-
|
19
|
-
|
19
|
+
use anonymity tools such as Tor or Mixmaster; and rely on the public
|
20
|
+
mail archives for responses. Be sure to scrub sensitive log messages
|
21
|
+
and such.
|
20
22
|
|
21
23
|
If you don't get a response within a few days, we may have forgotten
|
22
24
|
about it so feel free to ask again.
|
@@ -64,14 +66,14 @@ document distributed with git) on guidelines for patch submission.
|
|
64
66
|
== Contact Info
|
65
67
|
|
66
68
|
* public: mailto:unicorn-public@bogomips.org
|
67
|
-
* private: mailto:unicorn@bogomips.org
|
68
69
|
* nntp://news.gmane.org/gmane.comp.lang.ruby.unicorn.general
|
69
70
|
* nntp://news.public-inbox.org/inbox.comp.lang.ruby.unicorn
|
70
71
|
* https://bogomips.org/unicorn-public/
|
72
|
+
* http://ou63pmih66umazou.onion/unicorn-public/
|
71
73
|
|
72
74
|
Mailing list subscription is optional, so Cc: all participants.
|
73
75
|
|
74
|
-
You can follow along via NNTP:
|
76
|
+
You can follow along via NNTP (read-only):
|
75
77
|
|
76
78
|
nntp://news.public-inbox.org/inbox.comp.lang.ruby.unicorn
|
77
79
|
nntp://news.gmane.org/gmane.comp.lang.ruby.unicorn.general
|
@@ -79,6 +81,7 @@ You can follow along via NNTP:
|
|
79
81
|
Or Atom feeds:
|
80
82
|
|
81
83
|
https://bogomips.org/unicorn-public/new.atom
|
84
|
+
http://ou63pmih66umazou.onion/unicorn-public/new.atom
|
82
85
|
|
83
86
|
The HTML archives at https://bogomips.org/unicorn-public/
|
84
87
|
also has links to per-thread Atom feeds and downloadable
|
@@ -88,3 +91,6 @@ You may optionally subscribe via plain-text email:
|
|
88
91
|
|
89
92
|
mailto:unicorn-public+subscribe@bogomips.org
|
90
93
|
(and confirming the auto-reply)
|
94
|
+
|
95
|
+
Just keep in mind we suck at delivering email, so using NNTP,
|
96
|
+
or Atom feeds might be a better bet...
|
data/Links
CHANGED
@@ -23,7 +23,7 @@ or services behind them.
|
|
23
23
|
* {golden_brindle}[https://github.com/simonoff/golden_brindle] - tool to
|
24
24
|
manage multiple unicorn instances/applications on a single server
|
25
25
|
|
26
|
-
* {raindrops}[
|
26
|
+
* {raindrops}[https://bogomips.org/raindrops/] - real-time stats for
|
27
27
|
preforking Rack servers
|
28
28
|
|
29
29
|
* {UnXF}[https://bogomips.org/unxf/] Un-X-Forward* the Rack environment,
|
data/lib/unicorn.rb
CHANGED
@@ -95,7 +95,7 @@ module Unicorn
|
|
95
95
|
|
96
96
|
# returns an array of strings representing TCP listen socket addresses
|
97
97
|
# and Unix domain socket paths. This is useful for use with
|
98
|
-
# Raindrops::Middleware under Linux:
|
98
|
+
# Raindrops::Middleware under Linux: https://bogomips.org/raindrops/
|
99
99
|
def self.listener_names
|
100
100
|
Unicorn::HttpServer::LISTENERS.map do |io|
|
101
101
|
Unicorn::SocketHelper.sock_name(io)
|
data/lib/unicorn/configurator.rb
CHANGED
@@ -54,9 +54,10 @@ class Unicorn::Configurator
|
|
54
54
|
},
|
55
55
|
:before_murder => nil,
|
56
56
|
:pid => nil,
|
57
|
+
:worker_exec => false,
|
57
58
|
:preload_app => false,
|
58
59
|
:check_client_connection => false,
|
59
|
-
:rewindable_input => true,
|
60
|
+
:rewindable_input => true,
|
60
61
|
:client_body_buffer_size => Unicorn::Const::MAX_BODY,
|
61
62
|
}
|
62
63
|
#:startdoc:
|
@@ -172,6 +173,8 @@ class Unicorn::Configurator
|
|
172
173
|
# server.logger.error("worker process failure: #{status.inspect}")
|
173
174
|
# end
|
174
175
|
# end
|
176
|
+
#
|
177
|
+
# after_worker_exit is only available in unicorn 5.3.0+
|
175
178
|
def after_worker_exit(*args, &block)
|
176
179
|
set_hook(:after_worker_exit, block_given? ? block : args[0], 3)
|
177
180
|
end
|
@@ -187,6 +190,8 @@ class Unicorn::Configurator
|
|
187
190
|
#
|
188
191
|
# Do not use Configurator#user if you rely on changing users in the
|
189
192
|
# after_worker_ready hook.
|
193
|
+
#
|
194
|
+
# after_worker_ready is only available in unicorn 5.3.0+
|
190
195
|
def after_worker_ready(*args, &block)
|
191
196
|
set_hook(:after_worker_ready, block_given? ? block : args[0])
|
192
197
|
end
|
@@ -263,6 +268,17 @@ class Unicorn::Configurator
|
|
263
268
|
set[:timeout] = seconds > max ? max : seconds
|
264
269
|
end
|
265
270
|
|
271
|
+
# Whether to exec in each worker process after forking. This changes the
|
272
|
+
# memory layout of each worker process, which is a security feature designed
|
273
|
+
# to defeat possible address space discovery attacks. Note that using
|
274
|
+
# worker_exec only makes sense if you are not preloading the application,
|
275
|
+
# and will result in higher memory usage.
|
276
|
+
#
|
277
|
+
# worker_exec is only available in unicorn 5.3.0+
|
278
|
+
def worker_exec(bool)
|
279
|
+
set_bool(:worker_exec, bool)
|
280
|
+
end
|
281
|
+
|
266
282
|
# sets the current number of worker_processes to +nr+. Each worker
|
267
283
|
# process will serve exactly one client at a time. You can
|
268
284
|
# increment or decrement this value at runtime by sending SIGTTIN
|
@@ -529,13 +545,12 @@ class Unicorn::Configurator
|
|
529
545
|
# Disabling rewindability can improve performance by lowering
|
530
546
|
# I/O and memory usage for applications that accept uploads.
|
531
547
|
# Keep in mind that the Rack 1.x spec requires
|
532
|
-
# \env[\"rack.input\"] to be rewindable,
|
533
|
-
#
|
548
|
+
# \env[\"rack.input\"] to be rewindable,
|
549
|
+
# but the Rack 2.x spec does not.
|
534
550
|
#
|
535
|
-
# +rewindable_input+ defaults to +true+
|
536
|
-
#
|
537
|
-
#
|
538
|
-
# (less demanding) spec.
|
551
|
+
# +rewindable_input+ defaults to +true+ for compatibility.
|
552
|
+
# Setting it to +false+ may be safe for applications and
|
553
|
+
# frameworks developed for Rack 2.x and later.
|
539
554
|
def rewindable_input(bool)
|
540
555
|
set_bool(:rewindable_input, bool)
|
541
556
|
end
|
data/lib/unicorn/http_request.rb
CHANGED
@@ -29,7 +29,7 @@ class Unicorn::HttpParser
|
|
29
29
|
EMPTY_ARRAY = [].freeze
|
30
30
|
@@input_class = Unicorn::TeeInput
|
31
31
|
@@check_client_connection = false
|
32
|
-
@@tcpi_inspect_ok =
|
32
|
+
@@tcpi_inspect_ok = Socket.const_defined?(:TCP_INFO)
|
33
33
|
|
34
34
|
def self.input_class
|
35
35
|
@@input_class
|
@@ -105,26 +105,47 @@ class Unicorn::HttpParser
|
|
105
105
|
env.include?('rack.hijack_io'.freeze)
|
106
106
|
end
|
107
107
|
|
108
|
-
if
|
108
|
+
if Raindrops.const_defined?(:TCP_Info)
|
109
|
+
TCPI = Raindrops::TCP_Info.allocate
|
110
|
+
|
109
111
|
def check_client_connection(socket) # :nodoc:
|
110
112
|
if Unicorn::TCPClient === socket
|
111
|
-
|
112
|
-
@@tcp_info.get!(socket)
|
113
|
+
# Raindrops::TCP_Info#get!, #state (reads struct tcp_info#tcpi_state)
|
113
114
|
raise Errno::EPIPE, "client closed connection".freeze,
|
114
|
-
EMPTY_ARRAY if closed_state?(
|
115
|
+
EMPTY_ARRAY if closed_state?(TCPI.get!(socket).state)
|
115
116
|
else
|
116
117
|
write_http_header(socket)
|
117
118
|
end
|
118
119
|
end
|
119
120
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
121
|
+
if Raindrops.const_defined?(:TCP)
|
122
|
+
# raindrops 0.18.0+ supports FreeBSD + Linux using the same names
|
123
|
+
# Evaluate these hash lookups at load time so we can
|
124
|
+
# generate an opt_case_dispatch instruction
|
125
|
+
eval <<-EOS
|
126
|
+
def closed_state?(state) # :nodoc:
|
127
|
+
case state
|
128
|
+
when #{Raindrops::TCP[:ESTABLISHED]}
|
129
|
+
false
|
130
|
+
when #{Raindrops::TCP.values_at(
|
131
|
+
:CLOSE_WAIT, :TIME_WAIT, :CLOSE, :LAST_ACK, :CLOSING).join(',')}
|
132
|
+
true
|
133
|
+
else
|
134
|
+
false
|
135
|
+
end
|
136
|
+
end
|
137
|
+
EOS
|
138
|
+
else
|
139
|
+
# raindrops before 0.18 only supported TCP_INFO under Linux
|
140
|
+
def closed_state?(state) # :nodoc:
|
141
|
+
case state
|
142
|
+
when 1 # ESTABLISHED
|
143
|
+
false
|
144
|
+
when 8, 6, 7, 9, 11 # CLOSE_WAIT, TIME_WAIT, CLOSE, LAST_ACK, CLOSING
|
145
|
+
true
|
146
|
+
else
|
147
|
+
false
|
148
|
+
end
|
128
149
|
end
|
129
150
|
end
|
130
151
|
else
|
@@ -134,9 +155,8 @@ class Unicorn::HttpParser
|
|
134
155
|
# work after a client gives up.
|
135
156
|
def check_client_connection(socket) # :nodoc:
|
136
157
|
if Unicorn::TCPClient === socket && @@tcpi_inspect_ok
|
137
|
-
opt = socket.getsockopt(
|
158
|
+
opt = socket.getsockopt(Socket::IPPROTO_TCP, Socket::TCP_INFO).inspect
|
138
159
|
if opt =~ /\bstate=(\S+)/
|
139
|
-
@@tcpi_inspect_ok = true
|
140
160
|
raise Errno::EPIPE, "client closed connection".freeze,
|
141
161
|
EMPTY_ARRAY if closed_state_str?($1)
|
142
162
|
else
|
data/lib/unicorn/http_server.rb
CHANGED
@@ -92,7 +92,8 @@ class Unicorn::HttpServer
|
|
92
92
|
@self_pipe = []
|
93
93
|
@workers = {} # hash maps PIDs to Workers
|
94
94
|
@sig_queue = [] # signal queue used for self-piping
|
95
|
-
@
|
95
|
+
@pid = nil
|
96
|
+
@before_murder_called = Set.new() # ensures before_murder is called only once
|
96
97
|
|
97
98
|
# we try inheriting listeners first, so we bind them later.
|
98
99
|
# we don't write the pid file until we've bound listeners in case
|
@@ -109,6 +110,14 @@ class Unicorn::HttpServer
|
|
109
110
|
# list of signals we care about and trap in master.
|
110
111
|
@queue_sigs = [
|
111
112
|
:WINCH, :QUIT, :INT, :TERM, :USR1, :USR2, :HUP, :TTIN, :TTOU ]
|
113
|
+
|
114
|
+
@worker_data = if worker_data = ENV['UNICORN_WORKER']
|
115
|
+
worker_data = worker_data.split(',').map!(&:to_i)
|
116
|
+
worker_data[1] = worker_data.slice!(1..2).map do |i|
|
117
|
+
Kgio::Pipe.for_fd(i)
|
118
|
+
end
|
119
|
+
worker_data
|
120
|
+
end
|
112
121
|
end
|
113
122
|
|
114
123
|
# Runs the thing. Returns self so you can run join on it
|
@@ -117,7 +126,7 @@ class Unicorn::HttpServer
|
|
117
126
|
# this pipe is used to wake us up from select(2) in #join when signals
|
118
127
|
# are trapped. See trap_deferred.
|
119
128
|
@self_pipe.replace(Unicorn.pipe)
|
120
|
-
@master_pid = $$
|
129
|
+
@master_pid = @worker_data ? Process.ppid : $$
|
121
130
|
|
122
131
|
# setup signal handlers before writing pid file in case people get
|
123
132
|
# trigger happy and send signals as soon as the pid file exists.
|
@@ -435,11 +444,7 @@ class Unicorn::HttpServer
|
|
435
444
|
end
|
436
445
|
|
437
446
|
@reexec_pid = fork do
|
438
|
-
listener_fds =
|
439
|
-
LISTENERS.each do |sock|
|
440
|
-
sock.close_on_exec = false
|
441
|
-
listener_fds[sock.fileno] = sock
|
442
|
-
end
|
447
|
+
listener_fds = listener_sockets
|
443
448
|
ENV['UNICORN_FD'] = listener_fds.keys.join(',')
|
444
449
|
Dir.chdir(START_CTX[:cwd])
|
445
450
|
cmd = [ START_CTX[0] ].concat(START_CTX[:argv])
|
@@ -447,12 +452,7 @@ class Unicorn::HttpServer
|
|
447
452
|
# avoid leaking FDs we don't know about, but let before_exec
|
448
453
|
# unset FD_CLOEXEC, if anything else in the app eventually
|
449
454
|
# relies on FD inheritence.
|
450
|
-
(
|
451
|
-
next if listener_fds.include?(io)
|
452
|
-
io = IO.for_fd(io) rescue next
|
453
|
-
io.autoclose = false
|
454
|
-
io.close_on_exec = true
|
455
|
-
end
|
455
|
+
close_sockets_on_exec(listener_fds)
|
456
456
|
|
457
457
|
# exec(command, hash) works in at least 1.9.1+, but will only be
|
458
458
|
# required in 1.9.4/2.0.0 at earliest.
|
@@ -464,6 +464,40 @@ class Unicorn::HttpServer
|
|
464
464
|
proc_name 'master (old)'
|
465
465
|
end
|
466
466
|
|
467
|
+
def worker_spawn(worker)
|
468
|
+
listener_fds = listener_sockets
|
469
|
+
env = {}
|
470
|
+
env['UNICORN_FD'] = listener_fds.keys.join(',')
|
471
|
+
|
472
|
+
listener_fds[worker.to_io.fileno] = worker.to_io
|
473
|
+
listener_fds[worker.master.fileno] = worker.master
|
474
|
+
|
475
|
+
worker_info = [worker.nr, worker.to_io.fileno, worker.master.fileno]
|
476
|
+
env['UNICORN_WORKER'] = worker_info.join(',')
|
477
|
+
|
478
|
+
close_sockets_on_exec(listener_fds)
|
479
|
+
|
480
|
+
Process.spawn(env, START_CTX[0], *START_CTX[:argv], listener_fds)
|
481
|
+
end
|
482
|
+
|
483
|
+
def listener_sockets
|
484
|
+
listener_fds = {}
|
485
|
+
LISTENERS.each do |sock|
|
486
|
+
sock.close_on_exec = false
|
487
|
+
listener_fds[sock.fileno] = sock
|
488
|
+
end
|
489
|
+
listener_fds
|
490
|
+
end
|
491
|
+
|
492
|
+
def close_sockets_on_exec(sockets)
|
493
|
+
(3..1024).each do |io|
|
494
|
+
next if sockets.include?(io)
|
495
|
+
io = IO.for_fd(io) rescue next
|
496
|
+
io.autoclose = false
|
497
|
+
io.close_on_exec = true
|
498
|
+
end
|
499
|
+
end
|
500
|
+
|
467
501
|
# forcibly terminate all workers that haven't checked in in timeout seconds. The timeout is implemented using an unlinked File
|
468
502
|
def murder_lazy_workers
|
469
503
|
next_sleep = @timeout - 1
|
@@ -502,19 +536,29 @@ class Unicorn::HttpServer
|
|
502
536
|
end
|
503
537
|
|
504
538
|
def spawn_missing_workers
|
539
|
+
if @worker_data
|
540
|
+
worker = Unicorn::Worker.new(*@worker_data)
|
541
|
+
after_fork_internal
|
542
|
+
worker_loop(worker)
|
543
|
+
exit
|
544
|
+
end
|
545
|
+
|
505
546
|
worker_nr = -1
|
506
547
|
until (worker_nr += 1) == @worker_processes
|
507
548
|
@workers.value?(worker_nr) and next
|
508
549
|
worker = Unicorn::Worker.new(worker_nr)
|
509
550
|
before_fork.call(self, worker)
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
551
|
+
|
552
|
+
pid = @worker_exec ? worker_spawn(worker) : fork
|
553
|
+
|
554
|
+
unless pid
|
514
555
|
after_fork_internal
|
515
556
|
worker_loop(worker)
|
516
557
|
exit
|
517
558
|
end
|
559
|
+
|
560
|
+
@workers[pid] = worker
|
561
|
+
worker.atfork_parent
|
518
562
|
end
|
519
563
|
rescue => e
|
520
564
|
@logger.error(e) rescue nil
|
@@ -75,12 +75,15 @@ module Unicorn
|
|
75
75
|
elsif respond_to?(:accf_arg)
|
76
76
|
name = opt[:accept_filter]
|
77
77
|
name = DEFAULTS[:accept_filter] if name.nil?
|
78
|
+
sock.listen(opt[:backlog])
|
79
|
+
got = (sock.getsockopt(:SOL_SOCKET, :SO_ACCEPTFILTER) rescue nil).to_s
|
80
|
+
arg = accf_arg(name)
|
78
81
|
begin
|
79
|
-
sock.setsockopt(:SOL_SOCKET, :SO_ACCEPTFILTER,
|
82
|
+
sock.setsockopt(:SOL_SOCKET, :SO_ACCEPTFILTER, arg)
|
80
83
|
rescue => e
|
81
84
|
logger.error("#{sock_name(sock)} " \
|
82
85
|
"failed to set accept_filter=#{name} (#{e.inspect})")
|
83
|
-
end
|
86
|
+
end if arg != got
|
84
87
|
end
|
85
88
|
end
|
86
89
|
|
data/lib/unicorn/stream_input.rb
CHANGED
@@ -1,16 +1,17 @@
|
|
1
1
|
# -*- encoding: binary -*-
|
2
2
|
|
3
|
-
# When processing uploads,
|
4
|
-
# "rack.input" of the
|
3
|
+
# When processing uploads, unicorn may expose a StreamInput object under
|
4
|
+
# "rack.input" of the Rack environment when
|
5
|
+
# Unicorn::Configurator#rewindable_input is set to +false+
|
5
6
|
class Unicorn::StreamInput
|
6
7
|
# The I/O chunk size (in +bytes+) for I/O operations where
|
7
8
|
# the size cannot be user-specified when a method is called.
|
8
9
|
# The default is 16 kilobytes.
|
9
|
-
@@io_chunk_size = Unicorn::Const::CHUNK_SIZE
|
10
|
+
@@io_chunk_size = Unicorn::Const::CHUNK_SIZE # :nodoc:
|
10
11
|
|
11
12
|
# Initializes a new StreamInput object. You normally do not have to call
|
12
13
|
# this unless you are writing an HTTP server.
|
13
|
-
def initialize(socket, request)
|
14
|
+
def initialize(socket, request) # :nodoc:
|
14
15
|
@chunked = request.content_length.nil?
|
15
16
|
@socket = socket
|
16
17
|
@parser = request
|
data/lib/unicorn/tee_input.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# -*- encoding: binary -*-
|
2
2
|
|
3
|
-
#
|
3
|
+
# Acts like tee(1) on an input input to provide a input-like stream
|
4
4
|
# while providing rewindable semantics through a File/StringIO backing
|
5
5
|
# store. On the first pass, the input is only read on demand so your
|
6
6
|
# Rack application can use input notification (upload progress and
|
@@ -9,22 +9,22 @@
|
|
9
9
|
# strict interpretation of Rack::Lint::InputWrapper functionality and
|
10
10
|
# will not support any deviations from it.
|
11
11
|
#
|
12
|
-
# When processing uploads,
|
13
|
-
# "rack.input" of the Rack environment.
|
12
|
+
# When processing uploads, unicorn exposes a TeeInput object under
|
13
|
+
# "rack.input" of the Rack environment by default.
|
14
14
|
class Unicorn::TeeInput < Unicorn::StreamInput
|
15
15
|
# The maximum size (in +bytes+) to buffer in memory before
|
16
16
|
# resorting to a temporary file. Default is 112 kilobytes.
|
17
|
-
@@client_body_buffer_size = Unicorn::Const::MAX_BODY
|
17
|
+
@@client_body_buffer_size = Unicorn::Const::MAX_BODY # :nodoc:
|
18
18
|
|
19
19
|
# sets the maximum size of request bodies to buffer in memory,
|
20
20
|
# amounts larger than this are buffered to the filesystem
|
21
|
-
def self.client_body_buffer_size=(bytes)
|
21
|
+
def self.client_body_buffer_size=(bytes) # :nodoc:
|
22
22
|
@@client_body_buffer_size = bytes
|
23
23
|
end
|
24
24
|
|
25
25
|
# returns the maximum size of request bodies to buffer in memory,
|
26
26
|
# amounts larger than this are buffered to the filesystem
|
27
|
-
def self.client_body_buffer_size
|
27
|
+
def self.client_body_buffer_size # :nodoc:
|
28
28
|
@@client_body_buffer_size
|
29
29
|
end
|
30
30
|
|
@@ -37,7 +37,7 @@ class Unicorn::TeeInput < Unicorn::StreamInput
|
|
37
37
|
|
38
38
|
# Initializes a new TeeInput object. You normally do not have to call
|
39
39
|
# this unless you are writing an HTTP server.
|
40
|
-
def initialize(socket, request)
|
40
|
+
def initialize(socket, request) # :nodoc:
|
41
41
|
@len = request.content_length
|
42
42
|
super
|
43
43
|
@tmp = @len && @len <= @@client_body_buffer_size ?
|
data/lib/unicorn/worker.rb
CHANGED
@@ -12,18 +12,19 @@ class Unicorn::Worker
|
|
12
12
|
# :stopdoc:
|
13
13
|
attr_accessor :nr, :switched
|
14
14
|
attr_reader :to_io # IO.select-compatible
|
15
|
+
attr_reader :master
|
15
16
|
|
16
17
|
PER_DROP = Raindrops::PAGE_SIZE / Raindrops::SIZE
|
17
18
|
DROPS = []
|
18
19
|
|
19
|
-
def initialize(nr)
|
20
|
+
def initialize(nr, pipe=nil)
|
20
21
|
drop_index = nr / PER_DROP
|
21
22
|
@raindrop = DROPS[drop_index] ||= Raindrops.new(PER_DROP)
|
22
23
|
@offset = nr % PER_DROP
|
23
24
|
@raindrop[@offset] = 0
|
24
25
|
@nr = nr
|
25
26
|
@switched = false
|
26
|
-
@to_io, @master = Unicorn.pipe
|
27
|
+
@to_io, @master = pipe || Unicorn.pipe
|
27
28
|
end
|
28
29
|
|
29
30
|
def atfork_child # :nodoc:
|
@@ -124,7 +125,10 @@ class Unicorn::Worker
|
|
124
125
|
# Any and all errors raised within this method will be propagated
|
125
126
|
# directly back to the caller (usually the +after_fork+ hook.
|
126
127
|
# These errors commonly include ArgumentError for specifying an
|
127
|
-
# invalid user/group and Errno::EPERM for insufficient privileges
|
128
|
+
# invalid user/group and Errno::EPERM for insufficient privileges.
|
129
|
+
#
|
130
|
+
# chroot support is only available in unicorn 5.3.0+
|
131
|
+
# user and group switching appeared in unicorn 0.94.0 (2009-11-05)
|
128
132
|
def user(user, group = nil, chroot = false)
|
129
133
|
# we do not protect the caller, checking Process.euid == 0 is
|
130
134
|
# insufficient because modern systems have fine-grained
|
data/t/test-lib.sh
CHANGED
@@ -106,8 +106,8 @@ check_stderr () {
|
|
106
106
|
# unicorn_setup
|
107
107
|
unicorn_setup () {
|
108
108
|
eval $(unused_listen)
|
109
|
-
port=$(expr $listen : '[^:]*:\([0-9]
|
110
|
-
host=$(expr $listen : '\([^:]*\):[0-9]
|
109
|
+
port=$(expr $listen : '[^:]*:\([0-9]*\)')
|
110
|
+
host=$(expr $listen : '\([^:][^:]*\):[0-9][0-9]*')
|
111
111
|
|
112
112
|
rtmpfiles unicorn_config pid r_err r_out fifo tmp ok
|
113
113
|
cat > $unicorn_config <<EOF
|
data/test/exec/test_exec.rb
CHANGED
@@ -97,6 +97,9 @@ run lambda { |env|
|
|
97
97
|
end
|
98
98
|
|
99
99
|
def test_sd_listen_fds_emulation
|
100
|
+
# [ruby-core:69895] [Bug #11336] fixed by r51576
|
101
|
+
return if RUBY_VERSION.to_f < 2.3
|
102
|
+
|
100
103
|
File.open("config.ru", "wb") { |fp| fp.write(HI) }
|
101
104
|
sock = TCPServer.new(@addr, @port)
|
102
105
|
|
@@ -119,14 +122,12 @@ run lambda { |env|
|
|
119
122
|
res = hit(["http://#@addr:#@port/"])
|
120
123
|
assert_equal [ "HI\n" ], res
|
121
124
|
assert_shutdown(pid)
|
122
|
-
|
125
|
+
assert sock.getsockopt(:SOL_SOCKET, :SO_KEEPALIVE).bool,
|
123
126
|
'unicorn should always set SO_KEEPALIVE on inherited sockets'
|
124
127
|
end
|
125
128
|
ensure
|
126
129
|
sock.close if sock
|
127
|
-
|
128
|
-
# [ruby-core:69895] [Bug #11336] fixed by r51576
|
129
|
-
end if RUBY_VERSION.to_f >= 2.3
|
130
|
+
end
|
130
131
|
|
131
132
|
def test_inherit_listener_unspecified
|
132
133
|
File.open("config.ru", "wb") { |fp| fp.write(HI) }
|
@@ -142,7 +143,7 @@ run lambda { |env|
|
|
142
143
|
res = hit(["http://#@addr:#@port/"])
|
143
144
|
assert_equal [ "HI\n" ], res
|
144
145
|
assert_shutdown(pid)
|
145
|
-
|
146
|
+
assert sock.getsockopt(:SOL_SOCKET, :SO_KEEPALIVE).bool,
|
146
147
|
'unicorn should always set SO_KEEPALIVE on inherited sockets'
|
147
148
|
ensure
|
148
149
|
sock.close if sock
|
@@ -851,24 +851,6 @@ class HttpParserTest < Test::Unit::TestCase
|
|
851
851
|
assert_equal '', parser.env['HTTP_HOST']
|
852
852
|
end
|
853
853
|
|
854
|
-
# so we don't care about the portability of this test
|
855
|
-
# if it doesn't leak on Linux, it won't leak anywhere else
|
856
|
-
# unless your C compiler or platform is otherwise broken
|
857
|
-
LINUX_PROC_PID_STATUS = "/proc/self/status"
|
858
|
-
def test_memory_leak
|
859
|
-
match_rss = /^VmRSS:\s+(\d+)/
|
860
|
-
if File.read(LINUX_PROC_PID_STATUS) =~ match_rss
|
861
|
-
before = $1.to_i
|
862
|
-
1000000.times { Unicorn::HttpParser.new }
|
863
|
-
File.read(LINUX_PROC_PID_STATUS) =~ match_rss
|
864
|
-
after = $1.to_i
|
865
|
-
diff = after - before
|
866
|
-
assert(diff < 10000, "memory grew more than 10M: #{diff}")
|
867
|
-
end
|
868
|
-
end if RUBY_PLATFORM =~ /linux/ &&
|
869
|
-
File.readable?(LINUX_PROC_PID_STATUS) &&
|
870
|
-
!defined?(RUBY_ENGINE)
|
871
|
-
|
872
854
|
def test_memsize
|
873
855
|
require 'objspace'
|
874
856
|
if ObjectSpace.respond_to?(:memsize_of)
|
@@ -150,28 +150,31 @@ class TestSocketHelper < Test::Unit::TestCase
|
|
150
150
|
end
|
151
151
|
|
152
152
|
def test_tcp_defer_accept_default
|
153
|
+
return unless defined?(TCP_DEFER_ACCEPT)
|
153
154
|
port = unused_port @test_addr
|
154
155
|
name = "#@test_addr:#{port}"
|
155
156
|
sock = bind_listen(name)
|
156
157
|
cur = sock.getsockopt(Socket::SOL_TCP, TCP_DEFER_ACCEPT).unpack('i')[0]
|
157
158
|
assert cur >= 1
|
158
|
-
end
|
159
|
+
end
|
159
160
|
|
160
161
|
def test_tcp_defer_accept_disable
|
162
|
+
return unless defined?(TCP_DEFER_ACCEPT)
|
161
163
|
port = unused_port @test_addr
|
162
164
|
name = "#@test_addr:#{port}"
|
163
165
|
sock = bind_listen(name, :tcp_defer_accept => false)
|
164
166
|
cur = sock.getsockopt(Socket::SOL_TCP, TCP_DEFER_ACCEPT).unpack('i')[0]
|
165
167
|
assert_equal 0, cur
|
166
|
-
end
|
168
|
+
end
|
167
169
|
|
168
170
|
def test_tcp_defer_accept_nr
|
171
|
+
return unless defined?(TCP_DEFER_ACCEPT)
|
169
172
|
port = unused_port @test_addr
|
170
173
|
name = "#@test_addr:#{port}"
|
171
174
|
sock = bind_listen(name, :tcp_defer_accept => 60)
|
172
175
|
cur = sock.getsockopt(Socket::SOL_TCP, TCP_DEFER_ACCEPT).unpack('i')[0]
|
173
176
|
assert cur > 1
|
174
|
-
end
|
177
|
+
end
|
175
178
|
|
176
179
|
def test_ipv6only
|
177
180
|
port = begin
|
@@ -186,6 +189,7 @@ class TestSocketHelper < Test::Unit::TestCase
|
|
186
189
|
end
|
187
190
|
|
188
191
|
def test_reuseport
|
192
|
+
return unless defined?(Socket::SO_REUSEPORT)
|
189
193
|
port = unused_port @test_addr
|
190
194
|
name = "#@test_addr:#{port}"
|
191
195
|
sock = bind_listen(name, :reuseport => true)
|
@@ -193,5 +197,5 @@ class TestSocketHelper < Test::Unit::TestCase
|
|
193
197
|
assert_operator cur, :>, 0
|
194
198
|
rescue Errno::ENOPROTOOPT
|
195
199
|
# kernel does not support SO_REUSEPORT (older Linux)
|
196
|
-
end
|
200
|
+
end
|
197
201
|
end
|
data/test/unit/test_util.rb
CHANGED
@@ -69,7 +69,7 @@ class TestUtil < Test::Unit::TestCase
|
|
69
69
|
}
|
70
70
|
}
|
71
71
|
tmp.close!
|
72
|
-
end
|
72
|
+
end
|
73
73
|
|
74
74
|
def test_reopen_logs_renamed_with_internal_encoding
|
75
75
|
tmp = Tempfile.new('')
|
@@ -101,5 +101,5 @@ class TestUtil < Test::Unit::TestCase
|
|
101
101
|
}
|
102
102
|
}
|
103
103
|
tmp.close!
|
104
|
-
end
|
104
|
+
end
|
105
105
|
end
|
data/unicorn.gemspec
CHANGED
@@ -1,9 +1,6 @@
|
|
1
1
|
# -*- encoding: binary -*-
|
2
|
-
|
3
|
-
|
4
|
-
require 'olddoc'
|
5
|
-
extend Olddoc::Gemspec
|
6
|
-
name, summary, title = readme_metadata
|
2
|
+
manifest = File.exist?('.manifest') ?
|
3
|
+
IO.readlines('.manifest').map!(&:chomp!) : `git ls-files`.split("\n")
|
7
4
|
|
8
5
|
# don't bother with tests that fork, not worth our time to get working
|
9
6
|
# with `gem check -t` ... (of course we care for them when testing with
|
@@ -14,16 +11,18 @@ end.compact
|
|
14
11
|
|
15
12
|
Gem::Specification.new do |s|
|
16
13
|
s.name = %q{unicorn-shopify}
|
17
|
-
s.version = ENV[
|
18
|
-
s.authors = [
|
19
|
-
s.summary =
|
20
|
-
s.description =
|
14
|
+
s.version = (ENV['VERSION'] || '5.3.0').dup
|
15
|
+
s.authors = ['unicorn hackers']
|
16
|
+
s.summary = 'Rack HTTP server for fast clients and Unix'
|
17
|
+
s.description = File.read('README').split("\n\n")[1]
|
21
18
|
s.email = %q{unicorn-public@bogomips.org}
|
22
19
|
s.executables = %w(unicorn unicorn_rails)
|
23
20
|
s.extensions = %w(ext/unicorn_http/extconf.rb)
|
24
|
-
s.extra_rdoc_files =
|
21
|
+
s.extra_rdoc_files = IO.readlines('.document').map!(&:chomp!).keep_if do |f|
|
22
|
+
File.exist?(f)
|
23
|
+
end
|
25
24
|
s.files = manifest
|
26
|
-
s.homepage =
|
25
|
+
s.homepage = 'https://bogomips.org/unicorn/'
|
27
26
|
s.test_files = test_files
|
28
27
|
|
29
28
|
# technically we need ">= 1.9.3", too, but avoid the array here since
|
@@ -40,7 +39,6 @@ Gem::Specification.new do |s|
|
|
40
39
|
s.add_dependency(%q<raindrops>, '~> 0.7')
|
41
40
|
|
42
41
|
s.add_development_dependency('test-unit', '~> 3.0')
|
43
|
-
s.add_development_dependency('olddoc', '~> 1.2')
|
44
42
|
|
45
43
|
# Note: To avoid ambiguity, we intentionally avoid the SPDX-compatible
|
46
44
|
# 'Ruby' here since Ruby 1.9.3 switched to BSD-2-Clause, but we
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: unicorn-shopify
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- unicorn hackers
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-04-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -66,20 +66,6 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '3.0'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: olddoc
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - "~>"
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '1.2'
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - "~>"
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '1.2'
|
83
69
|
description: |-
|
84
70
|
unicorn is an HTTP server for Rack applications designed to only serve
|
85
71
|
fast clients on low-latency, high-bandwidth connections and take
|
@@ -297,7 +283,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
297
283
|
version: '0'
|
298
284
|
requirements: []
|
299
285
|
rubyforge_project:
|
300
|
-
rubygems_version: 2.6.
|
286
|
+
rubygems_version: 2.6.10
|
301
287
|
signing_key:
|
302
288
|
specification_version: 4
|
303
289
|
summary: Rack HTTP server for fast clients and Unix
|