unicorn-shopify 4.8.2.5.23

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