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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e9a95c3be0067afe5dee931055be48711ae83633
4
- data.tar.gz: 90f5d52bb33af65c144500ba3c798a7d1e48566b
3
+ metadata.gz: b4f49b8a39233e5173cd9449ac97280d9981fbaf
4
+ data.tar.gz: 7d59709e0d4a4670a1d549f930e6f1557b3b986e
5
5
  SHA512:
6
- metadata.gz: d29329476ace3f59e2157bdfd5b3716dffb3de167244b7cf2d1377945c889a55745b5f6a2c1f534cf9409fa638db41989ed648c89b89a77cf401d874b666f4b2
7
- data.tar.gz: 4f09a550bbaf5b6b958c9f159c7910681106a96f5c02e07e906aeee556d1ca201670503dab2dd1767da27afbd8fc8e5099250ab28fbaea754b558994d93390e0
6
+ metadata.gz: ef1af3b1aec6f855844103eefef52848fae3af4dd2ecb73dc47a3df0da6d826a436a790a52935a31d9af22d6506148411dc5d08fe981a3ffb9c73500ddfbb240
7
+ data.tar.gz: 9b6af6386d99ab1cbc9b872b5a296240e11f68e59e12966a6d546c0d373749b884b1ba3bee3c49ef99777937ef879cf3bb0179ee78b3e2bd082c032c4d6deef4
@@ -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
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
- DEF_VER = "v5.2.0"
2
+ DEF_VER = "v5.3.0.pre1"
3
3
  CONSTANT = "Unicorn::Const::UNICORN_VERSION"
4
4
  RVF = "lib/unicorn/version.rb"
5
5
  GVF = "GIT-VERSION-FILE"
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, it will be flagged as spam
13
- * Anonymous and pseudonymous messages will always be welcome.
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
- then feel free to email us privately at mailto:unicorn@bogomips.org
19
- instead and your issue will be handled discreetly.
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}[http://raindrops.bogomips.org/] - real-time stats for
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,
@@ -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: http://raindrops.bogomips.org/
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)
@@ -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, # for Rack 2.x: (Rack::VERSION[0] <= 1),
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, so this allows
533
- # intentionally violating the current Rack 1.x spec.
548
+ # \env[\"rack.input\"] to be rewindable,
549
+ # but the Rack 2.x spec does not.
534
550
  #
535
- # +rewindable_input+ defaults to +true+ when used with Rack 1.x for
536
- # Rack conformance. When Rack 2.x is finalized, this will most
537
- # likely default to +false+ while still conforming to the newer
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
@@ -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 = true
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 defined?(Raindrops::TCP_Info)
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
- @@tcp_info ||= Raindrops::TCP_Info.new(socket)
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?(@@tcp_info.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
- def closed_state?(state) # :nodoc:
121
- case state
122
- when 1 # ESTABLISHED
123
- false
124
- when 8, 6, 7, 9, 11 # CLOSE_WAIT, TIME_WAIT, CLOSE, LAST_ACK, CLOSING
125
- true
126
- else
127
- false
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(:IPPROTO_TCP, :TCP_INFO).inspect
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
@@ -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
- @before_murder_called = Set.new # ensures before_murder is called only once
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
- (3..1024).each do |io|
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
- if pid = fork
511
- @workers[pid] = worker
512
- worker.atfork_parent
513
- else
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, accf_arg(name))
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
 
@@ -1,16 +1,17 @@
1
1
  # -*- encoding: binary -*-
2
2
 
3
- # When processing uploads, Unicorn may expose a StreamInput object under
4
- # "rack.input" of the (future) Rack (2.x) environment.
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
@@ -1,6 +1,6 @@
1
1
  # -*- encoding: binary -*-
2
2
 
3
- # acts like tee(1) on an input input to provide a input-like stream
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, Unicorn exposes a TeeInput object under
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 ?
@@ -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
@@ -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
@@ -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
- assert_equal 1, sock.getsockopt(:SOL_SOCKET, :SO_KEEPALIVE).int,
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
- # disabled test on old Rubies: https://bugs.ruby-lang.org/issues/11336
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
- assert_equal 1, sock.getsockopt(:SOL_SOCKET, :SO_KEEPALIVE).int,
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 if defined?(TCP_DEFER_ACCEPT)
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 if defined?(TCP_DEFER_ACCEPT)
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 if defined?(TCP_DEFER_ACCEPT)
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 if defined?(Socket::SO_REUSEPORT)
200
+ end
197
201
  end
@@ -69,7 +69,7 @@ class TestUtil < Test::Unit::TestCase
69
69
  }
70
70
  }
71
71
  tmp.close!
72
- end if STDIN.respond_to?(:external_encoding)
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 if STDIN.respond_to?(:external_encoding)
104
+ end
105
105
  end
@@ -1,9 +1,6 @@
1
1
  # -*- encoding: binary -*-
2
- ENV["VERSION"] or abort "VERSION= must be specified"
3
- manifest = File.readlines('.manifest').map! { |x| x.chomp! }
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["VERSION"]
18
- s.authors = ["#{name} hackers"]
19
- s.summary = summary
20
- s.description = readme_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 = extra_rdoc_files(manifest)
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 = Olddoc.config['rdoc_url']
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.2.0.6
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-03-13 00:00:00.000000000 Z
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.8
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