boourns-unicorn 4.4.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 (155) hide show
  1. data/.CHANGELOG.old +25 -0
  2. data/.document +29 -0
  3. data/.gitignore +24 -0
  4. data/.mailmap +26 -0
  5. data/.wrongdoc.yml +10 -0
  6. data/Application_Timeouts +77 -0
  7. data/CONTRIBUTORS +35 -0
  8. data/COPYING +674 -0
  9. data/DESIGN +97 -0
  10. data/Documentation/.gitignore +5 -0
  11. data/Documentation/GNUmakefile +30 -0
  12. data/Documentation/unicorn.1.txt +174 -0
  13. data/Documentation/unicorn_rails.1.txt +175 -0
  14. data/FAQ +53 -0
  15. data/GIT-VERSION-GEN +40 -0
  16. data/GNUmakefile +267 -0
  17. data/HACKING +134 -0
  18. data/ISSUES +36 -0
  19. data/KNOWN_ISSUES +79 -0
  20. data/LICENSE +64 -0
  21. data/Links +56 -0
  22. data/PHILOSOPHY +145 -0
  23. data/README +149 -0
  24. data/Rakefile +97 -0
  25. data/SIGNALS +114 -0
  26. data/Sandbox +96 -0
  27. data/TODO +5 -0
  28. data/TUNING +98 -0
  29. data/bin/unicorn +121 -0
  30. data/bin/unicorn_rails +209 -0
  31. data/examples/big_app_gc.rb +2 -0
  32. data/examples/echo.ru +27 -0
  33. data/examples/git.ru +13 -0
  34. data/examples/init.sh +74 -0
  35. data/examples/logger_mp_safe.rb +25 -0
  36. data/examples/logrotate.conf +29 -0
  37. data/examples/nginx.conf +156 -0
  38. data/examples/unicorn.conf.minimal.rb +13 -0
  39. data/examples/unicorn.conf.rb +94 -0
  40. data/ext/unicorn_http/CFLAGS +13 -0
  41. data/ext/unicorn_http/c_util.h +124 -0
  42. data/ext/unicorn_http/common_field_optimization.h +111 -0
  43. data/ext/unicorn_http/ext_help.h +86 -0
  44. data/ext/unicorn_http/extconf.rb +10 -0
  45. data/ext/unicorn_http/global_variables.h +97 -0
  46. data/ext/unicorn_http/httpdate.c +82 -0
  47. data/ext/unicorn_http/unicorn_http.rl +1036 -0
  48. data/ext/unicorn_http/unicorn_http_common.rl +76 -0
  49. data/lib/unicorn.rb +107 -0
  50. data/lib/unicorn/app/exec_cgi.rb +154 -0
  51. data/lib/unicorn/app/inetd.rb +109 -0
  52. data/lib/unicorn/app/old_rails.rb +35 -0
  53. data/lib/unicorn/app/old_rails/static.rb +59 -0
  54. data/lib/unicorn/cgi_wrapper.rb +147 -0
  55. data/lib/unicorn/configurator.rb +630 -0
  56. data/lib/unicorn/const.rb +40 -0
  57. data/lib/unicorn/http_request.rb +83 -0
  58. data/lib/unicorn/http_response.rb +45 -0
  59. data/lib/unicorn/http_server.rb +755 -0
  60. data/lib/unicorn/launcher.rb +62 -0
  61. data/lib/unicorn/oob_gc.rb +71 -0
  62. data/lib/unicorn/preread_input.rb +33 -0
  63. data/lib/unicorn/socket_helper.rb +208 -0
  64. data/lib/unicorn/ssl_client.rb +11 -0
  65. data/lib/unicorn/ssl_configurator.rb +104 -0
  66. data/lib/unicorn/ssl_server.rb +42 -0
  67. data/lib/unicorn/stream_input.rb +149 -0
  68. data/lib/unicorn/tee_input.rb +126 -0
  69. data/lib/unicorn/tmpio.rb +29 -0
  70. data/lib/unicorn/util.rb +69 -0
  71. data/lib/unicorn/worker.rb +88 -0
  72. data/local.mk.sample +59 -0
  73. data/script/isolate_for_tests +32 -0
  74. data/setup.rb +1586 -0
  75. data/t/.gitignore +5 -0
  76. data/t/GNUmakefile +82 -0
  77. data/t/README +42 -0
  78. data/t/bin/content-md5-put +36 -0
  79. data/t/bin/sha1sum.rb +17 -0
  80. data/t/bin/unused_listen +40 -0
  81. data/t/bin/utee +12 -0
  82. data/t/broken-app.ru +12 -0
  83. data/t/detach.ru +11 -0
  84. data/t/env.ru +3 -0
  85. data/t/heartbeat-timeout.ru +12 -0
  86. data/t/listener_names.ru +4 -0
  87. data/t/my-tap-lib.sh +201 -0
  88. data/t/oob_gc.ru +21 -0
  89. data/t/oob_gc_path.ru +21 -0
  90. data/t/pid.ru +3 -0
  91. data/t/preread_input.ru +17 -0
  92. data/t/rack-input-tests.ru +21 -0
  93. data/t/sslgen.sh +71 -0
  94. data/t/t0000-http-basic.sh +50 -0
  95. data/t/t0001-reload-bad-config.sh +53 -0
  96. data/t/t0002-config-conflict.sh +49 -0
  97. data/t/t0002-parser-error.sh +94 -0
  98. data/t/t0003-working_directory.sh +51 -0
  99. data/t/t0004-heartbeat-timeout.sh +69 -0
  100. data/t/t0004-working_directory_broken.sh +24 -0
  101. data/t/t0005-working_directory_app.rb.sh +37 -0
  102. data/t/t0006-reopen-logs.sh +83 -0
  103. data/t/t0006.ru +13 -0
  104. data/t/t0007-working_directory_no_embed_cli.sh +44 -0
  105. data/t/t0008-back_out_of_upgrade.sh +110 -0
  106. data/t/t0009-broken-app.sh +56 -0
  107. data/t/t0009-winch_ttin.sh +59 -0
  108. data/t/t0010-reap-logging.sh +55 -0
  109. data/t/t0011-active-unix-socket.sh +79 -0
  110. data/t/t0012-reload-empty-config.sh +85 -0
  111. data/t/t0013-rewindable-input-false.sh +24 -0
  112. data/t/t0013.ru +12 -0
  113. data/t/t0014-rewindable-input-true.sh +24 -0
  114. data/t/t0014.ru +12 -0
  115. data/t/t0015-configurator-internals.sh +25 -0
  116. data/t/t0016-trust-x-forwarded-false.sh +30 -0
  117. data/t/t0017-trust-x-forwarded-true.sh +30 -0
  118. data/t/t0018-write-on-close.sh +23 -0
  119. data/t/t0019-max_header_len.sh +49 -0
  120. data/t/t0020-at_exit-handler.sh +49 -0
  121. data/t/t0021-process_detach.sh +29 -0
  122. data/t/t0022-listener_names-preload_app.sh +32 -0
  123. data/t/t0100-rack-input-tests.sh +124 -0
  124. data/t/t0116-client_body_buffer_size.sh +80 -0
  125. data/t/t0116.ru +16 -0
  126. data/t/t0600-https-server-basic.sh +48 -0
  127. data/t/t9000-preread-input.sh +48 -0
  128. data/t/t9001-oob_gc.sh +47 -0
  129. data/t/t9002-oob_gc-path.sh +75 -0
  130. data/t/test-lib.sh +113 -0
  131. data/t/write-on-close.ru +11 -0
  132. data/test/aggregate.rb +15 -0
  133. data/test/benchmark/README +50 -0
  134. data/test/benchmark/dd.ru +18 -0
  135. data/test/benchmark/stack.ru +8 -0
  136. data/test/exec/README +5 -0
  137. data/test/exec/test_exec.rb +1041 -0
  138. data/test/test_helper.rb +300 -0
  139. data/test/unit/test_configurator.rb +158 -0
  140. data/test/unit/test_droplet.rb +28 -0
  141. data/test/unit/test_http_parser.rb +860 -0
  142. data/test/unit/test_http_parser_ng.rb +716 -0
  143. data/test/unit/test_http_parser_xftrust.rb +38 -0
  144. data/test/unit/test_request.rb +197 -0
  145. data/test/unit/test_response.rb +99 -0
  146. data/test/unit/test_server.rb +289 -0
  147. data/test/unit/test_signals.rb +207 -0
  148. data/test/unit/test_sni_hostnames.rb +47 -0
  149. data/test/unit/test_socket_helper.rb +192 -0
  150. data/test/unit/test_stream_input.rb +204 -0
  151. data/test/unit/test_tee_input.rb +296 -0
  152. data/test/unit/test_upload.rb +306 -0
  153. data/test/unit/test_util.rb +99 -0
  154. data/unicorn.gemspec +44 -0
  155. metadata +333 -0
@@ -0,0 +1,35 @@
1
+ # -*- encoding: binary -*-
2
+
3
+ # :enddoc:
4
+ # This code is based on the original Rails handler in Mongrel
5
+ # Copyright (c) 2005 Zed A. Shaw
6
+ # Copyright (c) 2009 Eric Wong
7
+ # You can redistribute it and/or modify it under the same terms as Ruby 1.8 or
8
+ # the GPLv3
9
+ # Additional work donated by contributors. See CONTRIBUTORS for more info.
10
+ require 'unicorn/cgi_wrapper'
11
+ require 'dispatcher'
12
+
13
+ module Unicorn; module App; end; end
14
+
15
+ # Implements a handler that can run Rails.
16
+ class Unicorn::App::OldRails
17
+
18
+ autoload :Static, "unicorn/app/old_rails/static"
19
+
20
+ def call(env)
21
+ cgi = Unicorn::CGIWrapper.new(env)
22
+ begin
23
+ Dispatcher.dispatch(cgi,
24
+ ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS,
25
+ cgi.body)
26
+ rescue => e
27
+ err = env['rack.errors']
28
+ err.write("#{e} #{e.message}\n")
29
+ e.backtrace.each { |line| err.write("#{line}\n") }
30
+ end
31
+ cgi.out # finalize the response
32
+ cgi.rack_response
33
+ end
34
+
35
+ end
@@ -0,0 +1,59 @@
1
+ # -*- encoding: binary -*-
2
+ # :enddoc:
3
+ # This code is based on the original Rails handler in Mongrel
4
+ # Copyright (c) 2005 Zed A. Shaw
5
+ # Copyright (c) 2009 Eric Wong
6
+ # You can redistribute it and/or modify it under the same terms as Ruby 1.8 or
7
+ # the GPLv3
8
+
9
+ # Static file handler for Rails < 2.3. This handler is only provided
10
+ # as a convenience for developers. Performance-minded deployments should
11
+ # use nginx (or similar) for serving static files.
12
+ #
13
+ # This supports page caching directly and will try to resolve a
14
+ # request in the following order:
15
+ #
16
+ # * If the requested exact PATH_INFO exists as a file then serve it.
17
+ # * If it exists at PATH_INFO+rest_operator+".html" exists
18
+ # then serve that.
19
+ #
20
+ # This means that if you are using page caching it will actually work
21
+ # with Unicorn and you should see a decent speed boost (but not as
22
+ # fast as if you use a static server like nginx).
23
+ class Unicorn::App::OldRails::Static < Struct.new(:app, :root, :file_server)
24
+ FILE_METHODS = { 'GET' => true, 'HEAD' => true }
25
+
26
+ # avoid allocating new strings for hash lookups
27
+ REQUEST_METHOD = 'REQUEST_METHOD'
28
+ REQUEST_URI = 'REQUEST_URI'
29
+ PATH_INFO = 'PATH_INFO'
30
+
31
+ def initialize(app)
32
+ self.app = app
33
+ self.root = "#{::RAILS_ROOT}/public"
34
+ self.file_server = ::Rack::File.new(root)
35
+ end
36
+
37
+ def call(env)
38
+ # short circuit this ASAP if serving non-file methods
39
+ FILE_METHODS.include?(env[REQUEST_METHOD]) or return app.call(env)
40
+
41
+ # first try the path as-is
42
+ path_info = env[PATH_INFO].chomp("/")
43
+ if File.file?("#{root}/#{::Rack::Utils.unescape(path_info)}")
44
+ # File exists as-is so serve it up
45
+ env[PATH_INFO] = path_info
46
+ return file_server.call(env)
47
+ end
48
+
49
+ # then try the cached version:
50
+ path_info << ActionController::Base.page_cache_extension
51
+
52
+ if File.file?("#{root}/#{::Rack::Utils.unescape(path_info)}")
53
+ env[PATH_INFO] = path_info
54
+ return file_server.call(env)
55
+ end
56
+
57
+ app.call(env) # call OldRails
58
+ end
59
+ end if defined?(Unicorn::App::OldRails)
@@ -0,0 +1,147 @@
1
+ # -*- encoding: binary -*-
2
+
3
+ # :enddoc:
4
+ # This code is based on the original CGIWrapper from Mongrel
5
+ # Copyright (c) 2005 Zed A. Shaw
6
+ # Copyright (c) 2009 Eric Wong
7
+ # You can redistribute it and/or modify it under the same terms as Ruby 1.8 or
8
+ # the GPLv3
9
+ #
10
+ # Additional work donated by contributors. See CONTRIBUTORS for more info.
11
+
12
+ require 'cgi'
13
+
14
+ module Unicorn; end
15
+
16
+ # The beginning of a complete wrapper around Unicorn's internal HTTP
17
+ # processing system but maintaining the original Ruby CGI module. Use
18
+ # this only as a crutch to get existing CGI based systems working. It
19
+ # should handle everything, but please notify us if you see special
20
+ # warnings. This work is still very alpha so we need testers to help
21
+ # work out the various corner cases.
22
+ class Unicorn::CGIWrapper < ::CGI
23
+ undef_method :env_table
24
+ attr_reader :env_table
25
+ attr_reader :body
26
+
27
+ # these are stripped out of any keys passed to CGIWrapper.header function
28
+ NPH = 'nph'.freeze # Completely ignored, Unicorn outputs the date regardless
29
+ CONNECTION = 'connection'.freeze # Completely ignored. Why is CGI doing this?
30
+ CHARSET = 'charset'.freeze # this gets appended to Content-Type
31
+ COOKIE = 'cookie'.freeze # maps (Hash,Array,String) to "Set-Cookie" headers
32
+ STATUS = 'status'.freeze # stored as @status
33
+ Status = 'Status'.freeze # code + human-readable text, Rails sets this
34
+
35
+ # some of these are common strings, but this is the only module
36
+ # using them and the reason they're not in Unicorn::Const
37
+ SET_COOKIE = 'Set-Cookie'.freeze
38
+ CONTENT_TYPE = 'Content-Type'.freeze
39
+ CONTENT_LENGTH = 'Content-Length'.freeze # this is NOT Const::CONTENT_LENGTH
40
+ RACK_INPUT = 'rack.input'.freeze
41
+ RACK_ERRORS = 'rack.errors'.freeze
42
+
43
+ # this maps CGI header names to HTTP header names
44
+ HEADER_MAP = {
45
+ 'status' => Status,
46
+ 'type' => CONTENT_TYPE,
47
+ 'server' => 'Server'.freeze,
48
+ 'language' => 'Content-Language'.freeze,
49
+ 'expires' => 'Expires'.freeze,
50
+ 'length' => CONTENT_LENGTH,
51
+ }
52
+
53
+ # Takes an a Rackable environment, plus any additional CGI.new
54
+ # arguments These are used internally to create a wrapper around the
55
+ # real CGI while maintaining Rack/Unicorn's view of the world. This
56
+ # this will NOT deal well with large responses that take up a lot of
57
+ # memory, but neither does the CGI nor the original CGIWrapper from
58
+ # Mongrel...
59
+ def initialize(rack_env, *args)
60
+ @env_table = rack_env
61
+ @status = nil
62
+ @head = {}
63
+ @headv = Hash.new { |hash,key| hash[key] = [] }
64
+ @body = StringIO.new("")
65
+ super(*args)
66
+ end
67
+
68
+ # finalizes the response in a way Rack applications would expect
69
+ def rack_response
70
+ # @head[CONTENT_LENGTH] ||= @body.size
71
+ @headv[SET_COOKIE].concat(@output_cookies) if @output_cookies
72
+ @headv.each_pair do |key,value|
73
+ @head[key] ||= value.join("\n") unless value.empty?
74
+ end
75
+
76
+ # Capitalized "Status:", with human-readable status code (e.g. "200 OK")
77
+ @status ||= @head.delete(Status)
78
+
79
+ [ @status || 500, @head, [ @body.string ] ]
80
+ end
81
+
82
+ # The header is typically called to send back the header. In our case we
83
+ # collect it into a hash for later usage. This can be called multiple
84
+ # times to set different cookies.
85
+ def header(options = "text/html")
86
+ # if they pass in a string then just write the Content-Type
87
+ if String === options
88
+ @head[CONTENT_TYPE] ||= options
89
+ else
90
+ HEADER_MAP.each_pair do |from, to|
91
+ from = options.delete(from) or next
92
+ @head[to] = from.to_s
93
+ end
94
+
95
+ @head[CONTENT_TYPE] ||= "text/html"
96
+ if charset = options.delete(CHARSET)
97
+ @head[CONTENT_TYPE] << "; charset=#{charset}"
98
+ end
99
+
100
+ # lots of ways to set cookies
101
+ if cookie = options.delete(COOKIE)
102
+ set_cookies = @headv[SET_COOKIE]
103
+ case cookie
104
+ when Array
105
+ cookie.each { |c| set_cookies << c.to_s }
106
+ when Hash
107
+ cookie.each_value { |c| set_cookies << c.to_s }
108
+ else
109
+ set_cookies << cookie.to_s
110
+ end
111
+ end
112
+ @status ||= options.delete(STATUS) # all lower-case
113
+
114
+ # drop the keys we don't want anymore
115
+ options.delete(NPH)
116
+ options.delete(CONNECTION)
117
+
118
+ # finally, set the rest of the headers as-is, allowing duplicates
119
+ options.each_pair { |k,v| @headv[k] << v }
120
+ end
121
+
122
+ # doing this fakes out the cgi library to think the headers are empty
123
+ # we then do the real headers in the out function call later
124
+ ""
125
+ end
126
+
127
+ # The dumb thing is people can call header or this or both and in
128
+ # any order. So, we just reuse header and then finalize the
129
+ # HttpResponse the right way. This will have no effect if called
130
+ # the second time if the first "outputted" anything.
131
+ def out(options = "text/html")
132
+ header(options)
133
+ @body.size == 0 or return
134
+ @body << yield if block_given?
135
+ end
136
+
137
+ # Used to wrap the normal stdinput variable used inside CGI.
138
+ def stdinput
139
+ @env_table[RACK_INPUT]
140
+ end
141
+
142
+ # return a pointer to the StringIO body since it's STDOUT-like
143
+ def stdoutput
144
+ @body
145
+ end
146
+
147
+ end
@@ -0,0 +1,630 @@
1
+ # -*- encoding: binary -*-
2
+ require 'logger'
3
+ require 'unicorn/ssl_configurator'
4
+
5
+ # Implements a simple DSL for configuring a \Unicorn server.
6
+ #
7
+ # See http://unicorn.bogomips.org/examples/unicorn.conf.rb and
8
+ # http://unicorn.bogomips.org/examples/unicorn.conf.minimal.rb
9
+ # example configuration files. An example config file for use with
10
+ # nginx is also available at
11
+ # http://unicorn.bogomips.org/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
+ include Unicorn::SSLConfigurator
17
+
18
+ # :stopdoc:
19
+ attr_accessor :set, :config_file, :after_reload
20
+
21
+ # used to stash stuff for deferred processing of cli options in
22
+ # config.ru after "working_directory" is bound. Do not rely on
23
+ # this being around later on...
24
+ RACKUP = {
25
+ :daemonize => false,
26
+ :host => Unicorn::Const::DEFAULT_HOST,
27
+ :port => Unicorn::Const::DEFAULT_PORT,
28
+ :set_listener => false,
29
+ :options => { :listeners => [] }
30
+ }
31
+
32
+ # Default settings for Unicorn
33
+ DEFAULTS = {
34
+ :timeout => 60,
35
+ :logger => Logger.new($stderr),
36
+ :worker_processes => 1,
37
+ :after_fork => lambda { |server, worker|
38
+ server.logger.info("worker=#{worker.nr} spawned pid=#{$$}")
39
+ },
40
+ :before_fork => lambda { |server, worker|
41
+ server.logger.info("worker=#{worker.nr} spawning...")
42
+ },
43
+ :before_exec => lambda { |server|
44
+ server.logger.info("forked child re-executing...")
45
+ },
46
+ :pid => nil,
47
+ :preload_app => false,
48
+ :rewindable_input => true, # for Rack 2.x: (Rack::VERSION[0] <= 1),
49
+ :client_body_buffer_size => Unicorn::Const::MAX_BODY,
50
+ :trust_x_forwarded => true,
51
+ }
52
+ #:startdoc:
53
+
54
+ def initialize(defaults = {}) #:nodoc:
55
+ self.set = Hash.new(:unset)
56
+ @use_defaults = defaults.delete(:use_defaults)
57
+ self.config_file = defaults.delete(:config_file)
58
+
59
+ # after_reload is only used by unicorn_rails, unsupported otherwise
60
+ self.after_reload = defaults.delete(:after_reload)
61
+
62
+ set.merge!(DEFAULTS) if @use_defaults
63
+ defaults.each { |key, value| self.__send__(key, value) }
64
+ Hash === set[:listener_opts] or
65
+ set[:listener_opts] = Hash.new { |hash,key| hash[key] = {} }
66
+ Array === set[:listeners] or set[:listeners] = []
67
+ reload(false)
68
+ end
69
+
70
+ def reload(merge_defaults = true) #:nodoc:
71
+ if merge_defaults && @use_defaults
72
+ set.merge!(DEFAULTS) if @use_defaults
73
+ end
74
+ instance_eval(File.read(config_file), config_file) if config_file
75
+
76
+ parse_rackup_file
77
+
78
+ RACKUP[:set_listener] and
79
+ set[:listeners] << "#{RACKUP[:host]}:#{RACKUP[:port]}"
80
+
81
+ # unicorn_rails creates dirs here after working_directory is bound
82
+ after_reload.call if after_reload
83
+
84
+ # working_directory binds immediately (easier error checking that way),
85
+ # now ensure any paths we changed are correctly set.
86
+ [ :pid, :stderr_path, :stdout_path ].each do |var|
87
+ String === (path = set[var]) or next
88
+ path = File.expand_path(path)
89
+ File.writable?(path) || File.writable?(File.dirname(path)) or \
90
+ raise ArgumentError, "directory for #{var}=#{path} not writable"
91
+ end
92
+ end
93
+
94
+ def commit!(server, options = {}) #:nodoc:
95
+ skip = options[:skip] || []
96
+ if ready_pipe = RACKUP.delete(:ready_pipe)
97
+ server.ready_pipe = ready_pipe
98
+ end
99
+ set.each do |key, value|
100
+ value == :unset and next
101
+ skip.include?(key) and next
102
+ server.__send__("#{key}=", value)
103
+ end
104
+ end
105
+
106
+ def [](key) # :nodoc:
107
+ set[key]
108
+ end
109
+
110
+ # sets object to the +obj+ Logger-like object. The new Logger-like
111
+ # object must respond to the following methods:
112
+ # * debug
113
+ # * info
114
+ # * warn
115
+ # * error
116
+ # * fatal
117
+ # The default Logger will log its output to the path specified
118
+ # by +stderr_path+. If you're running Unicorn daemonized, then
119
+ # you must specify a path to prevent error messages from going
120
+ # to /dev/null.
121
+ def logger(obj)
122
+ %w(debug info warn error fatal).each do |m|
123
+ obj.respond_to?(m) and next
124
+ raise ArgumentError, "logger=#{obj} does not respond to method=#{m}"
125
+ end
126
+
127
+ set[:logger] = obj
128
+ end
129
+
130
+ # sets after_fork hook to a given block. This block will be called by
131
+ # the worker after forking. The following is an example hook which adds
132
+ # a per-process listener to every worker:
133
+ #
134
+ # after_fork do |server,worker|
135
+ # # per-process listener ports for debugging/admin:
136
+ # addr = "127.0.0.1:#{9293 + worker.nr}"
137
+ #
138
+ # # the negative :tries parameter indicates we will retry forever
139
+ # # waiting on the existing process to exit with a 5 second :delay
140
+ # # Existing options for Unicorn::Configurator#listen such as
141
+ # # :backlog, :rcvbuf, :sndbuf are available here as well.
142
+ # server.listen(addr, :tries => -1, :delay => 5, :backlog => 128)
143
+ # end
144
+ def after_fork(*args, &block)
145
+ set_hook(:after_fork, block_given? ? block : args[0])
146
+ end
147
+
148
+ # sets before_fork got be a given Proc object. This Proc
149
+ # object will be called by the master process before forking
150
+ # each worker.
151
+ def before_fork(*args, &block)
152
+ set_hook(:before_fork, block_given? ? block : args[0])
153
+ end
154
+
155
+ # sets the before_exec hook to a given Proc object. This
156
+ # Proc object will be called by the master process right
157
+ # before exec()-ing the new unicorn binary. This is useful
158
+ # for freeing certain OS resources that you do NOT wish to
159
+ # share with the reexeced child process.
160
+ # There is no corresponding after_exec hook (for obvious reasons).
161
+ def before_exec(*args, &block)
162
+ set_hook(:before_exec, block_given? ? block : args[0], 1)
163
+ end
164
+
165
+ # sets the timeout of worker processes to +seconds+. Workers
166
+ # handling the request/app.call/response cycle taking longer than
167
+ # this time period will be forcibly killed (via SIGKILL). This
168
+ # timeout is enforced by the master process itself and not subject
169
+ # to the scheduling limitations by the worker process. Due the
170
+ # low-complexity, low-overhead implementation, timeouts of less
171
+ # than 3.0 seconds can be considered inaccurate and unsafe.
172
+ #
173
+ # For running Unicorn behind nginx, it is recommended to set
174
+ # "fail_timeout=0" for in your nginx configuration like this
175
+ # to have nginx always retry backends that may have had workers
176
+ # SIGKILL-ed due to timeouts.
177
+ #
178
+ # # See http://wiki.nginx.org/NginxHttpUpstreamModule for more details
179
+ # # on nginx upstream configuration:
180
+ # upstream unicorn_backend {
181
+ # # for UNIX domain socket setups:
182
+ # server unix:/path/to/unicorn.sock fail_timeout=0;
183
+ #
184
+ # # for TCP setups
185
+ # server 192.168.0.7:8080 fail_timeout=0;
186
+ # server 192.168.0.8:8080 fail_timeout=0;
187
+ # server 192.168.0.9:8080 fail_timeout=0;
188
+ # }
189
+ def timeout(seconds)
190
+ set_int(:timeout, seconds, 3)
191
+ # POSIX says 31 days is the smallest allowed maximum timeout for select()
192
+ max = 30 * 60 * 60 * 24
193
+ set[:timeout] = seconds > max ? max : seconds
194
+ end
195
+
196
+ # sets the current number of worker_processes to +nr+. Each worker
197
+ # process will serve exactly one client at a time. You can
198
+ # increment or decrement this value at runtime by sending SIGTTIN
199
+ # or SIGTTOU respectively to the master process without reloading
200
+ # the rest of your Unicorn configuration. See the SIGNALS document
201
+ # for more information.
202
+ def worker_processes(nr)
203
+ set_int(:worker_processes, nr, 1)
204
+ end
205
+
206
+ # sets listeners to the given +addresses+, replacing or augmenting the
207
+ # current set. This is for the global listener pool shared by all
208
+ # worker processes. For per-worker listeners, see the after_fork example
209
+ # This is for internal API use only, do not use it in your Unicorn
210
+ # config file. Use listen instead.
211
+ def listeners(addresses) # :nodoc:
212
+ Array === addresses or addresses = Array(addresses)
213
+ addresses.map! { |addr| expand_addr(addr) }
214
+ set[:listeners] = addresses
215
+ end
216
+
217
+ # Adds an +address+ to the existing listener set. May be specified more
218
+ # than once. +address+ may be an Integer port number for a TCP port, an
219
+ # "IP_ADDRESS:PORT" for TCP listeners or a pathname for UNIX domain sockets.
220
+ #
221
+ # listen 3000 # listen to port 3000 on all TCP interfaces
222
+ # listen "127.0.0.1:3000" # listen to port 3000 on the loopback interface
223
+ # listen "/tmp/.unicorn.sock" # listen on the given Unix domain socket
224
+ # listen "[::1]:3000" # listen to port 3000 on the IPv6 loopback interface
225
+ #
226
+ # The following options may be specified (but are generally not needed):
227
+ #
228
+ # [:backlog => number of clients]
229
+ #
230
+ # This is the backlog of the listen() syscall.
231
+ #
232
+ # Some operating systems allow negative values here to specify the
233
+ # maximum allowable value. In most cases, this number is only
234
+ # recommendation and there are other OS-specific tunables and
235
+ # variables that can affect this number. See the listen(2)
236
+ # syscall documentation of your OS for the exact semantics of
237
+ # this.
238
+ #
239
+ # If you are running unicorn on multiple machines, lowering this number
240
+ # can help your load balancer detect when a machine is overloaded
241
+ # and give requests to a different machine.
242
+ #
243
+ # Default: 1024
244
+ #
245
+ # [:rcvbuf => bytes, :sndbuf => bytes]
246
+ #
247
+ # Maximum receive and send buffer sizes (in bytes) of sockets.
248
+ #
249
+ # These correspond to the SO_RCVBUF and SO_SNDBUF settings which
250
+ # can be set via the setsockopt(2) syscall. Some kernels
251
+ # (e.g. Linux 2.4+) have intelligent auto-tuning mechanisms and
252
+ # there is no need (and it is sometimes detrimental) to specify them.
253
+ #
254
+ # See the socket API documentation of your operating system
255
+ # to determine the exact semantics of these settings and
256
+ # other operating system-specific knobs where they can be
257
+ # specified.
258
+ #
259
+ # Defaults: operating system defaults
260
+ #
261
+ # [:tcp_nodelay => true or false]
262
+ #
263
+ # Disables Nagle's algorithm on TCP sockets if +true+.
264
+ #
265
+ # Setting this to +true+ can make streaming responses in Rails 3.1
266
+ # appear more quickly at the cost of slightly higher bandwidth usage.
267
+ # The effect of this option is most visible if nginx is not used,
268
+ # but nginx remains highly recommended with \Unicorn.
269
+ #
270
+ # This has no effect on UNIX sockets.
271
+ #
272
+ # Default: +true+ (Nagle's algorithm disabled) in \Unicorn,
273
+ # +true+ in Rainbows! This defaulted to +false+ in \Unicorn
274
+ # 3.x
275
+ #
276
+ # [:tcp_nopush => true or false]
277
+ #
278
+ # Enables/disables TCP_CORK in Linux or TCP_NOPUSH in FreeBSD
279
+ #
280
+ # This prevents partial TCP frames from being sent out and reduces
281
+ # wakeups in nginx if it is on a different machine. Since \Unicorn
282
+ # is only designed for applications that send the response body
283
+ # quickly without keepalive, sockets will always be flushed on close
284
+ # to prevent delays.
285
+ #
286
+ # This has no effect on UNIX sockets.
287
+ #
288
+ # Default: +false+
289
+ # This defaulted to +true+ in \Unicorn 3.4 - 3.7
290
+ #
291
+ # [:ipv6only => true or false]
292
+ #
293
+ # This option makes IPv6-capable TCP listeners IPv6-only and unable
294
+ # to receive IPv4 queries on dual-stack systems. A separate IPv4-only
295
+ # listener is required if this is true.
296
+ #
297
+ # This option is only available for Ruby 1.9.2 and later.
298
+ #
299
+ # Enabling this option for the IPv6-only listener and having a
300
+ # separate IPv4 listener is recommended if you wish to support IPv6
301
+ # on the same TCP port. Otherwise, the value of \env[\"REMOTE_ADDR\"]
302
+ # will appear as an ugly IPv4-mapped-IPv6 address for IPv4 clients
303
+ # (e.g ":ffff:10.0.0.1" instead of just "10.0.0.1").
304
+ #
305
+ # Default: Operating-system dependent
306
+ #
307
+ # [:tries => Integer]
308
+ #
309
+ # Times to retry binding a socket if it is already in use
310
+ #
311
+ # A negative number indicates we will retry indefinitely, this is
312
+ # useful for migrations and upgrades when individual workers
313
+ # are binding to different ports.
314
+ #
315
+ # Default: 5
316
+ #
317
+ # [:delay => seconds]
318
+ #
319
+ # Seconds to wait between successive +tries+
320
+ #
321
+ # Default: 0.5 seconds
322
+ #
323
+ # [:umask => mode]
324
+ #
325
+ # Sets the file mode creation mask for UNIX sockets. If specified,
326
+ # this is usually in octal notation.
327
+ #
328
+ # Typically UNIX domain sockets are created with more liberal
329
+ # file permissions than the rest of the application. By default,
330
+ # we create UNIX domain sockets to be readable and writable by
331
+ # all local users to give them the same accessibility as
332
+ # locally-bound TCP listeners.
333
+ #
334
+ # This has no effect on TCP listeners.
335
+ #
336
+ # Default: 0000 (world-read/writable)
337
+ #
338
+ # [:tcp_defer_accept => Integer]
339
+ #
340
+ # Defer accept() until data is ready (Linux-only)
341
+ #
342
+ # For Linux 2.6.32 and later, this is the number of retransmits to
343
+ # defer an accept() for if no data arrives, but the client will
344
+ # eventually be accepted after the specified number of retransmits
345
+ # regardless of whether data is ready.
346
+ #
347
+ # For Linux before 2.6.32, this is a boolean option, and
348
+ # accepts are _always_ deferred indefinitely if no data arrives.
349
+ # This is similar to <code>:accept_filter => "dataready"</code>
350
+ # under FreeBSD.
351
+ #
352
+ # Specifying +true+ is synonymous for the default value(s) below,
353
+ # and +false+ or +nil+ is synonymous for a value of zero.
354
+ #
355
+ # A value of +1+ is a good optimization for local networks
356
+ # and trusted clients. For Rainbows! and Zbatery users, a higher
357
+ # value (e.g. +60+) provides more protection against some
358
+ # denial-of-service attacks. There is no good reason to ever
359
+ # disable this with a +zero+ value when serving HTTP.
360
+ #
361
+ # Default: 1 retransmit for \Unicorn, 60 for Rainbows! 0.95.0\+
362
+ #
363
+ # [:accept_filter => String]
364
+ #
365
+ # defer accept() until data is ready (FreeBSD-only)
366
+ #
367
+ # This enables either the "dataready" or (default) "httpready"
368
+ # accept() filter under FreeBSD. This is intended as an
369
+ # optimization to reduce context switches with common GET/HEAD
370
+ # requests. For Rainbows! and Zbatery users, this provides
371
+ # some protection against certain denial-of-service attacks, too.
372
+ #
373
+ # There is no good reason to change from the default.
374
+ #
375
+ # Default: "httpready"
376
+ def listen(address, options = {})
377
+ address = expand_addr(address)
378
+ if String === address
379
+ [ :umask, :backlog, :sndbuf, :rcvbuf, :tries ].each do |key|
380
+ value = options[key] or next
381
+ Integer === value or
382
+ raise ArgumentError, "not an integer: #{key}=#{value.inspect}"
383
+ end
384
+ [ :tcp_nodelay, :tcp_nopush, :ipv6only ].each do |key|
385
+ (value = options[key]).nil? and next
386
+ TrueClass === value || FalseClass === value or
387
+ raise ArgumentError, "not boolean: #{key}=#{value.inspect}"
388
+ end
389
+ unless (value = options[:delay]).nil?
390
+ Numeric === value or
391
+ raise ArgumentError, "not numeric: delay=#{value.inspect}"
392
+ end
393
+ set[:listener_opts][address].merge!(options)
394
+ end
395
+
396
+ set[:listeners] << address
397
+ end
398
+
399
+ # sets the +path+ for the PID file of the unicorn master process
400
+ def pid(path); set_path(:pid, path); end
401
+
402
+ # Enabling this preloads an application before forking worker
403
+ # processes. This allows memory savings when using a
404
+ # copy-on-write-friendly GC but can cause bad things to happen when
405
+ # resources like sockets are opened at load time by the master
406
+ # process and shared by multiple children. People enabling this are
407
+ # highly encouraged to look at the before_fork/after_fork hooks to
408
+ # properly close/reopen sockets. Files opened for logging do not
409
+ # have to be reopened as (unbuffered-in-userspace) files opened with
410
+ # the File::APPEND flag are written to atomically on UNIX.
411
+ #
412
+ # In addition to reloading the unicorn-specific config settings,
413
+ # SIGHUP will reload application code in the working
414
+ # directory/symlink when workers are gracefully restarted when
415
+ # preload_app=false (the default). As reloading the application
416
+ # sometimes requires RubyGems updates, +Gem.refresh+ is always
417
+ # called before the application is loaded (for RubyGems users).
418
+ #
419
+ # During deployments, care should _always_ be taken to ensure your
420
+ # applications are properly deployed and running. Using
421
+ # preload_app=false (the default) means you _must_ check if
422
+ # your application is responding properly after a deployment.
423
+ # Improperly deployed applications can go into a spawn loop
424
+ # if the application fails to load. While your children are
425
+ # in a spawn loop, it is is possible to fix an application
426
+ # by properly deploying all required code and dependencies.
427
+ # Using preload_app=true means any application load error will
428
+ # cause the master process to exit with an error.
429
+
430
+ def preload_app(bool)
431
+ set_bool(:preload_app, bool)
432
+ end
433
+
434
+ # Toggles making \env[\"rack.input\"] rewindable.
435
+ # Disabling rewindability can improve performance by lowering
436
+ # I/O and memory usage for applications that accept uploads.
437
+ # Keep in mind that the Rack 1.x spec requires
438
+ # \env[\"rack.input\"] to be rewindable, so this allows
439
+ # intentionally violating the current Rack 1.x spec.
440
+ #
441
+ # +rewindable_input+ defaults to +true+ when used with Rack 1.x for
442
+ # Rack conformance. When Rack 2.x is finalized, this will most
443
+ # likely default to +false+ while still conforming to the newer
444
+ # (less demanding) spec.
445
+ def rewindable_input(bool)
446
+ set_bool(:rewindable_input, bool)
447
+ end
448
+
449
+ # The maximum size (in +bytes+) to buffer in memory before
450
+ # resorting to a temporary file. Default is 112 kilobytes.
451
+ # This option has no effect if "rewindable_input" is set to
452
+ # +false+.
453
+ def client_body_buffer_size(bytes)
454
+ set_int(:client_body_buffer_size, bytes, 0)
455
+ end
456
+
457
+ # Allow redirecting $stderr to a given path. Unlike doing this from
458
+ # the shell, this allows the unicorn process to know the path its
459
+ # writing to and rotate the file if it is used for logging. The
460
+ # file will be opened with the File::APPEND flag and writes
461
+ # synchronized to the kernel (but not necessarily to _disk_) so
462
+ # multiple processes can safely append to it.
463
+ #
464
+ # If you are daemonizing and using the default +logger+, it is important
465
+ # to specify this as errors will otherwise be lost to /dev/null.
466
+ # Some applications/libraries may also triggering warnings that go to
467
+ # stderr, and they will end up here.
468
+ def stderr_path(path)
469
+ set_path(:stderr_path, path)
470
+ end
471
+
472
+ # Same as stderr_path, except for $stdout. Not many Rack applications
473
+ # write to $stdout, but any that do will have their output written here.
474
+ # It is safe to point this to the same location a stderr_path.
475
+ # Like stderr_path, this defaults to /dev/null when daemonized.
476
+ def stdout_path(path)
477
+ set_path(:stdout_path, path)
478
+ end
479
+
480
+ # sets the working directory for Unicorn. This ensures SIGUSR2 will
481
+ # start a new instance of Unicorn in this directory. This may be
482
+ # a symlink, a common scenario for Capistrano users. Unlike
483
+ # all other Unicorn configuration directives, this binds immediately
484
+ # for error checking and cannot be undone by unsetting it in the
485
+ # configuration file and reloading.
486
+ def working_directory(path)
487
+ # just let chdir raise errors
488
+ path = File.expand_path(path)
489
+ if config_file &&
490
+ config_file[0] != ?/ &&
491
+ ! File.readable?("#{path}/#{config_file}")
492
+ raise ArgumentError,
493
+ "config_file=#{config_file} would not be accessible in" \
494
+ " working_directory=#{path}"
495
+ end
496
+ Dir.chdir(path)
497
+ Unicorn::HttpServer::START_CTX[:cwd] = ENV["PWD"] = path
498
+ end
499
+
500
+ # Runs worker processes as the specified +user+ and +group+.
501
+ # The master process always stays running as the user who started it.
502
+ # This switch will occur after calling the after_fork hook, and only
503
+ # if the Worker#user method is not called in the after_fork hook
504
+ # +group+ is optional and will not change if unspecified.
505
+ def user(user, group = nil)
506
+ # raises ArgumentError on invalid user/group
507
+ Etc.getpwnam(user)
508
+ Etc.getgrnam(group) if group
509
+ set[:user] = [ user, group ]
510
+ end
511
+
512
+ # Sets whether or not the parser will trust X-Forwarded-Proto and
513
+ # X-Forwarded-SSL headers and set "rack.url_scheme" to "https" accordingly.
514
+ # Rainbows!/Zbatery installations facing untrusted clients directly
515
+ # should set this to +false+. This is +true+ by default as Unicorn
516
+ # is designed to only sit behind trusted nginx proxies.
517
+ #
518
+ # This has never been publically documented and is subject to removal
519
+ # in future releases.
520
+ def trust_x_forwarded(bool) # :nodoc:
521
+ set_bool(:trust_x_forwarded, bool)
522
+ end
523
+
524
+ # expands "unix:path/to/foo" to a socket relative to the current path
525
+ # expands pathnames of sockets if relative to "~" or "~username"
526
+ # expands "*:port and ":port" to "0.0.0.0:port"
527
+ def expand_addr(address) #:nodoc:
528
+ return "0.0.0.0:#{address}" if Integer === address
529
+ return address unless String === address
530
+
531
+ case address
532
+ when %r{\Aunix:(.*)\z}
533
+ File.expand_path($1)
534
+ when %r{\A~}
535
+ File.expand_path(address)
536
+ when %r{\A(?:\*:)?(\d+)\z}
537
+ "0.0.0.0:#$1"
538
+ when %r{\A\[([a-fA-F0-9:]+)\]\z}, %r/\A((?:\d+\.){3}\d+)\z/
539
+ canonicalize_tcp($1, 80)
540
+ when %r{\A\[([a-fA-F0-9:]+)\]:(\d+)\z}, %r{\A(.*):(\d+)\z}
541
+ canonicalize_tcp($1, $2.to_i)
542
+ else
543
+ address
544
+ end
545
+ end
546
+
547
+ private
548
+ def set_int(var, n, min) #:nodoc:
549
+ Integer === n or raise ArgumentError, "not an integer: #{var}=#{n.inspect}"
550
+ n >= min or raise ArgumentError, "too low (< #{min}): #{var}=#{n.inspect}"
551
+ set[var] = n
552
+ end
553
+
554
+ def canonicalize_tcp(addr, port)
555
+ packed = Socket.pack_sockaddr_in(port, addr)
556
+ port, addr = Socket.unpack_sockaddr_in(packed)
557
+ /:/ =~ addr ? "[#{addr}]:#{port}" : "#{addr}:#{port}"
558
+ end
559
+
560
+ def set_path(var, path) #:nodoc:
561
+ case path
562
+ when NilClass, String
563
+ set[var] = path
564
+ else
565
+ raise ArgumentError
566
+ end
567
+ end
568
+
569
+ def check_bool(var, bool) # :nodoc:
570
+ case bool
571
+ when true, false
572
+ return bool
573
+ end
574
+ raise ArgumentError, "#{var}=#{bool.inspect} not a boolean"
575
+ end
576
+
577
+ def set_bool(var, bool) #:nodoc:
578
+ set[var] = check_bool(var, bool)
579
+ end
580
+
581
+ def set_hook(var, my_proc, req_arity = 2) #:nodoc:
582
+ case my_proc
583
+ when Proc
584
+ arity = my_proc.arity
585
+ (arity == req_arity) or \
586
+ raise ArgumentError,
587
+ "#{var}=#{my_proc.inspect} has invalid arity: " \
588
+ "#{arity} (need #{req_arity})"
589
+ when NilClass
590
+ my_proc = DEFAULTS[var]
591
+ else
592
+ raise ArgumentError, "invalid type: #{var}=#{my_proc.inspect}"
593
+ end
594
+ set[var] = my_proc
595
+ end
596
+
597
+ # this is called _after_ working_directory is bound. This only
598
+ # parses the embedded switches in .ru files
599
+ # (for "rackup" compatibility)
600
+ def parse_rackup_file # :nodoc:
601
+ ru = RACKUP[:file] or return # we only return here in unit tests
602
+
603
+ # :rails means use (old) Rails autodetect
604
+ if ru == :rails
605
+ File.readable?('config.ru') or return
606
+ ru = 'config.ru'
607
+ end
608
+
609
+ File.readable?(ru) or
610
+ raise ArgumentError, "rackup file (#{ru}) not readable"
611
+
612
+ # it could be a .rb file, too, we don't parse those manually
613
+ ru =~ /\.ru\z/ or return
614
+
615
+ /^#\\(.*)/ =~ File.read(ru) or return
616
+ RACKUP[:optparse].parse!($1.split(/\s+/))
617
+
618
+ if RACKUP[:daemonize]
619
+ # unicorn_rails wants a default pid path, (not plain 'unicorn')
620
+ if after_reload
621
+ spid = set[:pid]
622
+ pid('tmp/pids/unicorn.pid') if spid.nil? || spid == :unset
623
+ end
624
+ unless RACKUP[:daemonized]
625
+ Unicorn::Launcher.daemonize!(RACKUP[:options])
626
+ RACKUP[:ready_pipe] = RACKUP[:options].delete(:ready_pipe)
627
+ end
628
+ end
629
+ end
630
+ end