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