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