unicorn-camilo 4.8.2.5.19 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/.document +0 -1
  3. data/.gitignore +2 -2
  4. data/{.wrongdoc.yml → .olddoc.yml} +7 -2
  5. data/Documentation/unicorn.1.txt +9 -2
  6. data/Documentation/unicorn_rails.1.txt +2 -2
  7. data/FAQ +9 -1
  8. data/GIT-VERSION-GEN +1 -1
  9. data/GNUmakefile +31 -46
  10. data/HACKING +13 -27
  11. data/ISSUES +80 -16
  12. data/KNOWN_ISSUES +10 -10
  13. data/Links +10 -7
  14. data/PHILOSOPHY +1 -1
  15. data/README +8 -13
  16. data/Rakefile +0 -44
  17. data/Sandbox +1 -1
  18. data/TUNING +6 -3
  19. data/archive/.gitignore +3 -0
  20. data/archive/slrnpull.conf +4 -0
  21. data/bin/unicorn +1 -1
  22. data/bin/unicorn_rails +1 -1
  23. data/examples/unicorn.conf.rb +11 -0
  24. data/ext/unicorn_http/httpdate.c +1 -1
  25. data/ext/unicorn_http/unicorn_http.rl +48 -150
  26. data/lib/unicorn.rb +9 -15
  27. data/lib/unicorn/configurator.rb +3 -20
  28. data/lib/unicorn/const.rb +2 -25
  29. data/lib/unicorn/http_request.rb +4 -1
  30. data/lib/unicorn/http_response.rb +1 -3
  31. data/lib/unicorn/http_server.rb +85 -86
  32. data/lib/unicorn/socket_helper.rb +33 -67
  33. data/lib/unicorn/tee_input.rb +8 -1
  34. data/lib/unicorn/tmpio.rb +2 -4
  35. data/lib/unicorn/util.rb +1 -0
  36. data/lib/unicorn/worker.rb +1 -13
  37. data/t/GNUmakefile +1 -5
  38. data/t/README +1 -1
  39. data/t/t0002-parser-error.sh +3 -3
  40. data/test/exec/test_exec.rb +1 -1
  41. data/test/test_helper.rb +2 -2
  42. data/test/unit/test_http_parser.rb +3 -3
  43. data/test/unit/test_http_parser_ng.rb +8 -117
  44. data/test/unit/test_request.rb +1 -1
  45. data/test/unit/test_response.rb +3 -9
  46. data/test/unit/test_server.rb +3 -3
  47. data/test/unit/test_signals.rb +1 -1
  48. data/test/unit/test_socket_helper.rb +5 -5
  49. data/test/unit/test_tee_input.rb +10 -0
  50. data/test/unit/test_upload.rb +1 -1
  51. data/test/unit/test_util.rb +1 -1
  52. data/unicorn.gemspec +7 -10
  53. metadata +15 -33
  54. data/examples/git.ru +0 -13
  55. data/lib/unicorn/app/exec_cgi.rb +0 -154
  56. data/lib/unicorn/app/inetd.rb +0 -109
  57. data/lib/unicorn/ssl_client.rb +0 -11
  58. data/lib/unicorn/ssl_configurator.rb +0 -104
  59. data/lib/unicorn/ssl_server.rb +0 -42
  60. data/local.mk.sample +0 -59
  61. data/script/isolate_for_tests +0 -31
  62. data/t/t0016-trust-x-forwarded-false.sh +0 -30
  63. data/t/t0017-trust-x-forwarded-true.sh +0 -30
  64. data/test/unit/test_http_parser_xftrust.rb +0 -38
  65. data/test/unit/test_sni_hostnames.rb +0 -47
data/lib/unicorn.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  # -*- encoding: binary -*-
2
- require 'fcntl'
3
2
  require 'etc'
4
3
  require 'stringio'
5
4
  require 'rack'
@@ -22,8 +21,7 @@ module Unicorn
22
21
  # since there is nothing in the application stack that is responsible
23
22
  # for client shutdowns/disconnects. This exception is visible to Rack
24
23
  # applications unless PrereadInput middleware is loaded.
25
- class ClientShutdown < EOFError
26
- end
24
+ ClientShutdown = Class.new(EOFError)
27
25
 
28
26
  # :stopdoc:
29
27
 
@@ -67,6 +65,7 @@ module Unicorn
67
65
  use Rack::CommonLogger, $stderr
68
66
  use Rack::ShowExceptions
69
67
  use Rack::Lint
68
+ use Rack::TempfileReaper if Rack.const_defined?(:TempfileReaper)
70
69
  run inner_app
71
70
  end.to_app
72
71
  when "deployment"
@@ -74,6 +73,7 @@ module Unicorn
74
73
  use Rack::ContentLength
75
74
  use Rack::Chunked
76
75
  use Rack::CommonLogger, $stderr
76
+ use Rack::TempfileReaper if Rack.const_defined?(:TempfileReaper)
77
77
  run inner_app
78
78
  end.to_app
79
79
  else
@@ -100,19 +100,13 @@ module Unicorn
100
100
 
101
101
  # remove this when we only support Ruby >= 2.0
102
102
  def self.pipe # :nodoc:
103
- Kgio::Pipe.new.each { |io| io.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) }
103
+ Kgio::Pipe.new.each { |io| io.close_on_exec = true }
104
104
  end
105
105
  # :startdoc:
106
106
  end
107
107
  # :enddoc:
108
- require 'unicorn/const'
109
- require 'unicorn/socket_helper'
110
- require 'unicorn/stream_input'
111
- require 'unicorn/tee_input'
112
- require 'unicorn/http_request'
113
- require 'unicorn/configurator'
114
- require 'unicorn/tmpio'
115
- require 'unicorn/util'
116
- require 'unicorn/http_response'
117
- require 'unicorn/worker'
118
- require 'unicorn/http_server'
108
+
109
+ %w(const socket_helper stream_input tee_input http_request configurator
110
+ tmpio util http_response worker http_server).each do |s|
111
+ require_relative "unicorn/#{s}"
112
+ end
@@ -1,6 +1,5 @@
1
1
  # -*- encoding: binary -*-
2
2
  require 'logger'
3
- require 'unicorn/ssl_configurator'
4
3
 
5
4
  # Implements a simple DSL for configuring a \Unicorn server.
6
5
  #
@@ -13,7 +12,6 @@ require 'unicorn/ssl_configurator'
13
12
  # See the link:/TUNING.html document for more information on tuning unicorn.
14
13
  class Unicorn::Configurator
15
14
  include Unicorn
16
- include Unicorn::SSLConfigurator
17
15
 
18
16
  # :stopdoc:
19
17
  attr_accessor :set, :config_file, :after_reload
@@ -49,7 +47,6 @@ class Unicorn::Configurator
49
47
  :check_client_connection => false,
50
48
  :rewindable_input => true, # for Rack 2.x: (Rack::VERSION[0] <= 1),
51
49
  :client_body_buffer_size => Unicorn::Const::MAX_BODY,
52
- :trust_x_forwarded => true,
53
50
  }
54
51
  #:startdoc:
55
52
 
@@ -172,7 +169,7 @@ class Unicorn::Configurator
172
169
  set_hook(:before_exec, block_given? ? block : args[0], 1)
173
170
  end
174
171
 
175
- # Sets the before_murder hook to a gien Proc object. This Proc object
172
+ # Sets the before_murder hook to a given Proc object. This Proc object
176
173
  # will be called by the master process before killing a lazy worker
177
174
  # with SIGKILL, the point of this callback is NOT to prevent killing
178
175
  # but to provide an instrumentation hook
@@ -333,8 +330,6 @@ class Unicorn::Configurator
333
330
  # to receive IPv4 queries on dual-stack systems. A separate IPv4-only
334
331
  # listener is required if this is true.
335
332
  #
336
- # This option is only available for Ruby 1.9.2 and later.
337
- #
338
333
  # Enabling this option for the IPv6-only listener and having a
339
334
  # separate IPv4 listener is recommended if you wish to support IPv6
340
335
  # on the same TCP port. Otherwise, the value of \env[\"REMOTE_ADDR\"]
@@ -582,18 +577,6 @@ class Unicorn::Configurator
582
577
  set[:user] = [ user, group ]
583
578
  end
584
579
 
585
- # Sets whether or not the parser will trust X-Forwarded-Proto and
586
- # X-Forwarded-SSL headers and set "rack.url_scheme" to "https" accordingly.
587
- # Rainbows!/Zbatery installations facing untrusted clients directly
588
- # should set this to +false+. This is +true+ by default as Unicorn
589
- # is designed to only sit behind trusted nginx proxies.
590
- #
591
- # This has never been publically documented and is subject to removal
592
- # in future releases.
593
- def trust_x_forwarded(bool) # :nodoc:
594
- set_bool(:trust_x_forwarded, bool)
595
- end
596
-
597
580
  # expands "unix:path/to/foo" to a socket relative to the current path
598
581
  # expands pathnames of sockets if relative to "~" or "~username"
599
582
  # expands "*:port and ":port" to "0.0.0.0:port"
@@ -627,7 +610,7 @@ private
627
610
  def canonicalize_tcp(addr, port)
628
611
  packed = Socket.pack_sockaddr_in(port, addr)
629
612
  port, addr = Socket.unpack_sockaddr_in(packed)
630
- /:/ =~ addr ? "[#{addr}]:#{port}" : "#{addr}:#{port}"
613
+ addr.include?(':') ? "[#{addr}]:#{port}" : "#{addr}:#{port}"
631
614
  end
632
615
 
633
616
  def set_path(var, path) #:nodoc:
@@ -683,7 +666,7 @@ private
683
666
  raise ArgumentError, "rackup file (#{ru}) not readable"
684
667
 
685
668
  # it could be a .rb file, too, we don't parse those manually
686
- ru =~ /\.ru\z/ or return
669
+ ru.end_with?('.ru') or return
687
670
 
688
671
  /^#\\(.*)/ =~ File.read(ru) or return
689
672
  RACKUP[:optparse].parse!($1.split(/\s+/))
data/lib/unicorn/const.rb CHANGED
@@ -1,12 +1,6 @@
1
1
  # -*- encoding: binary -*-
2
2
 
3
- # :enddoc:
4
- # Frequently used constants when constructing requests or responses.
5
- # Many times the constant just refers to a string with the same
6
- # contents. Using these constants gave about a 3% to 10% performance
7
- # improvement over using the strings directly. Symbols did not really
8
- # improve things much compared to constants.
9
- module Unicorn::Const
3
+ module Unicorn::Const # :nodoc:
10
4
  # default TCP listen host address (0.0.0.0, all interfaces)
11
5
  DEFAULT_HOST = "0.0.0.0"
12
6
 
@@ -23,22 +17,5 @@ module Unicorn::Const
23
17
  # temporary file for reading (112 kilobytes). This is the default
24
18
  # value of client_body_buffer_size.
25
19
  MAX_BODY = 1024 * 112
26
-
27
- # :stopdoc:
28
- # common errors we'll send back
29
- # (N.B. these are not used by unicorn, but we won't drop them until
30
- # unicorn 5.x to avoid breaking Rainbows!).
31
- ERROR_400_RESPONSE = "HTTP/1.1 400 Bad Request\r\n\r\n"
32
- ERROR_414_RESPONSE = "HTTP/1.1 414 Request-URI Too Long\r\n\r\n"
33
- ERROR_413_RESPONSE = "HTTP/1.1 413 Request Entity Too Large\r\n\r\n"
34
- ERROR_500_RESPONSE = "HTTP/1.1 500 Internal Server Error\r\n\r\n"
35
-
36
- EXPECT_100_RESPONSE = "HTTP/1.1 100 Continue\r\n\r\n"
37
- EXPECT_100_RESPONSE_SUFFIXED = "100 Continue\r\n\r\nHTTP/1.1 "
38
-
39
- HTTP_RESPONSE_START = ['HTTP', '/1.1 ']
40
- HTTP_EXPECT = "HTTP_EXPECT"
41
-
42
- # :startdoc:
43
20
  end
44
- require 'unicorn/version'
21
+ require_relative 'version'
@@ -26,8 +26,11 @@ class Unicorn::HttpParser
26
26
 
27
27
  # :stopdoc:
28
28
  # A frozen format for this is about 15% faster
29
+ # Drop these frozen strings when Ruby 2.2 becomes more prevalent,
30
+ # 2.2+ optimizes hash assignments when used with literal string keys
29
31
  REMOTE_ADDR = 'REMOTE_ADDR'.freeze
30
32
  RACK_INPUT = 'rack.input'.freeze
33
+ HTTP_RESPONSE_START = [ 'HTTP', '/1.1 ']
31
34
  @@input_class = Unicorn::TeeInput
32
35
  @@check_client_connection = false
33
36
 
@@ -86,7 +89,7 @@ class Unicorn::HttpParser
86
89
  # detect if the socket is valid by writing a partial response:
87
90
  if @@check_client_connection && headers?
88
91
  @response_start_sent = true
89
- Unicorn::Const::HTTP_RESPONSE_START.each { |c| socket.write(c) }
92
+ HTTP_RESPONSE_START.each { |c| socket.write(c) }
90
93
  end
91
94
 
92
95
  e[RACK_INPUT] = 0 == content_length ?
@@ -24,14 +24,12 @@ module Unicorn::HttpResponse
24
24
  # writes the rack_response to socket as an HTTP response
25
25
  def http_response_write(socket, status, headers, body,
26
26
  response_start_sent=false)
27
- status = CODES[status.to_i] || status
28
27
  hijack = nil
29
28
 
30
29
  http_response_start = response_start_sent ? '' : 'HTTP/1.1 '
31
30
  if headers
32
- buf = "#{http_response_start}#{status}\r\n" \
31
+ buf = "#{http_response_start}#{CODES[status.to_i] || status}\r\n" \
33
32
  "Date: #{httpdate}\r\n" \
34
- "Status: #{status}\r\n" \
35
33
  "Connection: close\r\n"
36
34
  headers.each do |key, value|
37
35
  case key
@@ -1,5 +1,4 @@
1
1
  # -*- encoding: binary -*-
2
- require "unicorn/ssl_server"
3
2
 
4
3
  # This is the process manager of Unicorn. This manages worker
5
4
  # processes which in turn handle the I/O and application process.
@@ -22,10 +21,6 @@ class Unicorn::HttpServer
22
21
  attr_reader :pid, :logger
23
22
  include Unicorn::SocketHelper
24
23
  include Unicorn::HttpResponse
25
- include Unicorn::SSLServer
26
-
27
- # backwards compatibility with 1.x
28
- Worker = Unicorn::Worker
29
24
 
30
25
  # all bound listener sockets
31
26
  LISTENERS = []
@@ -33,23 +28,6 @@ class Unicorn::HttpServer
33
28
  # listeners we have yet to bind
34
29
  NEW_LISTENERS = []
35
30
 
36
- # This hash maps PIDs to Workers
37
- WORKERS = {}
38
-
39
- # We use SELF_PIPE differently in the master and worker processes:
40
- #
41
- # * The master process never closes or reinitializes this once
42
- # initialized. Signal handlers in the master process will write to
43
- # it to wake up the master from IO.select in exactly the same manner
44
- # djb describes in http://cr.yp.to/docs/selfpipe.html
45
- #
46
- # * The workers immediately close the pipe they inherit. See the
47
- # Unicorn::Worker class for the pipe workers use.
48
- SELF_PIPE = []
49
-
50
- # signal queue used for self-piping
51
- SIG_QUEUE = []
52
-
53
31
  # list of signals we care about and trap in master.
54
32
  QUEUE_SIGS = [ :WINCH, :QUIT, :INT, :TERM, :USR1, :USR2, :HUP, :TTIN, :TTOU ]
55
33
 
@@ -70,9 +48,9 @@ class Unicorn::HttpServer
70
48
  # you can set the following in your Unicorn config file, HUP and then
71
49
  # continue with the traditional USR2 + QUIT upgrade steps:
72
50
  #
73
- # Unicorn::HttpServer::START_CTX[0] = "/home/bofh/1.9.2/bin/unicorn"
51
+ # Unicorn::HttpServer::START_CTX[0] = "/home/bofh/2.2.0/bin/unicorn"
74
52
  START_CTX = {
75
- :argv => ARGV.map { |arg| arg.dup },
53
+ :argv => ARGV.map(&:dup),
76
54
  0 => $0.dup,
77
55
  }
78
56
  # We favor ENV['PWD'] since it is (usually) symlink aware for Capistrano
@@ -101,6 +79,19 @@ class Unicorn::HttpServer
101
79
  self.config = Unicorn::Configurator.new(options)
102
80
  self.listener_opts = {}
103
81
 
82
+ # We use @self_pipe differently in the master and worker processes:
83
+ #
84
+ # * The master process never closes or reinitializes this once
85
+ # initialized. Signal handlers in the master process will write to
86
+ # it to wake up the master from IO.select in exactly the same manner
87
+ # djb describes in http://cr.yp.to/docs/selfpipe.html
88
+ #
89
+ # * The workers immediately close the pipe they inherit. See the
90
+ # Unicorn::Worker class for the pipe workers use.
91
+ @self_pipe = []
92
+ @workers = {} # hash maps PIDs to Workers
93
+ @sig_queue = [] # signal queue used for self-piping
94
+
104
95
  # we try inheriting listeners first, so we bind them later.
105
96
  # we don't write the pid file until we've bound listeners in case
106
97
  # unicorn was started twice by mistake. Even though our #pid= method
@@ -120,13 +111,13 @@ class Unicorn::HttpServer
120
111
  inherit_listeners!
121
112
  # this pipe is used to wake us up from select(2) in #join when signals
122
113
  # are trapped. See trap_deferred.
123
- SELF_PIPE.replace(Unicorn.pipe)
114
+ @self_pipe.replace(Unicorn.pipe)
124
115
  @master_pid = $$
125
116
 
126
117
  # setup signal handlers before writing pid file in case people get
127
118
  # trigger happy and send signals as soon as the pid file exists.
128
119
  # Note that signals don't actually get handled until the #join method
129
- QUEUE_SIGS.each { |sig| trap(sig) { SIG_QUEUE << sig; awaken_master } }
120
+ QUEUE_SIGS.each { |sig| trap(sig) { @sig_queue << sig; awaken_master } }
130
121
  trap(:CHLD) { awaken_master }
131
122
 
132
123
  # write pid early for Mongrel compatibility if we're not inheriting sockets
@@ -159,9 +150,6 @@ class Unicorn::HttpServer
159
150
 
160
151
  LISTENERS.delete_if do |io|
161
152
  if dead_names.include?(sock_name(io))
162
- IO_PURGATORY.delete_if do |pio|
163
- pio.fileno == io.fileno && (pio.close rescue nil).nil? # true
164
- end
165
153
  (io.close rescue nil).nil? # true
166
154
  else
167
155
  set_server_sockopt(io, listener_opts[sock_name(io)])
@@ -199,7 +187,7 @@ class Unicorn::HttpServer
199
187
  if path
200
188
  if x = valid_pid?(path)
201
189
  return path if pid && path == pid && x == $$
202
- if x == reexec_pid && pid =~ /\.oldbin\z/
190
+ if x == reexec_pid && pid.end_with?('.oldbin')
203
191
  logger.warn("will not set pid=#{path} while reexec-ed "\
204
192
  "child is running PID:#{x}")
205
193
  return
@@ -242,7 +230,7 @@ class Unicorn::HttpServer
242
230
  begin
243
231
  io = bind_listen(address, opt)
244
232
  unless Kgio::TCPServer === io || Kgio::UNIXServer === io
245
- prevent_autoclose(io)
233
+ io.autoclose = false
246
234
  io = server_cast(io)
247
235
  end
248
236
  logger.info "listening on addr=#{sock_name(io)} fd=#{io.fileno}"
@@ -268,21 +256,25 @@ class Unicorn::HttpServer
268
256
  # is signalling us too often.
269
257
  def join
270
258
  respawn = true
271
- last_check = Time.now
259
+ last_check = time_now
272
260
 
273
261
  proc_name 'master'
274
262
  logger.info "master process ready" # test_exec.rb relies on this message
275
263
  if @ready_pipe
276
- @ready_pipe.syswrite($$.to_s)
264
+ begin
265
+ @ready_pipe.syswrite($$.to_s)
266
+ rescue => e
267
+ logger.warn("grandparent died too soon?: #{e.message} (#{e.class})")
268
+ end
277
269
  @ready_pipe = @ready_pipe.close rescue nil
278
270
  end
279
271
  begin
280
272
  reap_all_workers
281
- case SIG_QUEUE.shift
273
+ case @sig_queue.shift
282
274
  when nil
283
275
  # avoid murdering workers after our master process (or the
284
276
  # machine) comes out of suspend/hibernation
285
- if (last_check + @timeout) >= (last_check = Time.now)
277
+ if (last_check + @timeout) >= (last_check = time_now)
286
278
  sleep_time = murder_lazy_workers
287
279
  else
288
280
  sleep_time = @timeout/2.0 + 1
@@ -336,8 +328,8 @@ class Unicorn::HttpServer
336
328
  # Terminates all workers, but does not exit master process
337
329
  def stop(graceful = true)
338
330
  self.listeners = []
339
- limit = Time.now + timeout
340
- until WORKERS.empty? || Time.now > limit
331
+ limit = time_now + timeout
332
+ until @workers.empty? || time_now > limit
341
333
  if graceful
342
334
  soft_kill_each_worker(:QUIT)
343
335
  else
@@ -366,14 +358,6 @@ class Unicorn::HttpServer
366
358
  Unicorn::TeeInput.client_body_buffer_size = bytes
367
359
  end
368
360
 
369
- def trust_x_forwarded
370
- Unicorn::HttpParser.trust_x_forwarded?
371
- end
372
-
373
- def trust_x_forwarded=(bool)
374
- Unicorn::HttpParser.trust_x_forwarded = bool
375
- end
376
-
377
361
  def check_client_connection
378
362
  Unicorn::HttpRequest.check_client_connection
379
363
  end
@@ -386,13 +370,17 @@ class Unicorn::HttpServer
386
370
 
387
371
  # wait for a signal hander to wake us up and then consume the pipe
388
372
  def master_sleep(sec)
389
- IO.select([ SELF_PIPE[0] ], nil, nil, sec) or return
390
- SELF_PIPE[0].kgio_tryread(11)
373
+ @self_pipe[0].kgio_wait_readable(sec) or return
374
+ # 11 bytes is the maximum string length which can be embedded within
375
+ # the Ruby itself and not require a separate malloc (on 32-bit MRI 1.9+).
376
+ # Most reads are only one byte here and uncommon, so it's not worth a
377
+ # persistent buffer, either:
378
+ @self_pipe[0].kgio_tryread(11)
391
379
  end
392
380
 
393
381
  def awaken_master
394
382
  return if $$ != @master_pid
395
- SELF_PIPE[1].kgio_trywrite('.') # wakeup master process from select
383
+ @self_pipe[1].kgio_trywrite('.') # wakeup master process from select
396
384
  end
397
385
 
398
386
  # reaps all unreaped workers
@@ -406,7 +394,7 @@ class Unicorn::HttpServer
406
394
  self.pid = pid.chomp('.oldbin') if pid
407
395
  proc_name 'master'
408
396
  else
409
- worker = WORKERS.delete(wpid) and worker.close rescue nil
397
+ worker = @workers.delete(wpid) and worker.close rescue nil
410
398
  m = "reaped #{status.inspect} worker=#{worker.nr rescue 'unknown'}"
411
399
  status.success? ? logger.info(m) : logger.error(m)
412
400
  end
@@ -444,10 +432,7 @@ class Unicorn::HttpServer
444
432
  self.reexec_pid = fork do
445
433
  listener_fds = {}
446
434
  LISTENERS.each do |sock|
447
- # IO#close_on_exec= will be available on any future version of
448
- # Ruby that sets FD_CLOEXEC by default on new file descriptors
449
- # ref: http://redmine.ruby-lang.org/issues/5041
450
- sock.close_on_exec = false if sock.respond_to?(:close_on_exec=)
435
+ sock.close_on_exec = false
451
436
  listener_fds[sock.fileno] = sock
452
437
  end
453
438
  ENV['UNICORN_FD'] = listener_fds.keys.join(',')
@@ -460,13 +445,13 @@ class Unicorn::HttpServer
460
445
  (3..1024).each do |io|
461
446
  next if listener_fds.include?(io)
462
447
  io = IO.for_fd(io) rescue next
463
- prevent_autoclose(io)
464
- io.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
448
+ io.autoclose = false
449
+ io.close_on_exec = true
465
450
  end
466
451
 
467
452
  # exec(command, hash) works in at least 1.9.1+, but will only be
468
453
  # required in 1.9.4/2.0.0 at earliest.
469
- cmd << listener_fds if RUBY_VERSION >= "1.9.1"
454
+ cmd << listener_fds
470
455
  logger.info "executing #{cmd.inspect} (in #{Dir.pwd})"
471
456
  before_exec.call(self)
472
457
  exec(*cmd)
@@ -477,8 +462,8 @@ class Unicorn::HttpServer
477
462
  # forcibly terminate all workers that haven't checked in in timeout seconds. The timeout is implemented using an unlinked File
478
463
  def murder_lazy_workers
479
464
  next_sleep = @timeout - 1
480
- now = Time.now.to_i
481
- WORKERS.dup.each_pair do |wpid, worker|
465
+ now = time_now.to_i
466
+ @workers.dup.each_pair do |wpid, worker|
482
467
  tick = worker.tick
483
468
  0 == tick and next # skip workers that haven't processed any clients
484
469
  diff = now - tick
@@ -497,7 +482,7 @@ class Unicorn::HttpServer
497
482
  end
498
483
 
499
484
  def after_fork_internal
500
- SELF_PIPE.each { |io| io.close }.clear # this is master-only, now
485
+ @self_pipe.each(&:close).clear # this is master-only, now
501
486
  @ready_pipe.close if @ready_pipe
502
487
  Unicorn::Configurator::RACKUP.clear
503
488
  @ready_pipe = @init_listeners = @before_exec = @before_fork = nil
@@ -512,11 +497,11 @@ class Unicorn::HttpServer
512
497
  def spawn_missing_workers
513
498
  worker_nr = -1
514
499
  until (worker_nr += 1) == @worker_processes
515
- WORKERS.value?(worker_nr) and next
516
- worker = Worker.new(worker_nr)
500
+ @workers.value?(worker_nr) and next
501
+ worker = Unicorn::Worker.new(worker_nr)
517
502
  before_fork.call(self, worker)
518
503
  if pid = fork
519
- WORKERS[pid] = worker
504
+ @workers[pid] = worker
520
505
  worker.atfork_parent
521
506
  else
522
507
  after_fork_internal
@@ -530,9 +515,9 @@ class Unicorn::HttpServer
530
515
  end
531
516
 
532
517
  def maintain_worker_count
533
- (off = WORKERS.size - worker_processes) == 0 and return
518
+ (off = @workers.size - worker_processes) == 0 and return
534
519
  off < 0 and return spawn_missing_workers
535
- WORKERS.each_value { |w| w.nr >= worker_processes and w.soft_kill(:QUIT) }
520
+ @workers.each_value { |w| w.nr >= worker_processes and w.soft_kill(:QUIT) }
536
521
  end
537
522
 
538
523
  # if we get any error, try to write something back to the client
@@ -560,12 +545,15 @@ class Unicorn::HttpServer
560
545
  rescue
561
546
  end
562
547
 
563
- def expect_100_response
564
- if @request.response_start_sent
565
- Unicorn::Const::EXPECT_100_RESPONSE_SUFFIXED
566
- else
567
- Unicorn::Const::EXPECT_100_RESPONSE
568
- end
548
+ def e100_response_write(client, env)
549
+ # We use String#freeze to avoid allocations under Ruby 2.1+
550
+ # Not many users hit this code path, so it's better to reduce the
551
+ # constant table sizes even for 1.9.3-2.0 users who'll hit extra
552
+ # allocations here.
553
+ client.write(@request.response_start_sent ?
554
+ "100 Continue\r\n\r\nHTTP/1.1 ".freeze :
555
+ "HTTP/1.1 100 Continue\r\n\r\n".freeze)
556
+ env.delete('HTTP_EXPECT'.freeze)
569
557
  end
570
558
 
571
559
  # once a client is accepted, it is processed in its entirety here
@@ -575,8 +563,7 @@ class Unicorn::HttpServer
575
563
  return if @request.hijacked?
576
564
 
577
565
  if 100 == status.to_i
578
- client.write(expect_100_response)
579
- env.delete(Unicorn::Const::HTTP_EXPECT)
566
+ e100_response_write(client, env)
580
567
  status, headers, body = @app.call(env)
581
568
  return if @request.hijacked?
582
569
  end
@@ -609,22 +596,21 @@ class Unicorn::HttpServer
609
596
  worker.atfork_child
610
597
  # we'll re-trap :QUIT later for graceful shutdown iff we accept clients
611
598
  EXIT_SIGS.each { |sig| trap(sig) { exit!(0) } }
612
- exit!(0) if (SIG_QUEUE & EXIT_SIGS)[0]
599
+ exit!(0) if (@sig_queue & EXIT_SIGS)[0]
613
600
  WORKER_QUEUE_SIGS.each { |sig| trap(sig, nil) }
614
601
  trap(:CHLD, 'DEFAULT')
615
- SIG_QUEUE.clear
602
+ @sig_queue.clear
616
603
  proc_name "worker[#{worker.nr}]"
617
604
  START_CTX.clear
618
- WORKERS.clear
605
+ @workers.clear
619
606
 
620
607
  after_fork.call(self, worker) # can drop perms and create listeners
621
- LISTENERS.each { |sock| sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) }
608
+ LISTENERS.each { |sock| sock.close_on_exec = true }
622
609
 
623
610
  worker.user(*user) if user.kind_of?(Array) && ! worker.switched
624
611
  self.timeout /= 2.0 # halve it for select()
625
612
  @config = nil
626
613
  build_app! unless preload_app
627
- ssl_enable!
628
614
  @after_fork = @listener_opts = @orig_app = nil
629
615
  readers = LISTENERS.dup
630
616
  readers << worker
@@ -659,7 +645,7 @@ class Unicorn::HttpServer
659
645
  begin
660
646
  nr < 0 and reopen_worker_logs(worker.nr)
661
647
  nr = 0
662
- worker.tick = Time.now.to_i
648
+ worker.tick = time_now.to_i
663
649
  tmp = ready.dup
664
650
  while sock = tmp.shift
665
651
  # Unicorn::Worker#kgio_tryaccept is not like accept(2) at all,
@@ -667,7 +653,7 @@ class Unicorn::HttpServer
667
653
  if client = sock.kgio_tryaccept
668
654
  process_client(client)
669
655
  nr += 1
670
- worker.tick = Time.now.to_i
656
+ worker.tick = time_now.to_i
671
657
  end
672
658
  break if nr < 0
673
659
  end
@@ -684,7 +670,7 @@ class Unicorn::HttpServer
684
670
  ppid == Process.ppid or return
685
671
 
686
672
  # timeout used so we can detect parent death:
687
- worker.tick = Time.now.to_i
673
+ worker.tick = time_now.to_i
688
674
  ret = IO.select(readers, nil, nil, @timeout) and ready = ret[0]
689
675
  rescue => e
690
676
  redo if nr < 0 && readers[0]
@@ -696,17 +682,17 @@ class Unicorn::HttpServer
696
682
  # is no longer running.
697
683
  def kill_worker(signal, wpid)
698
684
  Process.kill(signal, wpid)
699
- rescue Errno::ESRCH
700
- worker = WORKERS.delete(wpid) and worker.close rescue nil
685
+ rescue Errno::ESRCH
686
+ worker = @workers.delete(wpid) and worker.close rescue nil
701
687
  end
702
688
 
703
689
  # delivers a signal to each worker
704
690
  def kill_each_worker(signal)
705
- WORKERS.keys.each { |wpid| kill_worker(signal, wpid) }
691
+ @workers.keys.each { |wpid| kill_worker(signal, wpid) }
706
692
  end
707
693
 
708
694
  def soft_kill_each_worker(signal)
709
- WORKERS.each_value { |worker| worker.soft_kill(signal) }
695
+ @workers.each_value { |worker| worker.soft_kill(signal) }
710
696
  end
711
697
 
712
698
  # unlinks a PID file at given +path+ if it contains the current PID
@@ -776,10 +762,10 @@ class Unicorn::HttpServer
776
762
  def inherit_listeners!
777
763
  # inherit sockets from parents, they need to be plain Socket objects
778
764
  # before they become Kgio::UNIXServer or Kgio::TCPServer
779
- inherited = ENV['UNICORN_FD'].to_s.split(/,/).map do |fd|
765
+ inherited = ENV['UNICORN_FD'].to_s.split(',').map do |fd|
780
766
  io = Socket.for_fd(fd.to_i)
781
767
  set_server_sockopt(io, listener_opts[sock_name(io)])
782
- prevent_autoclose(io)
768
+ io.autoclose = false
783
769
  logger.info "inherited addr=#{sock_name(io)} fd=#{fd}"
784
770
  server_cast(io)
785
771
  end
@@ -808,4 +794,17 @@ class Unicorn::HttpServer
808
794
  raise ArgumentError, "no listeners" if LISTENERS.empty?
809
795
  NEW_LISTENERS.clear
810
796
  end
797
+
798
+ # try to use the monotonic clock in Ruby >= 2.1, it is immune to clock
799
+ # offset adjustments and generates less garbage (Float vs Time object)
800
+ begin
801
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
802
+ def time_now
803
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
804
+ end
805
+ rescue NameError, NoMethodError
806
+ def time_now # Ruby <= 2.0
807
+ Time.now
808
+ end
809
+ end
811
810
  end