unicorn-fork 6.1.1

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 (145) hide show
  1. checksums.yaml +7 -0
  2. data/.CHANGELOG.old +25 -0
  3. data/.document +28 -0
  4. data/.gitattributes +5 -0
  5. data/.gitignore +25 -0
  6. data/.mailmap +26 -0
  7. data/.manifest +144 -0
  8. data/.olddoc.yml +25 -0
  9. data/Application_Timeouts +77 -0
  10. data/CONTRIBUTORS +39 -0
  11. data/COPYING +674 -0
  12. data/DESIGN +99 -0
  13. data/Documentation/.gitignore +3 -0
  14. data/Documentation/unicorn.1 +222 -0
  15. data/Documentation/unicorn_rails.1 +207 -0
  16. data/FAQ +70 -0
  17. data/GIT-VERSION-FILE +1 -0
  18. data/GIT-VERSION-GEN +39 -0
  19. data/GNUmakefile +318 -0
  20. data/HACKING +117 -0
  21. data/ISSUES +102 -0
  22. data/KNOWN_ISSUES +79 -0
  23. data/LICENSE +67 -0
  24. data/Links +58 -0
  25. data/PHILOSOPHY +139 -0
  26. data/README +165 -0
  27. data/Rakefile +17 -0
  28. data/SIGNALS +123 -0
  29. data/Sandbox +104 -0
  30. data/TODO +1 -0
  31. data/TUNING +119 -0
  32. data/archive/.gitignore +3 -0
  33. data/archive/slrnpull.conf +4 -0
  34. data/bin/unicorn +129 -0
  35. data/bin/unicorn_rails +210 -0
  36. data/examples/big_app_gc.rb +3 -0
  37. data/examples/echo.ru +27 -0
  38. data/examples/init.sh +102 -0
  39. data/examples/logger_mp_safe.rb +26 -0
  40. data/examples/logrotate.conf +44 -0
  41. data/examples/nginx.conf +156 -0
  42. data/examples/unicorn.conf.minimal.rb +14 -0
  43. data/examples/unicorn.conf.rb +111 -0
  44. data/examples/unicorn.socket +11 -0
  45. data/examples/unicorn@.service +40 -0
  46. data/ext/unicorn_http/CFLAGS +13 -0
  47. data/ext/unicorn_http/c_util.h +115 -0
  48. data/ext/unicorn_http/common_field_optimization.h +128 -0
  49. data/ext/unicorn_http/epollexclusive.h +128 -0
  50. data/ext/unicorn_http/ext_help.h +38 -0
  51. data/ext/unicorn_http/extconf.rb +40 -0
  52. data/ext/unicorn_http/global_variables.h +97 -0
  53. data/ext/unicorn_http/httpdate.c +91 -0
  54. data/ext/unicorn_http/unicorn_http.c +4348 -0
  55. data/ext/unicorn_http/unicorn_http.rl +1054 -0
  56. data/ext/unicorn_http/unicorn_http_common.rl +76 -0
  57. data/lib/unicorn/app/old_rails/static.rb +60 -0
  58. data/lib/unicorn/app/old_rails.rb +36 -0
  59. data/lib/unicorn/cgi_wrapper.rb +148 -0
  60. data/lib/unicorn/configurator.rb +749 -0
  61. data/lib/unicorn/const.rb +22 -0
  62. data/lib/unicorn/http_request.rb +180 -0
  63. data/lib/unicorn/http_response.rb +95 -0
  64. data/lib/unicorn/http_server.rb +860 -0
  65. data/lib/unicorn/launcher.rb +63 -0
  66. data/lib/unicorn/oob_gc.rb +82 -0
  67. data/lib/unicorn/preread_input.rb +34 -0
  68. data/lib/unicorn/select_waiter.rb +7 -0
  69. data/lib/unicorn/socket_helper.rb +186 -0
  70. data/lib/unicorn/stream_input.rb +152 -0
  71. data/lib/unicorn/tee_input.rb +132 -0
  72. data/lib/unicorn/tmpio.rb +34 -0
  73. data/lib/unicorn/util.rb +91 -0
  74. data/lib/unicorn/version.rb +1 -0
  75. data/lib/unicorn/worker.rb +166 -0
  76. data/lib/unicorn.rb +137 -0
  77. data/man/man1/unicorn.1 +222 -0
  78. data/man/man1/unicorn_rails.1 +207 -0
  79. data/setup.rb +1587 -0
  80. data/t/.gitignore +4 -0
  81. data/t/GNUmakefile +5 -0
  82. data/t/README +49 -0
  83. data/t/active-unix-socket.t +110 -0
  84. data/t/back-out-of-upgrade.t +44 -0
  85. data/t/bin/unused_listen +40 -0
  86. data/t/client_body_buffer_size.ru +15 -0
  87. data/t/client_body_buffer_size.t +79 -0
  88. data/t/detach.ru +12 -0
  89. data/t/env.ru +4 -0
  90. data/t/fails-rack-lint.ru +6 -0
  91. data/t/heartbeat-timeout.ru +13 -0
  92. data/t/heartbeat-timeout.t +60 -0
  93. data/t/integration.ru +129 -0
  94. data/t/integration.t +509 -0
  95. data/t/lib.perl +309 -0
  96. data/t/listener_names.ru +5 -0
  97. data/t/my-tap-lib.sh +201 -0
  98. data/t/oob_gc.ru +18 -0
  99. data/t/oob_gc_path.ru +18 -0
  100. data/t/pid.ru +4 -0
  101. data/t/preread_input.ru +23 -0
  102. data/t/reload-bad-config.t +49 -0
  103. data/t/reopen-logs.ru +14 -0
  104. data/t/reopen-logs.t +36 -0
  105. data/t/t0010-reap-logging.sh +55 -0
  106. data/t/t0012-reload-empty-config.sh +86 -0
  107. data/t/t0013-rewindable-input-false.sh +24 -0
  108. data/t/t0013.ru +13 -0
  109. data/t/t0014-rewindable-input-true.sh +24 -0
  110. data/t/t0014.ru +13 -0
  111. data/t/t0015-configurator-internals.sh +25 -0
  112. data/t/t0020-at_exit-handler.sh +49 -0
  113. data/t/t0021-process_detach.sh +29 -0
  114. data/t/t0022-listener_names-preload_app.sh +32 -0
  115. data/t/t0300-no-default-middleware.sh +20 -0
  116. data/t/t0301-no-default-middleware-ignored-in-config.sh +25 -0
  117. data/t/t0301.ru +14 -0
  118. data/t/t9001-oob_gc.sh +47 -0
  119. data/t/t9002-oob_gc-path.sh +75 -0
  120. data/t/test-lib.sh +125 -0
  121. data/t/winch_ttin.t +64 -0
  122. data/t/working_directory.t +86 -0
  123. data/test/aggregate.rb +16 -0
  124. data/test/benchmark/README +60 -0
  125. data/test/benchmark/dd.ru +19 -0
  126. data/test/benchmark/ddstream.ru +51 -0
  127. data/test/benchmark/readinput.ru +41 -0
  128. data/test/benchmark/stack.ru +9 -0
  129. data/test/benchmark/uconnect.perl +66 -0
  130. data/test/exec/README +5 -0
  131. data/test/exec/test_exec.rb +1030 -0
  132. data/test/test_helper.rb +307 -0
  133. data/test/unit/test_configurator.rb +176 -0
  134. data/test/unit/test_droplet.rb +29 -0
  135. data/test/unit/test_http_parser.rb +885 -0
  136. data/test/unit/test_http_parser_ng.rb +715 -0
  137. data/test/unit/test_server.rb +245 -0
  138. data/test/unit/test_signals.rb +189 -0
  139. data/test/unit/test_socket_helper.rb +160 -0
  140. data/test/unit/test_stream_input.rb +211 -0
  141. data/test/unit/test_tee_input.rb +304 -0
  142. data/test/unit/test_util.rb +132 -0
  143. data/test/unit/test_waiter.rb +35 -0
  144. data/unicorn.gemspec +49 -0
  145. metadata +266 -0
@@ -0,0 +1,749 @@
1
+ # -*- encoding: binary -*-
2
+ # frozen_string_literal: false
3
+ require 'logger'
4
+
5
+ # Implements a simple DSL for configuring a unicorn server.
6
+ #
7
+ # See https://yhbt.net/unicorn/examples/unicorn.conf.rb and
8
+ # https://yhbt.net/unicorn/examples/unicorn.conf.minimal.rb
9
+ # example configuration files. An example config file for use with
10
+ # nginx is also available at
11
+ # https://yhbt.net/unicorn/examples/nginx.conf
12
+ #
13
+ # See the link:/TUNING.html document for more information on tuning unicorn.
14
+ class Unicorn::Configurator
15
+ include Unicorn
16
+
17
+ # :stopdoc:
18
+ attr_accessor :set, :config_file, :after_reload
19
+
20
+ # used to stash stuff for deferred processing of cli options in
21
+ # config.ru after "working_directory" is bound. Do not rely on
22
+ # this being around later on...
23
+ RACKUP = {
24
+ :daemonize => false,
25
+ :host => Unicorn::Const::DEFAULT_HOST,
26
+ :port => Unicorn::Const::DEFAULT_PORT,
27
+ :set_listener => false,
28
+ :options => { :listeners => [] }
29
+ }
30
+
31
+ # Default settings for Unicorn
32
+ DEFAULTS = {
33
+ :timeout => 60,
34
+ :logger => Logger.new($stderr),
35
+ :worker_processes => 1,
36
+ :after_fork => lambda { |server, worker|
37
+ server.logger.info("worker=#{worker.nr} spawned pid=#{$$}")
38
+ },
39
+ :before_fork => lambda { |server, worker|
40
+ server.logger.info("worker=#{worker.nr} spawning...")
41
+ },
42
+ :before_exec => lambda { |server|
43
+ server.logger.info("forked child re-executing...")
44
+ },
45
+ :after_worker_exit => lambda { |server, worker, status|
46
+ m = "reaped #{status.inspect} worker=#{worker.nr rescue 'unknown'}"
47
+ if status.success?
48
+ server.logger.info(m)
49
+ else
50
+ server.logger.error(m)
51
+ end
52
+ },
53
+ :after_worker_ready => lambda { |server, worker|
54
+ server.logger.info("worker=#{worker.nr} ready")
55
+ },
56
+ :pid => nil,
57
+ :early_hints => false,
58
+ :worker_exec => false,
59
+ :preload_app => false,
60
+ :check_client_connection => false,
61
+ :rewindable_input => true,
62
+ :client_body_buffer_size => Unicorn::Const::MAX_BODY,
63
+ }
64
+ #:startdoc:
65
+
66
+ def initialize(defaults = {}) #:nodoc:
67
+ self.set = Hash.new(:unset)
68
+ @use_defaults = defaults.delete(:use_defaults)
69
+ self.config_file = defaults.delete(:config_file)
70
+
71
+ # after_reload is only used by unicorn_rails, unsupported otherwise
72
+ self.after_reload = defaults.delete(:after_reload)
73
+
74
+ set.merge!(DEFAULTS) if @use_defaults
75
+ defaults.each { |key, value| self.__send__(key, value) }
76
+ Hash === set[:listener_opts] or
77
+ set[:listener_opts] = Hash.new { |hash,key| hash[key] = {} }
78
+ Array === set[:listeners] or set[:listeners] = []
79
+ reload(false)
80
+ end
81
+
82
+ def reload(merge_defaults = true) #:nodoc:
83
+ if merge_defaults && @use_defaults
84
+ set.merge!(DEFAULTS) if @use_defaults
85
+ end
86
+ instance_eval(File.read(config_file), config_file) if config_file
87
+
88
+ parse_rackup_file
89
+
90
+ RACKUP[:set_listener] and
91
+ set[:listeners] << "#{RACKUP[:host]}:#{RACKUP[:port]}"
92
+
93
+ RACKUP[:no_default_middleware] and
94
+ set[:default_middleware] = false
95
+
96
+ # unicorn_rails creates dirs here after working_directory is bound
97
+ after_reload.call if after_reload
98
+
99
+ # working_directory binds immediately (easier error checking that way),
100
+ # now ensure any paths we changed are correctly set.
101
+ [ :pid, :stderr_path, :stdout_path ].each do |var|
102
+ String === (path = set[var]) or next
103
+ path = File.expand_path(path)
104
+ File.writable?(path) || File.writable?(File.dirname(path)) or \
105
+ raise ArgumentError, "directory for #{var}=#{path} not writable"
106
+ end
107
+ end
108
+
109
+ def commit!(server, options = {}) #:nodoc:
110
+ skip = options[:skip] || []
111
+ if ready_pipe = RACKUP.delete(:ready_pipe)
112
+ server.ready_pipe = ready_pipe
113
+ end
114
+ if set[:check_client_connection]
115
+ set[:listeners].each do |address|
116
+ if set[:listener_opts][address][:tcp_nopush] == true
117
+ raise ArgumentError,
118
+ "check_client_connection is incompatible with tcp_nopush:true"
119
+ end
120
+ end
121
+ end
122
+ set.each do |key, value|
123
+ value == :unset and next
124
+ skip.include?(key) and next
125
+ server.__send__("#{key}=", value)
126
+ end
127
+ end
128
+
129
+ def [](key) # :nodoc:
130
+ set[key]
131
+ end
132
+
133
+ # sets object to the +obj+ Logger-like object. The new Logger-like
134
+ # object must respond to the following methods:
135
+ # * debug
136
+ # * info
137
+ # * warn
138
+ # * error
139
+ # * fatal
140
+ # The default Logger will log its output to the path specified
141
+ # by +stderr_path+. If you're running Unicorn daemonized, then
142
+ # you must specify a path to prevent error messages from going
143
+ # to /dev/null.
144
+ def logger(obj)
145
+ %w(debug info warn error fatal).each do |m|
146
+ obj.respond_to?(m) and next
147
+ raise ArgumentError, "logger=#{obj} does not respond to method=#{m}"
148
+ end
149
+
150
+ set[:logger] = obj
151
+ end
152
+
153
+ # sets after_fork hook to a given block. This block will be called by
154
+ # the worker after forking. The following is an example hook which adds
155
+ # a per-process listener to every worker:
156
+ #
157
+ # after_fork do |server,worker|
158
+ # # per-process listener ports for debugging/admin:
159
+ # addr = "127.0.0.1:#{9293 + worker.nr}"
160
+ #
161
+ # # the negative :tries parameter indicates we will retry forever
162
+ # # waiting on the existing process to exit with a 5 second :delay
163
+ # # Existing options for Unicorn::Configurator#listen such as
164
+ # # :backlog, :rcvbuf, :sndbuf are available here as well.
165
+ # server.listen(addr, :tries => -1, :delay => 5, :backlog => 128)
166
+ # end
167
+ def after_fork(*args, &block)
168
+ set_hook(:after_fork, block_given? ? block : args[0])
169
+ end
170
+
171
+ # sets after_worker_exit hook to a given block. This block will be called
172
+ # by the master process after a worker exits:
173
+ #
174
+ # after_worker_exit do |server,worker,status|
175
+ # # status is a Process::Status instance for the exited worker process
176
+ # unless status.success?
177
+ # server.logger.error("worker process failure: #{status.inspect}")
178
+ # end
179
+ # end
180
+ #
181
+ # after_worker_exit is only available in unicorn 5.3.0+
182
+ def after_worker_exit(*args, &block)
183
+ set_hook(:after_worker_exit, block_given? ? block : args[0], 3)
184
+ end
185
+
186
+ # sets after_worker_ready hook to a given block. This block will be called
187
+ # by a worker process after it has been fully loaded, directly before it
188
+ # starts responding to requests:
189
+ #
190
+ # after_worker_ready do |server,worker|
191
+ # server.logger.info("worker #{worker.nr} ready, dropping privileges")
192
+ # worker.user('username', 'groupname')
193
+ # end
194
+ #
195
+ # Do not use Configurator#user if you rely on changing users in the
196
+ # after_worker_ready hook.
197
+ #
198
+ # after_worker_ready is only available in unicorn 5.3.0+
199
+ def after_worker_ready(*args, &block)
200
+ set_hook(:after_worker_ready, block_given? ? block : args[0])
201
+ end
202
+
203
+ # sets before_fork got be a given Proc object. This Proc
204
+ # object will be called by the master process before forking
205
+ # each worker.
206
+ def before_fork(*args, &block)
207
+ set_hook(:before_fork, block_given? ? block : args[0])
208
+ end
209
+
210
+ # sets the before_exec hook to a given Proc object. This
211
+ # Proc object will be called by the master process right
212
+ # before exec()-ing the new unicorn binary. This is useful
213
+ # for freeing certain OS resources that you do NOT wish to
214
+ # share with the reexeced child process.
215
+ # There is no corresponding after_exec hook (for obvious reasons).
216
+ def before_exec(*args, &block)
217
+ set_hook(:before_exec, block_given? ? block : args[0], 1)
218
+ end
219
+
220
+ # Strongly consider using link:/Application_Timeouts.html instead
221
+ # of this misfeature. This misfeature has done decades of damage
222
+ # to Ruby since it demotivates the use of fine-grained timeout
223
+ # mechanisms.
224
+ #
225
+ # Sets the timeout of worker processes to +seconds+. Workers
226
+ # handling the request/app.call/response cycle taking longer than
227
+ # this time period will be forcibly killed (via SIGKILL). This
228
+ # timeout is enforced by the master process itself and not subject
229
+ # to the scheduling limitations by the worker process. Due the
230
+ # low-complexity, low-overhead implementation, timeouts of less
231
+ # than 3.0 seconds can be considered inaccurate and unsafe.
232
+ #
233
+ # For running Unicorn behind nginx, it is recommended to set
234
+ # "fail_timeout=0" for in your nginx configuration like this
235
+ # to have nginx always retry backends that may have had workers
236
+ # SIGKILL-ed due to timeouts.
237
+ #
238
+ # upstream unicorn_backend {
239
+ # # for UNIX domain socket setups:
240
+ # server unix:/path/to/.unicorn.sock fail_timeout=0;
241
+ #
242
+ # # for TCP setups
243
+ # server 192.168.0.7:8080 fail_timeout=0;
244
+ # server 192.168.0.8:8080 fail_timeout=0;
245
+ # server 192.168.0.9:8080 fail_timeout=0;
246
+ # }
247
+ #
248
+ # See https://nginx.org/en/docs/http/ngx_http_upstream_module.html
249
+ # for more details on nginx upstream configuration.
250
+ def timeout(seconds)
251
+ set_int(:timeout, seconds, 3)
252
+ # POSIX says 31 days is the smallest allowed maximum timeout for select()
253
+ max = 30 * 60 * 60 * 24
254
+ set[:timeout] = seconds > max ? max : seconds
255
+ end
256
+
257
+ # Whether to exec in each worker process after forking. This changes the
258
+ # memory layout of each worker process, which is a security feature designed
259
+ # to defeat possible address space discovery attacks. Note that using
260
+ # worker_exec only makes sense if you are not preloading the application,
261
+ # and will result in higher memory usage.
262
+ #
263
+ # worker_exec is only available in unicorn 5.3.0+
264
+ def worker_exec(bool)
265
+ set_bool(:worker_exec, bool)
266
+ end
267
+
268
+ # sets the current number of worker_processes to +nr+. Each worker
269
+ # process will serve exactly one client at a time. You can
270
+ # increment or decrement this value at runtime by sending SIGTTIN
271
+ # or SIGTTOU respectively to the master process without reloading
272
+ # the rest of your Unicorn configuration. See the SIGNALS document
273
+ # for more information.
274
+ def worker_processes(nr)
275
+ set_int(:worker_processes, nr, 1)
276
+ end
277
+
278
+ # sets whether to add default middleware in the development and
279
+ # deployment RACK_ENVs.
280
+ #
281
+ # default_middleware is only available in unicorn 5.5.0+
282
+ def default_middleware(bool)
283
+ set_bool(:default_middleware, bool)
284
+ end
285
+
286
+ # sets whether to enable the proposed early hints Rack API.
287
+ # If enabled, Rails 5.2+ will automatically send a 103 Early Hint
288
+ # for all the `javascript_include_tag` and `stylesheet_link_tag`
289
+ # in your response. See: https://api.rubyonrails.org/v5.2/classes/ActionDispatch/Request.html#method-i-send_early_hints
290
+ # See also https://tools.ietf.org/html/rfc8297
291
+ def early_hints(bool)
292
+ set_bool(:early_hints, bool)
293
+ end
294
+
295
+ # sets listeners to the given +addresses+, replacing or augmenting the
296
+ # current set. This is for the global listener pool shared by all
297
+ # worker processes. For per-worker listeners, see the after_fork example
298
+ # This is for internal API use only, do not use it in your Unicorn
299
+ # config file. Use listen instead.
300
+ def listeners(addresses) # :nodoc:
301
+ Array === addresses or addresses = Array(addresses)
302
+ addresses.map! { |addr| expand_addr(addr) }
303
+ set[:listeners] = addresses
304
+ end
305
+
306
+ # Adds an +address+ to the existing listener set. May be specified more
307
+ # than once. +address+ may be an Integer port number for a TCP port, an
308
+ # "IP_ADDRESS:PORT" for TCP listeners or a pathname for UNIX domain sockets.
309
+ #
310
+ # listen 3000 # listen to port 3000 on all TCP interfaces
311
+ # listen "127.0.0.1:3000" # listen to port 3000 on the loopback interface
312
+ # listen "/path/to/.unicorn.sock" # listen on the given Unix domain socket
313
+ # listen "[::1]:3000" # listen to port 3000 on the IPv6 loopback interface
314
+ #
315
+ # When using Unix domain sockets, be sure:
316
+ # 1) the path matches the one used by nginx
317
+ # 2) uses the same filesystem namespace as the nginx process
318
+ # For systemd users using PrivateTmp=true (for either nginx or unicorn),
319
+ # this means Unix domain sockets must not be placed in /tmp
320
+ #
321
+ # The following options may be specified (but are generally not needed):
322
+ #
323
+ # [:backlog => number of clients]
324
+ #
325
+ # This is the backlog of the listen() syscall.
326
+ #
327
+ # Some operating systems allow negative values here to specify the
328
+ # maximum allowable value. In most cases, this number is only
329
+ # recommendation and there are other OS-specific tunables and
330
+ # variables that can affect this number. See the listen(2)
331
+ # syscall documentation of your OS for the exact semantics of
332
+ # this.
333
+ #
334
+ # If you are running unicorn on multiple machines, lowering this number
335
+ # can help your load balancer detect when a machine is overloaded
336
+ # and give requests to a different machine.
337
+ #
338
+ # Default: 1024
339
+ #
340
+ # Note: with the Linux kernel, the net.core.somaxconn sysctl defaults
341
+ # to 128, capping this value to 128. Raising the sysctl allows a
342
+ # larger backlog (which may not be desirable with multiple,
343
+ # load-balanced machines).
344
+ #
345
+ # [:rcvbuf => bytes, :sndbuf => bytes]
346
+ #
347
+ # Maximum receive and send buffer sizes (in bytes) of sockets.
348
+ #
349
+ # These correspond to the SO_RCVBUF and SO_SNDBUF settings which
350
+ # can be set via the setsockopt(2) syscall. Some kernels
351
+ # (e.g. Linux 2.4+) have intelligent auto-tuning mechanisms and
352
+ # there is no need (and it is sometimes detrimental) to specify them.
353
+ #
354
+ # See the socket API documentation of your operating system
355
+ # to determine the exact semantics of these settings and
356
+ # other operating system-specific knobs where they can be
357
+ # specified.
358
+ #
359
+ # Defaults: operating system defaults
360
+ #
361
+ # [:tcp_nodelay => true or false]
362
+ #
363
+ # Disables Nagle's algorithm on TCP sockets if +true+.
364
+ #
365
+ # Setting this to +true+ can make streaming responses in Rails 3.1
366
+ # appear more quickly at the cost of slightly higher bandwidth usage.
367
+ # The effect of this option is most visible if nginx is not used,
368
+ # but nginx remains highly recommended with unicorn.
369
+ #
370
+ # This has no effect on UNIX sockets.
371
+ #
372
+ # Default: +true+ (Nagle's algorithm disabled) in unicorn
373
+ # This defaulted to +false+ in unicorn 3.x
374
+ #
375
+ # [:tcp_nopush => true or false]
376
+ #
377
+ # Enables/disables TCP_CORK in Linux or TCP_NOPUSH in FreeBSD
378
+ #
379
+ # This prevents partial TCP frames from being sent out and reduces
380
+ # wakeups in nginx if it is on a different machine. Since unicorn
381
+ # is only designed for applications that send the response body
382
+ # quickly without keepalive, sockets will always be flushed on close
383
+ # to prevent delays.
384
+ #
385
+ # This has no effect on UNIX sockets.
386
+ #
387
+ # Default: +false+
388
+ # This defaulted to +true+ in unicorn 3.4 - 3.7
389
+ #
390
+ # [:ipv6only => true or false]
391
+ #
392
+ # This option makes IPv6-capable TCP listeners IPv6-only and unable
393
+ # to receive IPv4 queries on dual-stack systems. A separate IPv4-only
394
+ # listener is required if this is true.
395
+ #
396
+ # Enabling this option for the IPv6-only listener and having a
397
+ # separate IPv4 listener is recommended if you wish to support IPv6
398
+ # on the same TCP port. Otherwise, the value of \env[\"REMOTE_ADDR\"]
399
+ # will appear as an ugly IPv4-mapped-IPv6 address for IPv4 clients
400
+ # (e.g ":ffff:10.0.0.1" instead of just "10.0.0.1").
401
+ #
402
+ # Default: Operating-system dependent
403
+ #
404
+ # [:reuseport => true or false]
405
+ #
406
+ # This enables multiple, independently-started unicorn instances to
407
+ # bind to the same port (as long as all the processes enable this).
408
+ #
409
+ # This option must be used when unicorn first binds the listen socket.
410
+ # It cannot be enabled when a socket is inherited via SIGUSR2
411
+ # (but it will remain on if inherited), and it cannot be enabled
412
+ # directly via SIGHUP.
413
+ #
414
+ # Note: there is a chance of connections being dropped if
415
+ # one of the unicorn instances is stopped while using this.
416
+ #
417
+ # This is supported on *BSD systems and Linux 3.9 or later.
418
+ #
419
+ # ref: https://lwn.net/Articles/542629/
420
+ #
421
+ # Default: false (unset)
422
+ #
423
+ # [:tries => Integer]
424
+ #
425
+ # Times to retry binding a socket if it is already in use
426
+ #
427
+ # A negative number indicates we will retry indefinitely, this is
428
+ # useful for migrations and upgrades when individual workers
429
+ # are binding to different ports.
430
+ #
431
+ # Default: 5
432
+ #
433
+ # [:delay => seconds]
434
+ #
435
+ # Seconds to wait between successive +tries+
436
+ #
437
+ # Default: 0.5 seconds
438
+ #
439
+ # [:umask => mode]
440
+ #
441
+ # Sets the file mode creation mask for UNIX sockets. If specified,
442
+ # this is usually in octal notation.
443
+ #
444
+ # Typically UNIX domain sockets are created with more liberal
445
+ # file permissions than the rest of the application. By default,
446
+ # we create UNIX domain sockets to be readable and writable by
447
+ # all local users to give them the same accessibility as
448
+ # locally-bound TCP listeners.
449
+ #
450
+ # This has no effect on TCP listeners.
451
+ #
452
+ # Default: 0000 (world-read/writable)
453
+ #
454
+ # [:tcp_defer_accept => Integer]
455
+ #
456
+ # Defer accept() until data is ready (Linux-only)
457
+ #
458
+ # For Linux 2.6.32 and later, this is the number of retransmits to
459
+ # defer an accept() for if no data arrives, but the client will
460
+ # eventually be accepted after the specified number of retransmits
461
+ # regardless of whether data is ready.
462
+ #
463
+ # For Linux before 2.6.32, this is a boolean option, and
464
+ # accepts are _always_ deferred indefinitely if no data arrives.
465
+ # This is similar to <code>:accept_filter => "dataready"</code>
466
+ # under FreeBSD.
467
+ #
468
+ # Specifying +true+ is synonymous for the default value(s) below,
469
+ # and +false+ or +nil+ is synonymous for a value of zero.
470
+ #
471
+ # A value of +1+ is a good optimization for local networks
472
+ # and trusted clients. There is no good reason to ever
473
+ # disable this with a +zero+ value with unicorn.
474
+ #
475
+ # Default: 1
476
+ #
477
+ # [:accept_filter => String]
478
+ #
479
+ # defer accept() until data is ready (FreeBSD-only)
480
+ #
481
+ # This enables either the "dataready" or (default) "httpready"
482
+ # accept() filter under FreeBSD. This is intended as an
483
+ # optimization to reduce context switches with common GET/HEAD
484
+ # requests.
485
+ #
486
+ # There is no good reason to change from the default.
487
+ #
488
+ # Default: "httpready"
489
+ def listen(address, options = {})
490
+ address = expand_addr(address)
491
+ if String === address
492
+ [ :umask, :backlog, :sndbuf, :rcvbuf, :tries ].each do |key|
493
+ value = options[key] or next
494
+ Integer === value or
495
+ raise ArgumentError, "not an integer: #{key}=#{value.inspect}"
496
+ end
497
+ [ :tcp_nodelay, :tcp_nopush, :ipv6only, :reuseport ].each do |key|
498
+ (value = options[key]).nil? and next
499
+ TrueClass === value || FalseClass === value or
500
+ raise ArgumentError, "not boolean: #{key}=#{value.inspect}"
501
+ end
502
+ unless (value = options[:delay]).nil?
503
+ Numeric === value or
504
+ raise ArgumentError, "not numeric: delay=#{value.inspect}"
505
+ end
506
+ set[:listener_opts][address].merge!(options)
507
+ end
508
+
509
+ set[:listeners] << address
510
+ end
511
+
512
+ # sets the +path+ for the PID file of the unicorn master process
513
+ def pid(path); set_path(:pid, path); end
514
+
515
+ # Enabling this preloads an application before forking worker
516
+ # processes. This allows memory savings when using a
517
+ # copy-on-write-friendly GC but can cause bad things to happen when
518
+ # resources like sockets are opened at load time by the master
519
+ # process and shared by multiple children. People enabling this are
520
+ # highly encouraged to look at the before_fork/after_fork hooks to
521
+ # properly close/reopen sockets. Files opened for logging do not
522
+ # have to be reopened as (unbuffered-in-userspace) files opened with
523
+ # the File::APPEND flag are written to atomically on UNIX.
524
+ #
525
+ # In addition to reloading the unicorn-specific config settings,
526
+ # SIGHUP will reload application code in the working
527
+ # directory/symlink when workers are gracefully restarted when
528
+ # preload_app=false (the default). As reloading the application
529
+ # sometimes requires RubyGems updates, +Gem.refresh+ is always
530
+ # called before the application is loaded (for RubyGems users).
531
+ #
532
+ # During deployments, care should _always_ be taken to ensure your
533
+ # applications are properly deployed and running. Using
534
+ # preload_app=false (the default) means you _must_ check if
535
+ # your application is responding properly after a deployment.
536
+ # Improperly deployed applications can go into a spawn loop
537
+ # if the application fails to load. While your children are
538
+ # in a spawn loop, it is is possible to fix an application
539
+ # by properly deploying all required code and dependencies.
540
+ # Using preload_app=true means any application load error will
541
+ # cause the master process to exit with an error.
542
+
543
+ def preload_app(bool)
544
+ set_bool(:preload_app, bool)
545
+ end
546
+
547
+ # Toggles making \env[\"rack.input\"] rewindable.
548
+ # Disabling rewindability can improve performance by lowering
549
+ # I/O and memory usage for applications that accept uploads.
550
+ # Keep in mind that the Rack 1.x spec requires
551
+ # \env[\"rack.input\"] to be rewindable,
552
+ # but the Rack 2.x spec does not.
553
+ #
554
+ # +rewindable_input+ defaults to +true+ for compatibility.
555
+ # Setting it to +false+ may be safe for applications and
556
+ # frameworks developed for Rack 2.x and later.
557
+ def rewindable_input(bool)
558
+ set_bool(:rewindable_input, bool)
559
+ end
560
+
561
+ # The maximum size (in +bytes+) to buffer in memory before
562
+ # resorting to a temporary file. Default is 112 kilobytes.
563
+ # This option has no effect if "rewindable_input" is set to
564
+ # +false+.
565
+ def client_body_buffer_size(bytes)
566
+ set_int(:client_body_buffer_size, bytes, 0)
567
+ end
568
+
569
+ # When enabled, unicorn will check the client connection by writing
570
+ # the beginning of the HTTP headers before calling the application.
571
+ #
572
+ # This will prevent calling the application for clients who have
573
+ # disconnected while their connection was queued.
574
+ #
575
+ # This only affects clients connecting over Unix domain sockets
576
+ # and TCP via loopback (127.*.*.*). It is unlikely to detect
577
+ # disconnects if the client is on a remote host (even on a fast LAN).
578
+ #
579
+ # This option cannot be used in conjunction with :tcp_nopush.
580
+ def check_client_connection(bool)
581
+ set_bool(:check_client_connection, bool)
582
+ end
583
+
584
+ # Allow redirecting $stderr to a given path. Unlike doing this from
585
+ # the shell, this allows the unicorn process to know the path its
586
+ # writing to and rotate the file if it is used for logging. The
587
+ # file will be opened with the File::APPEND flag and writes
588
+ # synchronized to the kernel (but not necessarily to _disk_) so
589
+ # multiple processes can safely append to it.
590
+ #
591
+ # If you are daemonizing and using the default +logger+, it is important
592
+ # to specify this as errors will otherwise be lost to /dev/null.
593
+ # Some applications/libraries may also triggering warnings that go to
594
+ # stderr, and they will end up here.
595
+ def stderr_path(path)
596
+ set_path(:stderr_path, path)
597
+ end
598
+
599
+ # Same as stderr_path, except for $stdout. Not many Rack applications
600
+ # write to $stdout, but any that do will have their output written here.
601
+ # It is safe to point this to the same location a stderr_path.
602
+ # Like stderr_path, this defaults to /dev/null when daemonized.
603
+ def stdout_path(path)
604
+ set_path(:stdout_path, path)
605
+ end
606
+
607
+ # sets the working directory for Unicorn. This ensures SIGUSR2 will
608
+ # start a new instance of Unicorn in this directory. This may be
609
+ # a symlink, a common scenario for Capistrano users. Unlike
610
+ # all other Unicorn configuration directives, this binds immediately
611
+ # for error checking and cannot be undone by unsetting it in the
612
+ # configuration file and reloading.
613
+ def working_directory(path)
614
+ # just let chdir raise errors
615
+ path = File.expand_path(path)
616
+ if config_file &&
617
+ ! config_file.start_with?('/') &&
618
+ ! File.readable?("#{path}/#{config_file}")
619
+ raise ArgumentError,
620
+ "config_file=#{config_file} would not be accessible in" \
621
+ " working_directory=#{path}"
622
+ end
623
+ Dir.chdir(path)
624
+ Unicorn::HttpServer::START_CTX[:cwd] = ENV["PWD"] = path
625
+ end
626
+
627
+ # Runs worker processes as the specified +user+ and +group+.
628
+ # The master process always stays running as the user who started it.
629
+ # This switch will occur after calling the after_fork hook, and only
630
+ # if the Worker#user method is not called in the after_fork hook
631
+ # +group+ is optional and will not change if unspecified.
632
+ #
633
+ # Do not use Configurator#user if you rely on changing users in the
634
+ # after_worker_ready hook. Instead, you need to call Worker#user
635
+ # directly in after_worker_ready.
636
+ def user(user, group = nil)
637
+ # raises ArgumentError on invalid user/group
638
+ Etc.getpwnam(user)
639
+ Etc.getgrnam(group) if group
640
+ set[:user] = [ user, group ]
641
+ end
642
+
643
+ # expands "unix:path/to/foo" to a socket relative to the current path
644
+ # expands pathnames of sockets if relative to "~" or "~username"
645
+ # expands "*:port and ":port" to "0.0.0.0:port"
646
+ def expand_addr(address) #:nodoc:
647
+ return "0.0.0.0:#{address}" if Integer === address
648
+ return address unless String === address
649
+
650
+ case address
651
+ when %r{\Aunix:(.*)\z}
652
+ File.expand_path($1)
653
+ when %r{\A~}
654
+ File.expand_path(address)
655
+ when %r{\A(?:\*:)?(\d+)\z}
656
+ "0.0.0.0:#$1"
657
+ when %r{\A\[([a-fA-F0-9:]+)\]\z}, %r/\A((?:\d+\.){3}\d+)\z/
658
+ canonicalize_tcp($1, 80)
659
+ when %r{\A\[([a-fA-F0-9:]+)\]:(\d+)\z}, %r{\A(.*):(\d+)\z}
660
+ canonicalize_tcp($1, $2.to_i)
661
+ else
662
+ address
663
+ end
664
+ end
665
+
666
+ private
667
+ def set_int(var, n, min) #:nodoc:
668
+ Integer === n or raise ArgumentError, "not an integer: #{var}=#{n.inspect}"
669
+ n >= min or raise ArgumentError, "too low (< #{min}): #{var}=#{n.inspect}"
670
+ set[var] = n
671
+ end
672
+
673
+ def canonicalize_tcp(addr, port)
674
+ packed = Socket.pack_sockaddr_in(port, addr)
675
+ port, addr = Socket.unpack_sockaddr_in(packed)
676
+ addr.include?(':') ? "[#{addr}]:#{port}" : "#{addr}:#{port}"
677
+ end
678
+
679
+ def set_path(var, path) #:nodoc:
680
+ case path
681
+ when NilClass, String
682
+ set[var] = path
683
+ else
684
+ raise ArgumentError
685
+ end
686
+ end
687
+
688
+ def check_bool(var, bool) # :nodoc:
689
+ case bool
690
+ when true, false
691
+ return bool
692
+ end
693
+ raise ArgumentError, "#{var}=#{bool.inspect} not a boolean"
694
+ end
695
+
696
+ def set_bool(var, bool) #:nodoc:
697
+ set[var] = check_bool(var, bool)
698
+ end
699
+
700
+ def set_hook(var, my_proc, req_arity = 2) #:nodoc:
701
+ case my_proc
702
+ when Proc
703
+ arity = my_proc.arity
704
+ (arity == req_arity) or \
705
+ raise ArgumentError,
706
+ "#{var}=#{my_proc.inspect} has invalid arity: " \
707
+ "#{arity} (need #{req_arity})"
708
+ when NilClass
709
+ my_proc = DEFAULTS[var]
710
+ else
711
+ raise ArgumentError, "invalid type: #{var}=#{my_proc.inspect}"
712
+ end
713
+ set[var] = my_proc
714
+ end
715
+
716
+ # this is called _after_ working_directory is bound. This only
717
+ # parses the embedded switches in .ru files
718
+ # (for "rackup" compatibility)
719
+ def parse_rackup_file # :nodoc:
720
+ ru = RACKUP[:file] or return # we only return here in unit tests
721
+
722
+ # :rails means use (old) Rails autodetect
723
+ if ru == :rails
724
+ File.readable?('config.ru') or return
725
+ ru = 'config.ru'
726
+ end
727
+
728
+ File.readable?(ru) or
729
+ raise ArgumentError, "rackup file (#{ru}) not readable"
730
+
731
+ # it could be a .rb file, too, we don't parse those manually
732
+ ru.end_with?('.ru') or return
733
+
734
+ /^#\\(.*)/ =~ File.read(ru) or return
735
+ RACKUP[:optparse].parse!($1.split(/\s+/))
736
+
737
+ if RACKUP[:daemonize]
738
+ # unicorn_rails wants a default pid path, (not plain 'unicorn')
739
+ if after_reload
740
+ spid = set[:pid]
741
+ pid('tmp/pids/unicorn.pid') if spid.nil? || spid == :unset
742
+ end
743
+ unless RACKUP[:daemonized]
744
+ Unicorn::Launcher.daemonize!(RACKUP[:options])
745
+ RACKUP[:ready_pipe] = RACKUP[:options].delete(:ready_pipe)
746
+ end
747
+ end
748
+ end
749
+ end