unicorn-maintained 6.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. checksums.yaml +7 -0
  2. data/.CHANGELOG.old +25 -0
  3. data/.document +28 -0
  4. data/.gitattributes +5 -0
  5. data/.gitignore +25 -0
  6. data/.mailmap +26 -0
  7. data/.manifest +149 -0
  8. data/.olddoc.yml +25 -0
  9. data/Application_Timeouts +77 -0
  10. data/CONTRIBUTORS +39 -0
  11. data/COPYING +674 -0
  12. data/DESIGN +99 -0
  13. data/Documentation/.gitignore +3 -0
  14. data/Documentation/unicorn.1 +222 -0
  15. data/Documentation/unicorn_rails.1 +207 -0
  16. data/FAQ +70 -0
  17. data/GIT-VERSION-FILE +1 -0
  18. data/GIT-VERSION-GEN +39 -0
  19. data/GNUmakefile +317 -0
  20. data/HACKING +112 -0
  21. data/ISSUES +102 -0
  22. data/KNOWN_ISSUES +79 -0
  23. data/LATEST +1 -0
  24. data/LICENSE +67 -0
  25. data/Links +58 -0
  26. data/NEWS +1 -0
  27. data/PHILOSOPHY +139 -0
  28. data/README +156 -0
  29. data/Rakefile +16 -0
  30. data/SIGNALS +123 -0
  31. data/Sandbox +104 -0
  32. data/TODO +3 -0
  33. data/TUNING +119 -0
  34. data/archive/.gitignore +3 -0
  35. data/archive/slrnpull.conf +4 -0
  36. data/bin/unicorn +128 -0
  37. data/bin/unicorn_rails +209 -0
  38. data/examples/big_app_gc.rb +2 -0
  39. data/examples/echo.ru +26 -0
  40. data/examples/init.sh +102 -0
  41. data/examples/logger_mp_safe.rb +25 -0
  42. data/examples/logrotate.conf +44 -0
  43. data/examples/nginx.conf +156 -0
  44. data/examples/unicorn.conf.minimal.rb +13 -0
  45. data/examples/unicorn.conf.rb +110 -0
  46. data/examples/unicorn.socket +11 -0
  47. data/examples/unicorn@.service +40 -0
  48. data/ext/unicorn_http/CFLAGS +13 -0
  49. data/ext/unicorn_http/c_util.h +116 -0
  50. data/ext/unicorn_http/common_field_optimization.h +128 -0
  51. data/ext/unicorn_http/epollexclusive.h +128 -0
  52. data/ext/unicorn_http/ext_help.h +38 -0
  53. data/ext/unicorn_http/extconf.rb +39 -0
  54. data/ext/unicorn_http/global_variables.h +97 -0
  55. data/ext/unicorn_http/httpdate.c +91 -0
  56. data/ext/unicorn_http/unicorn_http.c +4334 -0
  57. data/ext/unicorn_http/unicorn_http.rl +1040 -0
  58. data/ext/unicorn_http/unicorn_http_common.rl +76 -0
  59. data/lib/unicorn/app/old_rails/static.rb +59 -0
  60. data/lib/unicorn/app/old_rails.rb +35 -0
  61. data/lib/unicorn/cgi_wrapper.rb +147 -0
  62. data/lib/unicorn/configurator.rb +748 -0
  63. data/lib/unicorn/const.rb +21 -0
  64. data/lib/unicorn/http_request.rb +201 -0
  65. data/lib/unicorn/http_response.rb +93 -0
  66. data/lib/unicorn/http_server.rb +859 -0
  67. data/lib/unicorn/launcher.rb +62 -0
  68. data/lib/unicorn/oob_gc.rb +81 -0
  69. data/lib/unicorn/preread_input.rb +33 -0
  70. data/lib/unicorn/select_waiter.rb +6 -0
  71. data/lib/unicorn/socket_helper.rb +185 -0
  72. data/lib/unicorn/stream_input.rb +151 -0
  73. data/lib/unicorn/tee_input.rb +131 -0
  74. data/lib/unicorn/tmpio.rb +33 -0
  75. data/lib/unicorn/util.rb +90 -0
  76. data/lib/unicorn/version.rb +1 -0
  77. data/lib/unicorn/worker.rb +165 -0
  78. data/lib/unicorn.rb +136 -0
  79. data/man/man1/unicorn.1 +222 -0
  80. data/man/man1/unicorn_rails.1 +207 -0
  81. data/setup.rb +1586 -0
  82. data/t/.gitignore +4 -0
  83. data/t/GNUmakefile +5 -0
  84. data/t/README +49 -0
  85. data/t/active-unix-socket.t +117 -0
  86. data/t/bin/unused_listen +40 -0
  87. data/t/broken-app.ru +12 -0
  88. data/t/client_body_buffer_size.ru +14 -0
  89. data/t/client_body_buffer_size.t +80 -0
  90. data/t/detach.ru +11 -0
  91. data/t/env.ru +3 -0
  92. data/t/fails-rack-lint.ru +5 -0
  93. data/t/heartbeat-timeout.ru +12 -0
  94. data/t/heartbeat-timeout.t +62 -0
  95. data/t/integration.ru +115 -0
  96. data/t/integration.t +356 -0
  97. data/t/lib.perl +258 -0
  98. data/t/listener_names.ru +4 -0
  99. data/t/my-tap-lib.sh +201 -0
  100. data/t/oob_gc.ru +17 -0
  101. data/t/oob_gc_path.ru +17 -0
  102. data/t/pid.ru +3 -0
  103. data/t/preread_input.ru +22 -0
  104. data/t/reload-bad-config.t +54 -0
  105. data/t/reopen-logs.ru +13 -0
  106. data/t/reopen-logs.t +39 -0
  107. data/t/t0008-back_out_of_upgrade.sh +110 -0
  108. data/t/t0009-broken-app.sh +56 -0
  109. data/t/t0010-reap-logging.sh +55 -0
  110. data/t/t0012-reload-empty-config.sh +86 -0
  111. data/t/t0013-rewindable-input-false.sh +24 -0
  112. data/t/t0013.ru +12 -0
  113. data/t/t0014-rewindable-input-true.sh +24 -0
  114. data/t/t0014.ru +12 -0
  115. data/t/t0015-configurator-internals.sh +25 -0
  116. data/t/t0020-at_exit-handler.sh +49 -0
  117. data/t/t0021-process_detach.sh +29 -0
  118. data/t/t0022-listener_names-preload_app.sh +32 -0
  119. data/t/t0300-no-default-middleware.sh +20 -0
  120. data/t/t0301-no-default-middleware-ignored-in-config.sh +25 -0
  121. data/t/t0301.ru +13 -0
  122. data/t/t9001-oob_gc.sh +47 -0
  123. data/t/t9002-oob_gc-path.sh +75 -0
  124. data/t/test-lib.sh +125 -0
  125. data/t/winch_ttin.t +67 -0
  126. data/t/working_directory.t +94 -0
  127. data/test/aggregate.rb +15 -0
  128. data/test/benchmark/README +60 -0
  129. data/test/benchmark/dd.ru +18 -0
  130. data/test/benchmark/ddstream.ru +50 -0
  131. data/test/benchmark/readinput.ru +40 -0
  132. data/test/benchmark/stack.ru +8 -0
  133. data/test/benchmark/uconnect.perl +66 -0
  134. data/test/exec/README +5 -0
  135. data/test/exec/test_exec.rb +1029 -0
  136. data/test/test_helper.rb +306 -0
  137. data/test/unit/test_ccc.rb +91 -0
  138. data/test/unit/test_configurator.rb +175 -0
  139. data/test/unit/test_droplet.rb +28 -0
  140. data/test/unit/test_http_parser.rb +884 -0
  141. data/test/unit/test_http_parser_ng.rb +714 -0
  142. data/test/unit/test_request.rb +169 -0
  143. data/test/unit/test_server.rb +244 -0
  144. data/test/unit/test_signals.rb +188 -0
  145. data/test/unit/test_socket_helper.rb +159 -0
  146. data/test/unit/test_stream_input.rb +210 -0
  147. data/test/unit/test_tee_input.rb +303 -0
  148. data/test/unit/test_util.rb +131 -0
  149. data/test/unit/test_waiter.rb +34 -0
  150. data/unicorn.gemspec +48 -0
  151. metadata +275 -0
@@ -0,0 +1,21 @@
1
+ # -*- encoding: binary -*-
2
+
3
+ module Unicorn::Const # :nodoc:
4
+ # default TCP listen host address (0.0.0.0, all interfaces)
5
+ DEFAULT_HOST = "0.0.0.0"
6
+
7
+ # default TCP listen port (8080)
8
+ DEFAULT_PORT = 8080
9
+
10
+ # default TCP listen address and port (0.0.0.0:8080)
11
+ DEFAULT_LISTEN = "#{DEFAULT_HOST}:#{DEFAULT_PORT}"
12
+
13
+ # The basic request body size we'll try to read at once (16 kilobytes).
14
+ CHUNK_SIZE = 16 * 1024
15
+
16
+ # Maximum request body size before it is moved out of memory and into a
17
+ # temporary file for reading (112 kilobytes). This is the default
18
+ # value of client_body_buffer_size.
19
+ MAX_BODY = 1024 * 112
20
+ end
21
+ require_relative 'version'
@@ -0,0 +1,201 @@
1
+ # -*- encoding: binary -*-
2
+ # :enddoc:
3
+ # no stable API here
4
+ require 'unicorn_http'
5
+
6
+ # TODO: remove redundant names
7
+ Unicorn.const_set(:HttpRequest, Unicorn::HttpParser)
8
+ class Unicorn::HttpParser
9
+
10
+ # default parameters we merge into the request env for Rack handlers
11
+ DEFAULTS = {
12
+ "rack.errors" => $stderr,
13
+ "rack.multiprocess" => true,
14
+ "rack.multithread" => false,
15
+ "rack.run_once" => false,
16
+ "rack.version" => [1, 2],
17
+ "rack.hijack?" => true,
18
+ "SCRIPT_NAME" => "",
19
+
20
+ # this is not in the Rack spec, but some apps may rely on it
21
+ "SERVER_SOFTWARE" => "Unicorn #{Unicorn::Const::UNICORN_VERSION}"
22
+ }
23
+
24
+ NULL_IO = StringIO.new("")
25
+
26
+ # :stopdoc:
27
+ HTTP_RESPONSE_START = [ 'HTTP'.freeze, '/1.1 '.freeze ]
28
+ EMPTY_ARRAY = [].freeze
29
+ @@input_class = Unicorn::TeeInput
30
+ @@check_client_connection = false
31
+ @@tcpi_inspect_ok = Socket.const_defined?(:TCP_INFO)
32
+
33
+ def self.input_class
34
+ @@input_class
35
+ end
36
+
37
+ def self.input_class=(klass)
38
+ @@input_class = klass
39
+ end
40
+
41
+ def self.check_client_connection
42
+ @@check_client_connection
43
+ end
44
+
45
+ def self.check_client_connection=(bool)
46
+ @@check_client_connection = bool
47
+ end
48
+
49
+ # :startdoc:
50
+
51
+ # Does the majority of the IO processing. It has been written in
52
+ # Ruby using about 8 different IO processing strategies.
53
+ #
54
+ # It is currently carefully constructed to make sure that it gets
55
+ # the best possible performance for the common case: GET requests
56
+ # that are fully complete after a single read(2)
57
+ #
58
+ # Anyone who thinks they can make it faster is more than welcome to
59
+ # take a crack at it.
60
+ #
61
+ # returns an environment hash suitable for Rack if successful
62
+ # This does minimal exception trapping and it is up to the caller
63
+ # to handle any socket errors (e.g. user aborted upload).
64
+ def read_headers(socket, ai)
65
+ e = env
66
+
67
+ # From https://www.ietf.org/rfc/rfc3875:
68
+ # "Script authors should be aware that the REMOTE_ADDR and
69
+ # REMOTE_HOST meta-variables (see sections 4.1.8 and 4.1.9)
70
+ # may not identify the ultimate source of the request. They
71
+ # identify the client for the immediate request to the server;
72
+ # that client may be a proxy, gateway, or other intermediary
73
+ # acting on behalf of the actual source client."
74
+ e['REMOTE_ADDR'] = ai.unix? ? '127.0.0.1' : ai.ip_address
75
+
76
+ # short circuit the common case with small GET requests first
77
+ socket.readpartial(16384, buf)
78
+ if parse.nil?
79
+ # Parser is not done, queue up more data to read and continue parsing
80
+ # an Exception thrown from the parser will throw us out of the loop
81
+ false until add_parse(socket.readpartial(16384))
82
+ end
83
+
84
+ check_client_connection(socket, ai) if @@check_client_connection
85
+
86
+ e['rack.input'] = 0 == content_length ?
87
+ NULL_IO : @@input_class.new(socket, self)
88
+
89
+ # for Rack hijacking in Rack 1.5 and later
90
+ e['unicorn.socket'] = socket
91
+ e['rack.hijack'] = self
92
+
93
+ e.merge!(DEFAULTS)
94
+ end
95
+
96
+ # for rack.hijack, we respond to this method so no extra allocation
97
+ # of a proc object
98
+ def call
99
+ hijacked!
100
+ env['rack.hijack_io'] = env['unicorn.socket']
101
+ end
102
+
103
+ def hijacked?
104
+ env.include?('rack.hijack_io'.freeze)
105
+ end
106
+
107
+ if Raindrops.const_defined?(:TCP_Info)
108
+ TCPI = Raindrops::TCP_Info.allocate
109
+
110
+ def check_client_connection(socket, ai) # :nodoc:
111
+ if ai.ip?
112
+ # Raindrops::TCP_Info#get!, #state (reads struct tcp_info#tcpi_state)
113
+ raise Errno::EPIPE, "client closed connection".freeze,
114
+ EMPTY_ARRAY if closed_state?(TCPI.get!(socket).state)
115
+ else
116
+ write_http_header(socket)
117
+ end
118
+ end
119
+
120
+ if Raindrops.const_defined?(:TCP)
121
+ # raindrops 0.18.0+ supports FreeBSD + Linux using the same names
122
+ # Evaluate these hash lookups at load time so we can
123
+ # generate an opt_case_dispatch instruction
124
+ eval <<-EOS
125
+ def closed_state?(state) # :nodoc:
126
+ case state
127
+ when #{Raindrops::TCP[:ESTABLISHED]}
128
+ false
129
+ when #{Raindrops::TCP.values_at(
130
+ :CLOSE_WAIT, :TIME_WAIT, :CLOSE, :LAST_ACK, :CLOSING).join(',')}
131
+ true
132
+ else
133
+ false
134
+ end
135
+ end
136
+ EOS
137
+ else
138
+ # raindrops before 0.18 only supported TCP_INFO under Linux
139
+ def closed_state?(state) # :nodoc:
140
+ case state
141
+ when 1 # ESTABLISHED
142
+ false
143
+ when 8, 6, 7, 9, 11 # CLOSE_WAIT, TIME_WAIT, CLOSE, LAST_ACK, CLOSING
144
+ true
145
+ else
146
+ false
147
+ end
148
+ end
149
+ end
150
+ else
151
+
152
+ # Ruby 2.2+ can show struct tcp_info as a string Socket::Option#inspect.
153
+ # Not that efficient, but probably still better than doing unnecessary
154
+ # work after a client gives up.
155
+ def check_client_connection(socket, ai) # :nodoc:
156
+ if @@tcpi_inspect_ok && ai.ip?
157
+ opt = socket.getsockopt(Socket::IPPROTO_TCP, Socket::TCP_INFO).inspect
158
+ if opt =~ /\bstate=(\S+)/
159
+ raise Errno::EPIPE, "client closed connection".freeze,
160
+ EMPTY_ARRAY if closed_state_str?($1)
161
+ else
162
+ @@tcpi_inspect_ok = false
163
+ write_http_header(socket)
164
+ end
165
+ opt.clear
166
+ else
167
+ write_http_header(socket)
168
+ end
169
+ end
170
+
171
+ def closed_state_str?(state)
172
+ case state
173
+ when 'ESTABLISHED'
174
+ false
175
+ # not a typo, ruby maps TCP_CLOSE (no 'D') to state=CLOSED (w/ 'D')
176
+ when 'CLOSE_WAIT', 'TIME_WAIT', 'CLOSED', 'LAST_ACK', 'CLOSING'
177
+ true
178
+ else
179
+ false
180
+ end
181
+ end
182
+ end
183
+
184
+ def write_http_header(socket) # :nodoc:
185
+ if headers?
186
+ self.response_start_sent = true
187
+ HTTP_RESPONSE_START.each { |c| socket.write(c) }
188
+ end
189
+ end
190
+
191
+ # called by ext/unicorn_http/unicorn_http.rl via rb_funcall
192
+ def self.is_chunked?(v) # :nodoc:
193
+ vals = v.split(/[ \t]*,[ \t]*/).map!(&:downcase)
194
+ if vals.pop == 'chunked'.freeze
195
+ return true unless vals.include?('chunked'.freeze)
196
+ raise Unicorn::HttpParserError, 'double chunked', []
197
+ end
198
+ return false unless vals.include?('chunked'.freeze)
199
+ raise Unicorn::HttpParserError, 'chunked not last', []
200
+ end
201
+ end
@@ -0,0 +1,93 @@
1
+ # -*- encoding: binary -*-
2
+ # :enddoc:
3
+ # Writes a Rack response to your client using the HTTP/1.1 specification.
4
+ # You use it by simply doing:
5
+ #
6
+ # status, headers, body = rack_app.call(env)
7
+ # http_response_write(socket, status, headers, body)
8
+ #
9
+ # Most header correctness (including Content-Length and Content-Type)
10
+ # is the job of Rack, with the exception of the "Date" and "Status" header.
11
+ module Unicorn::HttpResponse
12
+
13
+ STATUS_CODES = defined?(Rack::Utils::HTTP_STATUS_CODES) ?
14
+ Rack::Utils::HTTP_STATUS_CODES : {}
15
+ STATUS_WITH_NO_ENTITY_BODY = defined?(
16
+ Rack::Utils::STATUS_WITH_NO_ENTITY_BODY) ?
17
+ Rack::Utils::STATUS_WITH_NO_ENTITY_BODY : begin
18
+ warn 'Rack::Utils::STATUS_WITH_NO_ENTITY_BODY missing'
19
+ {}
20
+ end
21
+
22
+ # internal API, code will always be common-enough-for-even-old-Rack
23
+ def err_response(code, response_start_sent)
24
+ "#{response_start_sent ? '' : 'HTTP/1.1 '}" \
25
+ "#{code} #{STATUS_CODES[code]}\r\n\r\n"
26
+ end
27
+
28
+ def append_header(buf, key, value)
29
+ case value
30
+ when Array # Rack 3
31
+ value.each { |v| buf << "#{key}: #{v}\r\n" }
32
+ when /\n/ # Rack 2
33
+ # avoiding blank, key-only cookies with /\n+/
34
+ value.split(/\n+/).each { |v| buf << "#{key}: #{v}\r\n" }
35
+ else
36
+ buf << "#{key}: #{value}\r\n"
37
+ end
38
+ end
39
+
40
+ # writes the rack_response to socket as an HTTP response
41
+ def http_response_write(socket, status, headers, body,
42
+ req = Unicorn::HttpRequest.new)
43
+ hijack = nil
44
+ do_chunk = false
45
+ if headers
46
+ code = status.to_i
47
+ msg = STATUS_CODES[code]
48
+ start = req.response_start_sent ? ''.freeze : 'HTTP/1.1 '.freeze
49
+ term = STATUS_WITH_NO_ENTITY_BODY.include?(code) || false
50
+ buf = "#{start}#{msg ? %Q(#{code} #{msg}) : status}\r\n" \
51
+ "Date: #{httpdate}\r\n" \
52
+ "Connection: close\r\n"
53
+ headers.each do |key, value|
54
+ case key
55
+ when %r{\A(?:Date|Connection)\z}i
56
+ next
57
+ when %r{\AContent-Length\z}i
58
+ append_header(buf, key, value)
59
+ term = true
60
+ when %r{\ATransfer-Encoding\z}i
61
+ append_header(buf, key, value)
62
+ term = true if /\bchunked\b/i === value # value may be Array :x
63
+ when "rack.hijack"
64
+ # This should only be hit under Rack >= 1.5, as this was an illegal
65
+ # key in Rack < 1.5
66
+ hijack = value
67
+ else
68
+ append_header(buf, key, value)
69
+ end
70
+ end
71
+ if !hijack && !term && req.chunkable_response?
72
+ do_chunk = true
73
+ buf << "Transfer-Encoding: chunked\r\n".freeze
74
+ end
75
+ socket.write(buf << "\r\n".freeze)
76
+ end
77
+
78
+ if hijack
79
+ req.hijacked!
80
+ hijack.call(socket)
81
+ elsif do_chunk
82
+ begin
83
+ body.each do |b|
84
+ socket.write("#{b.bytesize.to_s(16)}\r\n", b, "\r\n".freeze)
85
+ end
86
+ ensure
87
+ socket.write("0\r\n\r\n".freeze)
88
+ end
89
+ else
90
+ body.each { |chunk| socket.write(chunk) }
91
+ end
92
+ end
93
+ end