unicorn-shopify 5.2.0.6 → 5.3.0

Sign up to get free protection for your applications and to get access to all the features.
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