puma 5.2.2 → 6.3.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.
Potentially problematic release.
This version of puma might be problematic. Click here for more details.
- checksums.yaml +4 -4
 - data/History.md +483 -4
 - data/README.md +101 -20
 - data/bin/puma-wild +1 -1
 - data/docs/architecture.md +50 -16
 - data/docs/compile_options.md +38 -2
 - data/docs/deployment.md +53 -67
 - data/docs/fork_worker.md +1 -3
 - data/docs/jungle/rc.d/README.md +1 -1
 - data/docs/kubernetes.md +1 -1
 - data/docs/nginx.md +1 -1
 - data/docs/plugins.md +15 -15
 - data/docs/rails_dev_mode.md +2 -3
 - data/docs/restart.md +7 -7
 - data/docs/signals.md +11 -10
 - data/docs/stats.md +8 -8
 - data/docs/systemd.md +65 -69
 - data/docs/testing_benchmarks_local_files.md +150 -0
 - data/docs/testing_test_rackup_ci_files.md +36 -0
 - data/ext/puma_http11/extconf.rb +44 -13
 - data/ext/puma_http11/http11_parser.c +24 -11
 - data/ext/puma_http11/http11_parser.h +2 -2
 - data/ext/puma_http11/http11_parser.java.rl +2 -2
 - data/ext/puma_http11/http11_parser.rl +2 -2
 - data/ext/puma_http11/http11_parser_common.rl +3 -3
 - data/ext/puma_http11/mini_ssl.c +150 -23
 - data/ext/puma_http11/org/jruby/puma/Http11.java +3 -3
 - data/ext/puma_http11/org/jruby/puma/Http11Parser.java +50 -48
 - data/ext/puma_http11/org/jruby/puma/MiniSSL.java +188 -102
 - data/ext/puma_http11/puma_http11.c +18 -10
 - data/lib/puma/app/status.rb +10 -7
 - data/lib/puma/binder.rb +112 -62
 - data/lib/puma/cli.rb +24 -20
 - data/lib/puma/client.rb +162 -36
 - data/lib/puma/cluster/worker.rb +31 -27
 - data/lib/puma/cluster/worker_handle.rb +12 -1
 - data/lib/puma/cluster.rb +102 -61
 - data/lib/puma/commonlogger.rb +21 -14
 - data/lib/puma/configuration.rb +78 -54
 - data/lib/puma/const.rb +135 -97
 - data/lib/puma/control_cli.rb +25 -20
 - data/lib/puma/detect.rb +12 -2
 - data/lib/puma/dsl.rb +308 -58
 - data/lib/puma/error_logger.rb +20 -11
 - data/lib/puma/events.rb +6 -126
 - data/lib/puma/io_buffer.rb +39 -4
 - data/lib/puma/jruby_restart.rb +2 -1
 - data/lib/puma/{json.rb → json_serialization.rb} +1 -1
 - data/lib/puma/launcher/bundle_pruner.rb +104 -0
 - data/lib/puma/launcher.rb +114 -173
 - data/lib/puma/log_writer.rb +147 -0
 - data/lib/puma/minissl/context_builder.rb +30 -16
 - data/lib/puma/minissl.rb +132 -38
 - data/lib/puma/null_io.rb +5 -0
 - data/lib/puma/plugin/systemd.rb +90 -0
 - data/lib/puma/plugin/tmp_restart.rb +1 -1
 - data/lib/puma/plugin.rb +2 -2
 - data/lib/puma/rack/builder.rb +7 -7
 - data/lib/puma/rack_default.rb +19 -4
 - data/lib/puma/reactor.rb +19 -10
 - data/lib/puma/request.rb +373 -153
 - data/lib/puma/runner.rb +74 -28
 - data/lib/puma/sd_notify.rb +149 -0
 - data/lib/puma/server.rb +127 -136
 - data/lib/puma/single.rb +13 -11
 - data/lib/puma/state_file.rb +39 -7
 - data/lib/puma/thread_pool.rb +33 -26
 - data/lib/puma/util.rb +20 -15
 - data/lib/puma.rb +28 -11
 - data/lib/rack/handler/puma.rb +113 -86
 - data/tools/Dockerfile +1 -1
 - metadata +15 -10
 - data/lib/puma/queue_close.rb +0 -26
 - data/lib/puma/systemd.rb +0 -46
 
    
        data/lib/puma/client.rb
    CHANGED
    
    | 
         @@ -8,7 +8,8 @@ class IO 
     | 
|
| 
       8 
8 
     | 
    
         
             
              end
         
     | 
| 
       9 
9 
     | 
    
         
             
            end
         
     | 
| 
       10 
10 
     | 
    
         | 
| 
       11 
     | 
    
         
            -
             
     | 
| 
      
 11 
     | 
    
         
            +
            require_relative 'detect'
         
     | 
| 
      
 12 
     | 
    
         
            +
            require_relative 'io_buffer'
         
     | 
| 
       12 
13 
     | 
    
         
             
            require 'tempfile'
         
     | 
| 
       13 
14 
     | 
    
         
             
            require 'forwardable'
         
     | 
| 
       14 
15 
     | 
    
         | 
| 
         @@ -23,6 +24,11 @@ module Puma 
     | 
|
| 
       23 
24 
     | 
    
         | 
| 
       24 
25 
     | 
    
         
             
              class ConnectionError < RuntimeError; end
         
     | 
| 
       25 
26 
     | 
    
         | 
| 
      
 27 
     | 
    
         
            +
              class HttpParserError501 < IOError; end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
              #———————————————————————— DO NOT USE — this class is for internal use only ———
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
       26 
32 
     | 
    
         
             
              # An instance of this class represents a unique request from a client.
         
     | 
| 
       27 
33 
     | 
    
         
             
              # For example, this could be a web request from a browser or from CURL.
         
     | 
| 
       28 
34 
     | 
    
         
             
              #
         
     | 
| 
         @@ -35,7 +41,21 @@ module Puma 
     | 
|
| 
       35 
41 
     | 
    
         
             
              # Instances of this class are responsible for knowing if
         
     | 
| 
       36 
42 
     | 
    
         
             
              # the header and body are fully buffered via the `try_to_finish` method.
         
     | 
| 
       37 
43 
     | 
    
         
             
              # They can be used to "time out" a response via the `timeout_at` reader.
         
     | 
| 
       38 
     | 
    
         
            -
               
     | 
| 
      
 44 
     | 
    
         
            +
              #
         
     | 
| 
      
 45 
     | 
    
         
            +
              class Client # :nodoc:
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                # this tests all values but the last, which must be chunked
         
     | 
| 
      
 48 
     | 
    
         
            +
                ALLOWED_TRANSFER_ENCODING = %w[compress deflate gzip].freeze
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                # chunked body validation
         
     | 
| 
      
 51 
     | 
    
         
            +
                CHUNK_SIZE_INVALID = /[^\h]/.freeze
         
     | 
| 
      
 52 
     | 
    
         
            +
                CHUNK_VALID_ENDING = "\r\n".freeze
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                # Content-Length header value validation
         
     | 
| 
      
 55 
     | 
    
         
            +
                CONTENT_LENGTH_VALUE_INVALID = /[^\d]/.freeze
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                TE_ERR_MSG = 'Invalid Transfer-Encoding'
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
       39 
59 
     | 
    
         
             
                # The object used for a request with no body. All requests with
         
     | 
| 
       40 
60 
     | 
    
         
             
                # no body share this one object since it has no state.
         
     | 
| 
       41 
61 
     | 
    
         
             
                EmptyBody = NullIO.new
         
     | 
| 
         @@ -46,16 +66,14 @@ module Puma 
     | 
|
| 
       46 
66 
     | 
    
         
             
                def initialize(io, env=nil)
         
     | 
| 
       47 
67 
     | 
    
         
             
                  @io = io
         
     | 
| 
       48 
68 
     | 
    
         
             
                  @to_io = io.to_io
         
     | 
| 
      
 69 
     | 
    
         
            +
                  @io_buffer = IOBuffer.new
         
     | 
| 
       49 
70 
     | 
    
         
             
                  @proto_env = env
         
     | 
| 
       50 
     | 
    
         
            -
                   
     | 
| 
       51 
     | 
    
         
            -
                    @env = nil
         
     | 
| 
       52 
     | 
    
         
            -
                  else
         
     | 
| 
       53 
     | 
    
         
            -
                    @env = env.dup
         
     | 
| 
       54 
     | 
    
         
            -
                  end
         
     | 
| 
      
 71 
     | 
    
         
            +
                  @env = env&.dup
         
     | 
| 
       55 
72 
     | 
    
         | 
| 
       56 
73 
     | 
    
         
             
                  @parser = HttpParser.new
         
     | 
| 
       57 
74 
     | 
    
         
             
                  @parsed_bytes = 0
         
     | 
| 
       58 
75 
     | 
    
         
             
                  @read_header = true
         
     | 
| 
      
 76 
     | 
    
         
            +
                  @read_proxy = false
         
     | 
| 
       59 
77 
     | 
    
         
             
                  @ready = false
         
     | 
| 
       60 
78 
     | 
    
         | 
| 
       61 
79 
     | 
    
         
             
                  @body = nil
         
     | 
| 
         @@ -68,20 +86,29 @@ module Puma 
     | 
|
| 
       68 
86 
     | 
    
         
             
                  @requests_served = 0
         
     | 
| 
       69 
87 
     | 
    
         
             
                  @hijacked = false
         
     | 
| 
       70 
88 
     | 
    
         | 
| 
      
 89 
     | 
    
         
            +
                  @http_content_length_limit = nil
         
     | 
| 
      
 90 
     | 
    
         
            +
                  @http_content_length_limit_exceeded = false
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
       71 
92 
     | 
    
         
             
                  @peerip = nil
         
     | 
| 
      
 93 
     | 
    
         
            +
                  @peer_family = nil
         
     | 
| 
      
 94 
     | 
    
         
            +
                  @listener = nil
         
     | 
| 
       72 
95 
     | 
    
         
             
                  @remote_addr_header = nil
         
     | 
| 
      
 96 
     | 
    
         
            +
                  @expect_proxy_proto = false
         
     | 
| 
       73 
97 
     | 
    
         | 
| 
       74 
98 
     | 
    
         
             
                  @body_remain = 0
         
     | 
| 
       75 
99 
     | 
    
         | 
| 
       76 
100 
     | 
    
         
             
                  @in_last_chunk = false
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
                  # need unfrozen ASCII-8BIT, +'' is UTF-8
         
     | 
| 
      
 103 
     | 
    
         
            +
                  @read_buffer = String.new # rubocop: disable Performance/UnfreezeString
         
     | 
| 
       77 
104 
     | 
    
         
             
                end
         
     | 
| 
       78 
105 
     | 
    
         | 
| 
       79 
106 
     | 
    
         
             
                attr_reader :env, :to_io, :body, :io, :timeout_at, :ready, :hijacked,
         
     | 
| 
       80 
     | 
    
         
            -
                            :tempfile
         
     | 
| 
      
 107 
     | 
    
         
            +
                            :tempfile, :io_buffer, :http_content_length_limit_exceeded
         
     | 
| 
       81 
108 
     | 
    
         | 
| 
       82 
     | 
    
         
            -
                attr_writer :peerip
         
     | 
| 
      
 109 
     | 
    
         
            +
                attr_writer :peerip, :http_content_length_limit
         
     | 
| 
       83 
110 
     | 
    
         | 
| 
       84 
     | 
    
         
            -
                attr_accessor :remote_addr_header
         
     | 
| 
      
 111 
     | 
    
         
            +
                attr_accessor :remote_addr_header, :listener
         
     | 
| 
       85 
112 
     | 
    
         | 
| 
       86 
113 
     | 
    
         
             
                def_delegators :@io, :closed?
         
     | 
| 
       87 
114 
     | 
    
         | 
| 
         @@ -105,7 +132,7 @@ module Puma 
     | 
|
| 
       105 
132 
     | 
    
         | 
| 
       106 
133 
     | 
    
         
             
                # @!attribute [r] in_data_phase
         
     | 
| 
       107 
134 
     | 
    
         
             
                def in_data_phase
         
     | 
| 
       108 
     | 
    
         
            -
                   
     | 
| 
      
 135 
     | 
    
         
            +
                  !(@read_header || @read_proxy)
         
     | 
| 
       109 
136 
     | 
    
         
             
                end
         
     | 
| 
       110 
137 
     | 
    
         | 
| 
       111 
138 
     | 
    
         
             
                def set_timeout(val)
         
     | 
| 
         @@ -119,17 +146,22 @@ module Puma 
     | 
|
| 
       119 
146 
     | 
    
         | 
| 
       120 
147 
     | 
    
         
             
                def reset(fast_check=true)
         
     | 
| 
       121 
148 
     | 
    
         
             
                  @parser.reset
         
     | 
| 
      
 149 
     | 
    
         
            +
                  @io_buffer.reset
         
     | 
| 
       122 
150 
     | 
    
         
             
                  @read_header = true
         
     | 
| 
      
 151 
     | 
    
         
            +
                  @read_proxy = !!@expect_proxy_proto
         
     | 
| 
       123 
152 
     | 
    
         
             
                  @env = @proto_env.dup
         
     | 
| 
       124 
153 
     | 
    
         
             
                  @body = nil
         
     | 
| 
       125 
154 
     | 
    
         
             
                  @tempfile = nil
         
     | 
| 
       126 
155 
     | 
    
         
             
                  @parsed_bytes = 0
         
     | 
| 
       127 
156 
     | 
    
         
             
                  @ready = false
         
     | 
| 
       128 
157 
     | 
    
         
             
                  @body_remain = 0
         
     | 
| 
       129 
     | 
    
         
            -
                  @peerip = nil
         
     | 
| 
      
 158 
     | 
    
         
            +
                  @peerip = nil if @remote_addr_header
         
     | 
| 
       130 
159 
     | 
    
         
             
                  @in_last_chunk = false
         
     | 
| 
      
 160 
     | 
    
         
            +
                  @http_content_length_limit_exceeded = false
         
     | 
| 
       131 
161 
     | 
    
         | 
| 
       132 
162 
     | 
    
         
             
                  if @buffer
         
     | 
| 
      
 163 
     | 
    
         
            +
                    return false unless try_to_parse_proxy_protocol
         
     | 
| 
      
 164 
     | 
    
         
            +
             
     | 
| 
       133 
165 
     | 
    
         
             
                    @parsed_bytes = @parser.execute(@env, @buffer, @parsed_bytes)
         
     | 
| 
       134 
166 
     | 
    
         | 
| 
       135 
167 
     | 
    
         
             
                    if @parser.finished?
         
     | 
| 
         @@ -142,8 +174,7 @@ module Puma 
     | 
|
| 
       142 
174 
     | 
    
         
             
                    return false
         
     | 
| 
       143 
175 
     | 
    
         
             
                  else
         
     | 
| 
       144 
176 
     | 
    
         
             
                    begin
         
     | 
| 
       145 
     | 
    
         
            -
                      if fast_check &&
         
     | 
| 
       146 
     | 
    
         
            -
                          IO.select([@to_io], nil, nil, FAST_TRACK_KA_TIMEOUT)
         
     | 
| 
      
 177 
     | 
    
         
            +
                      if fast_check && @to_io.wait_readable(FAST_TRACK_KA_TIMEOUT)
         
     | 
| 
       147 
178 
     | 
    
         
             
                        return try_to_finish
         
     | 
| 
       148 
179 
     | 
    
         
             
                      end
         
     | 
| 
       149 
180 
     | 
    
         
             
                    rescue IOError
         
     | 
| 
         @@ -156,13 +187,48 @@ module Puma 
     | 
|
| 
       156 
187 
     | 
    
         
             
                def close
         
     | 
| 
       157 
188 
     | 
    
         
             
                  begin
         
     | 
| 
       158 
189 
     | 
    
         
             
                    @io.close
         
     | 
| 
       159 
     | 
    
         
            -
                  rescue IOError
         
     | 
| 
       160 
     | 
    
         
            -
                     
     | 
| 
      
 190 
     | 
    
         
            +
                  rescue IOError, Errno::EBADF
         
     | 
| 
      
 191 
     | 
    
         
            +
                    Puma::Util.purge_interrupt_queue
         
     | 
| 
       161 
192 
     | 
    
         
             
                  end
         
     | 
| 
       162 
193 
     | 
    
         
             
                end
         
     | 
| 
       163 
194 
     | 
    
         | 
| 
      
 195 
     | 
    
         
            +
                # If necessary, read the PROXY protocol from the buffer. Returns
         
     | 
| 
      
 196 
     | 
    
         
            +
                # false if more data is needed.
         
     | 
| 
      
 197 
     | 
    
         
            +
                def try_to_parse_proxy_protocol
         
     | 
| 
      
 198 
     | 
    
         
            +
                  if @read_proxy
         
     | 
| 
      
 199 
     | 
    
         
            +
                    if @expect_proxy_proto == :v1
         
     | 
| 
      
 200 
     | 
    
         
            +
                      if @buffer.include? "\r\n"
         
     | 
| 
      
 201 
     | 
    
         
            +
                        if md = PROXY_PROTOCOL_V1_REGEX.match(@buffer)
         
     | 
| 
      
 202 
     | 
    
         
            +
                          if md[1]
         
     | 
| 
      
 203 
     | 
    
         
            +
                            @peerip = md[1].split(" ")[0]
         
     | 
| 
      
 204 
     | 
    
         
            +
                          end
         
     | 
| 
      
 205 
     | 
    
         
            +
                          @buffer = md.post_match
         
     | 
| 
      
 206 
     | 
    
         
            +
                        end
         
     | 
| 
      
 207 
     | 
    
         
            +
                        # if the buffer has a \r\n but doesn't have a PROXY protocol
         
     | 
| 
      
 208 
     | 
    
         
            +
                        # request, this is just HTTP from a non-PROXY client; move on
         
     | 
| 
      
 209 
     | 
    
         
            +
                        @read_proxy = false
         
     | 
| 
      
 210 
     | 
    
         
            +
                        return @buffer.size > 0
         
     | 
| 
      
 211 
     | 
    
         
            +
                      else
         
     | 
| 
      
 212 
     | 
    
         
            +
                        return false
         
     | 
| 
      
 213 
     | 
    
         
            +
                      end
         
     | 
| 
      
 214 
     | 
    
         
            +
                    end
         
     | 
| 
      
 215 
     | 
    
         
            +
                  end
         
     | 
| 
      
 216 
     | 
    
         
            +
                  true
         
     | 
| 
      
 217 
     | 
    
         
            +
                end
         
     | 
| 
      
 218 
     | 
    
         
            +
             
     | 
| 
       164 
219 
     | 
    
         
             
                def try_to_finish
         
     | 
| 
       165 
     | 
    
         
            -
                   
     | 
| 
      
 220 
     | 
    
         
            +
                  if env[CONTENT_LENGTH] && above_http_content_limit(env[CONTENT_LENGTH].to_i)
         
     | 
| 
      
 221 
     | 
    
         
            +
                    @http_content_length_limit_exceeded = true
         
     | 
| 
      
 222 
     | 
    
         
            +
                  end
         
     | 
| 
      
 223 
     | 
    
         
            +
             
     | 
| 
      
 224 
     | 
    
         
            +
                  if @http_content_length_limit_exceeded
         
     | 
| 
      
 225 
     | 
    
         
            +
                    @buffer = nil
         
     | 
| 
      
 226 
     | 
    
         
            +
                    @body = EmptyBody
         
     | 
| 
      
 227 
     | 
    
         
            +
                    set_ready
         
     | 
| 
      
 228 
     | 
    
         
            +
                    return true
         
     | 
| 
      
 229 
     | 
    
         
            +
                  end
         
     | 
| 
      
 230 
     | 
    
         
            +
             
     | 
| 
      
 231 
     | 
    
         
            +
                  return read_body if in_data_phase
         
     | 
| 
       166 
232 
     | 
    
         | 
| 
       167 
233 
     | 
    
         
             
                  begin
         
     | 
| 
       168 
234 
     | 
    
         
             
                    data = @io.read_nonblock(CHUNK_SIZE)
         
     | 
| 
         @@ -187,8 +253,14 @@ module Puma 
     | 
|
| 
       187 
253 
     | 
    
         
             
                    @buffer = data
         
     | 
| 
       188 
254 
     | 
    
         
             
                  end
         
     | 
| 
       189 
255 
     | 
    
         | 
| 
      
 256 
     | 
    
         
            +
                  return false unless try_to_parse_proxy_protocol
         
     | 
| 
      
 257 
     | 
    
         
            +
             
     | 
| 
       190 
258 
     | 
    
         
             
                  @parsed_bytes = @parser.execute(@env, @buffer, @parsed_bytes)
         
     | 
| 
       191 
259 
     | 
    
         | 
| 
      
 260 
     | 
    
         
            +
                  if @parser.finished? && above_http_content_limit(@parser.body.bytesize)
         
     | 
| 
      
 261 
     | 
    
         
            +
                    @http_content_length_limit_exceeded = true
         
     | 
| 
      
 262 
     | 
    
         
            +
                  end
         
     | 
| 
      
 263 
     | 
    
         
            +
             
     | 
| 
       192 
264 
     | 
    
         
             
                  if @parser.finished?
         
     | 
| 
       193 
265 
     | 
    
         
             
                    return setup_body
         
     | 
| 
       194 
266 
     | 
    
         
             
                  elsif @parsed_bytes >= MAX_HEADER
         
     | 
| 
         @@ -201,13 +273,13 @@ module Puma 
     | 
|
| 
       201 
273 
     | 
    
         | 
| 
       202 
274 
     | 
    
         
             
                def eagerly_finish
         
     | 
| 
       203 
275 
     | 
    
         
             
                  return true if @ready
         
     | 
| 
       204 
     | 
    
         
            -
                  return false unless  
     | 
| 
      
 276 
     | 
    
         
            +
                  return false unless @to_io.wait_readable(0)
         
     | 
| 
       205 
277 
     | 
    
         
             
                  try_to_finish
         
     | 
| 
       206 
278 
     | 
    
         
             
                end
         
     | 
| 
       207 
279 
     | 
    
         | 
| 
       208 
280 
     | 
    
         
             
                def finish(timeout)
         
     | 
| 
       209 
281 
     | 
    
         
             
                  return if @ready
         
     | 
| 
       210 
     | 
    
         
            -
                   
     | 
| 
      
 282 
     | 
    
         
            +
                  @to_io.wait_readable(timeout) || timeout! until try_to_finish
         
     | 
| 
       211 
283 
     | 
    
         
             
                end
         
     | 
| 
       212 
284 
     | 
    
         | 
| 
       213 
285 
     | 
    
         
             
                def timeout!
         
     | 
| 
         @@ -226,7 +298,7 @@ module Puma 
     | 
|
| 
       226 
298 
     | 
    
         
             
                  return @peerip if @peerip
         
     | 
| 
       227 
299 
     | 
    
         | 
| 
       228 
300 
     | 
    
         
             
                  if @remote_addr_header
         
     | 
| 
       229 
     | 
    
         
            -
                    hdr = (@env[@remote_addr_header] ||  
     | 
| 
      
 301 
     | 
    
         
            +
                    hdr = (@env[@remote_addr_header] || @io.peeraddr.last).split(/[\s,]/).first
         
     | 
| 
       230 
302 
     | 
    
         
             
                    @peerip = hdr
         
     | 
| 
       231 
303 
     | 
    
         
             
                    return hdr
         
     | 
| 
       232 
304 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -234,6 +306,16 @@ module Puma 
     | 
|
| 
       234 
306 
     | 
    
         
             
                  @peerip ||= @io.peeraddr.last
         
     | 
| 
       235 
307 
     | 
    
         
             
                end
         
     | 
| 
       236 
308 
     | 
    
         | 
| 
      
 309 
     | 
    
         
            +
                def peer_family
         
     | 
| 
      
 310 
     | 
    
         
            +
                  return @peer_family if @peer_family
         
     | 
| 
      
 311 
     | 
    
         
            +
             
     | 
| 
      
 312 
     | 
    
         
            +
                  @peer_family ||= begin
         
     | 
| 
      
 313 
     | 
    
         
            +
                                     @io.local_address.afamily
         
     | 
| 
      
 314 
     | 
    
         
            +
                                   rescue
         
     | 
| 
      
 315 
     | 
    
         
            +
                                     Socket::AF_INET
         
     | 
| 
      
 316 
     | 
    
         
            +
                                   end
         
     | 
| 
      
 317 
     | 
    
         
            +
                end
         
     | 
| 
      
 318 
     | 
    
         
            +
             
     | 
| 
       237 
319 
     | 
    
         
             
                # Returns true if the persistent connection can be closed immediately
         
     | 
| 
       238 
320 
     | 
    
         
             
                # without waiting for the configured idle/shutdown timeout.
         
     | 
| 
       239 
321 
     | 
    
         
             
                # @version 5.0.0
         
     | 
| 
         @@ -243,10 +325,21 @@ module Puma 
     | 
|
| 
       243 
325 
     | 
    
         
             
                  @parsed_bytes == 0
         
     | 
| 
       244 
326 
     | 
    
         
             
                end
         
     | 
| 
       245 
327 
     | 
    
         | 
| 
      
 328 
     | 
    
         
            +
                def expect_proxy_proto=(val)
         
     | 
| 
      
 329 
     | 
    
         
            +
                  if val
         
     | 
| 
      
 330 
     | 
    
         
            +
                    if @read_header
         
     | 
| 
      
 331 
     | 
    
         
            +
                      @read_proxy = true
         
     | 
| 
      
 332 
     | 
    
         
            +
                    end
         
     | 
| 
      
 333 
     | 
    
         
            +
                  else
         
     | 
| 
      
 334 
     | 
    
         
            +
                    @read_proxy = false
         
     | 
| 
      
 335 
     | 
    
         
            +
                  end
         
     | 
| 
      
 336 
     | 
    
         
            +
                  @expect_proxy_proto = val
         
     | 
| 
      
 337 
     | 
    
         
            +
                end
         
     | 
| 
      
 338 
     | 
    
         
            +
             
     | 
| 
       246 
339 
     | 
    
         
             
                private
         
     | 
| 
       247 
340 
     | 
    
         | 
| 
       248 
341 
     | 
    
         
             
                def setup_body
         
     | 
| 
       249 
     | 
    
         
            -
                  @body_read_start = Process.clock_gettime(Process::CLOCK_MONOTONIC, : 
     | 
| 
      
 342 
     | 
    
         
            +
                  @body_read_start = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)
         
     | 
| 
       250 
343 
     | 
    
         | 
| 
       251 
344 
     | 
    
         
             
                  if @env[HTTP_EXPECT] == CONTINUE
         
     | 
| 
       252 
345 
     | 
    
         
             
                    # TODO allow a hook here to check the headers before
         
     | 
| 
         @@ -260,16 +353,27 @@ module Puma 
     | 
|
| 
       260 
353 
     | 
    
         
             
                  body = @parser.body
         
     | 
| 
       261 
354 
     | 
    
         | 
| 
       262 
355 
     | 
    
         
             
                  te = @env[TRANSFER_ENCODING2]
         
     | 
| 
       263 
     | 
    
         
            -
             
     | 
| 
       264 
356 
     | 
    
         
             
                  if te
         
     | 
| 
       265 
     | 
    
         
            -
                     
     | 
| 
       266 
     | 
    
         
            -
             
     | 
| 
       267 
     | 
    
         
            -
             
     | 
| 
       268 
     | 
    
         
            -
             
     | 
| 
       269 
     | 
    
         
            -
             
     | 
| 
      
 357 
     | 
    
         
            +
                    te_lwr = te.downcase
         
     | 
| 
      
 358 
     | 
    
         
            +
                    if te.include? ','
         
     | 
| 
      
 359 
     | 
    
         
            +
                      te_ary = te_lwr.split ','
         
     | 
| 
      
 360 
     | 
    
         
            +
                      te_count = te_ary.count CHUNKED
         
     | 
| 
      
 361 
     | 
    
         
            +
                      te_valid = te_ary[0..-2].all? { |e| ALLOWED_TRANSFER_ENCODING.include? e }
         
     | 
| 
      
 362 
     | 
    
         
            +
                      if te_ary.last == CHUNKED && te_count == 1 && te_valid
         
     | 
| 
      
 363 
     | 
    
         
            +
                        @env.delete TRANSFER_ENCODING2
         
     | 
| 
      
 364 
     | 
    
         
            +
                        return setup_chunked_body body
         
     | 
| 
      
 365 
     | 
    
         
            +
                      elsif te_count >= 1
         
     | 
| 
      
 366 
     | 
    
         
            +
                        raise HttpParserError   , "#{TE_ERR_MSG}, multiple chunked: '#{te}'"
         
     | 
| 
      
 367 
     | 
    
         
            +
                      elsif !te_valid
         
     | 
| 
      
 368 
     | 
    
         
            +
                        raise HttpParserError501, "#{TE_ERR_MSG}, unknown value: '#{te}'"
         
     | 
| 
       270 
369 
     | 
    
         
             
                      end
         
     | 
| 
       271 
     | 
    
         
            -
                    elsif  
     | 
| 
       272 
     | 
    
         
            -
                       
     | 
| 
      
 370 
     | 
    
         
            +
                    elsif te_lwr == CHUNKED
         
     | 
| 
      
 371 
     | 
    
         
            +
                      @env.delete TRANSFER_ENCODING2
         
     | 
| 
      
 372 
     | 
    
         
            +
                      return setup_chunked_body body
         
     | 
| 
      
 373 
     | 
    
         
            +
                    elsif ALLOWED_TRANSFER_ENCODING.include? te_lwr
         
     | 
| 
      
 374 
     | 
    
         
            +
                      raise HttpParserError     , "#{TE_ERR_MSG}, single value must be chunked: '#{te}'"
         
     | 
| 
      
 375 
     | 
    
         
            +
                    else
         
     | 
| 
      
 376 
     | 
    
         
            +
                      raise HttpParserError501  , "#{TE_ERR_MSG}, unknown value: '#{te}'"
         
     | 
| 
       273 
377 
     | 
    
         
             
                    end
         
     | 
| 
       274 
378 
     | 
    
         
             
                  end
         
     | 
| 
       275 
379 
     | 
    
         | 
| 
         @@ -277,7 +381,12 @@ module Puma 
     | 
|
| 
       277 
381 
     | 
    
         | 
| 
       278 
382 
     | 
    
         
             
                  cl = @env[CONTENT_LENGTH]
         
     | 
| 
       279 
383 
     | 
    
         | 
| 
       280 
     | 
    
         
            -
                   
     | 
| 
      
 384 
     | 
    
         
            +
                  if cl
         
     | 
| 
      
 385 
     | 
    
         
            +
                    # cannot contain characters that are not \d
         
     | 
| 
      
 386 
     | 
    
         
            +
                    if CONTENT_LENGTH_VALUE_INVALID.match? cl
         
     | 
| 
      
 387 
     | 
    
         
            +
                      raise HttpParserError, "Invalid Content-Length: #{cl.inspect}"
         
     | 
| 
      
 388 
     | 
    
         
            +
                    end
         
     | 
| 
      
 389 
     | 
    
         
            +
                  else
         
     | 
| 
       281 
390 
     | 
    
         
             
                    @buffer = body.empty? ? nil : body
         
     | 
| 
       282 
391 
     | 
    
         
             
                    @body = EmptyBody
         
     | 
| 
       283 
392 
     | 
    
         
             
                    set_ready
         
     | 
| 
         @@ -295,6 +404,7 @@ module Puma 
     | 
|
| 
       295 
404 
     | 
    
         | 
| 
       296 
405 
     | 
    
         
             
                  if remain > MAX_BODY
         
     | 
| 
       297 
406 
     | 
    
         
             
                    @body = Tempfile.new(Const::PUMA_TMP_BASE)
         
     | 
| 
      
 407 
     | 
    
         
            +
                    @body.unlink
         
     | 
| 
       298 
408 
     | 
    
         
             
                    @body.binmode
         
     | 
| 
       299 
409 
     | 
    
         
             
                    @tempfile = @body
         
     | 
| 
       300 
410 
     | 
    
         
             
                  else
         
     | 
| 
         @@ -307,7 +417,7 @@ module Puma 
     | 
|
| 
       307 
417 
     | 
    
         | 
| 
       308 
418 
     | 
    
         
             
                  @body_remain = remain
         
     | 
| 
       309 
419 
     | 
    
         | 
| 
       310 
     | 
    
         
            -
                   
     | 
| 
      
 420 
     | 
    
         
            +
                  false
         
     | 
| 
       311 
421 
     | 
    
         
             
                end
         
     | 
| 
       312 
422 
     | 
    
         | 
| 
       313 
423 
     | 
    
         
             
                def read_body
         
     | 
| 
         @@ -326,7 +436,7 @@ module Puma 
     | 
|
| 
       326 
436 
     | 
    
         
             
                  end
         
     | 
| 
       327 
437 
     | 
    
         | 
| 
       328 
438 
     | 
    
         
             
                  begin
         
     | 
| 
       329 
     | 
    
         
            -
                    chunk = @io.read_nonblock(want)
         
     | 
| 
      
 439 
     | 
    
         
            +
                    chunk = @io.read_nonblock(want, @read_buffer)
         
     | 
| 
       330 
440 
     | 
    
         
             
                  rescue IO::WaitReadable
         
     | 
| 
       331 
441 
     | 
    
         
             
                    return false
         
     | 
| 
       332 
442 
     | 
    
         
             
                  rescue SystemCallError, IOError
         
     | 
| 
         @@ -358,7 +468,7 @@ module Puma 
     | 
|
| 
       358 
468 
     | 
    
         
             
                def read_chunked_body
         
     | 
| 
       359 
469 
     | 
    
         
             
                  while true
         
     | 
| 
       360 
470 
     | 
    
         
             
                    begin
         
     | 
| 
       361 
     | 
    
         
            -
                      chunk = @io.read_nonblock(4096)
         
     | 
| 
      
 471 
     | 
    
         
            +
                      chunk = @io.read_nonblock(4096, @read_buffer)
         
     | 
| 
       362 
472 
     | 
    
         
             
                    rescue IO::WaitReadable
         
     | 
| 
       363 
473 
     | 
    
         
             
                      return false
         
     | 
| 
       364 
474 
     | 
    
         
             
                    rescue SystemCallError, IOError
         
     | 
| 
         @@ -386,6 +496,7 @@ module Puma 
     | 
|
| 
       386 
496 
     | 
    
         
             
                  @prev_chunk = ""
         
     | 
| 
       387 
497 
     | 
    
         | 
| 
       388 
498 
     | 
    
         
             
                  @body = Tempfile.new(Const::PUMA_TMP_BASE)
         
     | 
| 
      
 499 
     | 
    
         
            +
                  @body.unlink
         
     | 
| 
       389 
500 
     | 
    
         
             
                  @body.binmode
         
     | 
| 
       390 
501 
     | 
    
         
             
                  @tempfile = @body
         
     | 
| 
       391 
502 
     | 
    
         
             
                  @chunked_content_length = 0
         
     | 
| 
         @@ -434,7 +545,13 @@ module Puma 
     | 
|
| 
       434 
545 
     | 
    
         
             
                  while !io.eof?
         
     | 
| 
       435 
546 
     | 
    
         
             
                    line = io.gets
         
     | 
| 
       436 
547 
     | 
    
         
             
                    if line.end_with?("\r\n")
         
     | 
| 
       437 
     | 
    
         
            -
                       
     | 
| 
      
 548 
     | 
    
         
            +
                      # Puma doesn't process chunk extensions, but should parse if they're
         
     | 
| 
      
 549 
     | 
    
         
            +
                      # present, which is the reason for the semicolon regex
         
     | 
| 
      
 550 
     | 
    
         
            +
                      chunk_hex = line.strip[/\A[^;]+/]
         
     | 
| 
      
 551 
     | 
    
         
            +
                      if CHUNK_SIZE_INVALID.match? chunk_hex
         
     | 
| 
      
 552 
     | 
    
         
            +
                        raise HttpParserError, "Invalid chunk size: '#{chunk_hex}'"
         
     | 
| 
      
 553 
     | 
    
         
            +
                      end
         
     | 
| 
      
 554 
     | 
    
         
            +
                      len = chunk_hex.to_i(16)
         
     | 
| 
       438 
555 
     | 
    
         
             
                      if len == 0
         
     | 
| 
       439 
556 
     | 
    
         
             
                        @in_last_chunk = true
         
     | 
| 
       440 
557 
     | 
    
         
             
                        @body.rewind
         
     | 
| 
         @@ -465,7 +582,12 @@ module Puma 
     | 
|
| 
       465 
582 
     | 
    
         | 
| 
       466 
583 
     | 
    
         
             
                      case
         
     | 
| 
       467 
584 
     | 
    
         
             
                      when got == len
         
     | 
| 
       468 
     | 
    
         
            -
                         
     | 
| 
      
 585 
     | 
    
         
            +
                        # proper chunked segment must end with "\r\n"
         
     | 
| 
      
 586 
     | 
    
         
            +
                        if part.end_with? CHUNK_VALID_ENDING
         
     | 
| 
      
 587 
     | 
    
         
            +
                          write_chunk(part[0..-3]) # to skip the ending \r\n
         
     | 
| 
      
 588 
     | 
    
         
            +
                        else
         
     | 
| 
      
 589 
     | 
    
         
            +
                          raise HttpParserError, "Chunk size mismatch"
         
     | 
| 
      
 590 
     | 
    
         
            +
                        end
         
     | 
| 
       469 
591 
     | 
    
         
             
                      when got <= len - 2
         
     | 
| 
       470 
592 
     | 
    
         
             
                        write_chunk(part)
         
     | 
| 
       471 
593 
     | 
    
         
             
                        @partial_part_left = len - part.size
         
     | 
| 
         @@ -489,10 +611,14 @@ module Puma 
     | 
|
| 
       489 
611 
     | 
    
         | 
| 
       490 
612 
     | 
    
         
             
                def set_ready
         
     | 
| 
       491 
613 
     | 
    
         
             
                  if @body_read_start
         
     | 
| 
       492 
     | 
    
         
            -
                    @env['puma.request_body_wait'] = Process.clock_gettime(Process::CLOCK_MONOTONIC, : 
     | 
| 
      
 614 
     | 
    
         
            +
                    @env['puma.request_body_wait'] = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond) - @body_read_start
         
     | 
| 
       493 
615 
     | 
    
         
             
                  end
         
     | 
| 
       494 
616 
     | 
    
         
             
                  @requests_served += 1
         
     | 
| 
       495 
617 
     | 
    
         
             
                  @ready = true
         
     | 
| 
       496 
618 
     | 
    
         
             
                end
         
     | 
| 
      
 619 
     | 
    
         
            +
             
     | 
| 
      
 620 
     | 
    
         
            +
                def above_http_content_limit(value)
         
     | 
| 
      
 621 
     | 
    
         
            +
                  @http_content_length_limit&.< value
         
     | 
| 
      
 622 
     | 
    
         
            +
                end
         
     | 
| 
       497 
623 
     | 
    
         
             
              end
         
     | 
| 
       498 
624 
     | 
    
         
             
            end
         
     | 
    
        data/lib/puma/cluster/worker.rb
    CHANGED
    
    | 
         @@ -2,27 +2,29 @@ 
     | 
|
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            module Puma
         
     | 
| 
       4 
4 
     | 
    
         
             
              class Cluster < Puma::Runner
         
     | 
| 
      
 5 
     | 
    
         
            +
                #—————————————————————— DO NOT USE — this class is for internal use only ———
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
       5 
8 
     | 
    
         
             
                # This class is instantiated by the `Puma::Cluster` and represents a single
         
     | 
| 
       6 
9 
     | 
    
         
             
                # worker process.
         
     | 
| 
       7 
10 
     | 
    
         
             
                #
         
     | 
| 
       8 
11 
     | 
    
         
             
                # At the core of this class is running an instance of `Puma::Server` which
         
     | 
| 
       9 
12 
     | 
    
         
             
                # gets created via the `start_server` method from the `Puma::Runner` class
         
     | 
| 
       10 
13 
     | 
    
         
             
                # that this inherits from.
         
     | 
| 
       11 
     | 
    
         
            -
                class Worker < Puma::Runner
         
     | 
| 
      
 14 
     | 
    
         
            +
                class Worker < Puma::Runner # :nodoc:
         
     | 
| 
       12 
15 
     | 
    
         
             
                  attr_reader :index, :master
         
     | 
| 
       13 
16 
     | 
    
         | 
| 
       14 
17 
     | 
    
         
             
                  def initialize(index:, master:, launcher:, pipes:, server: nil)
         
     | 
| 
       15 
     | 
    
         
            -
                    super 
     | 
| 
      
 18 
     | 
    
         
            +
                    super(launcher)
         
     | 
| 
       16 
19 
     | 
    
         | 
| 
       17 
20 
     | 
    
         
             
                    @index = index
         
     | 
| 
       18 
21 
     | 
    
         
             
                    @master = master
         
     | 
| 
       19 
     | 
    
         
            -
                    @launcher = launcher
         
     | 
| 
       20 
     | 
    
         
            -
                    @options = launcher.options
         
     | 
| 
       21 
22 
     | 
    
         
             
                    @check_pipe = pipes[:check_pipe]
         
     | 
| 
       22 
23 
     | 
    
         
             
                    @worker_write = pipes[:worker_write]
         
     | 
| 
       23 
24 
     | 
    
         
             
                    @fork_pipe = pipes[:fork_pipe]
         
     | 
| 
       24 
25 
     | 
    
         
             
                    @wakeup = pipes[:wakeup]
         
     | 
| 
       25 
26 
     | 
    
         
             
                    @server = server
         
     | 
| 
      
 27 
     | 
    
         
            +
                    @hook_data = {}
         
     | 
| 
       26 
28 
     | 
    
         
             
                  end
         
     | 
| 
       27 
29 
     | 
    
         | 
| 
       28 
30 
     | 
    
         
             
                  def run
         
     | 
| 
         @@ -34,8 +36,8 @@ module Puma 
     | 
|
| 
       34 
36 
     | 
    
         
             
                    Signal.trap "SIGCHLD", "DEFAULT"
         
     | 
| 
       35 
37 
     | 
    
         | 
| 
       36 
38 
     | 
    
         
             
                    Thread.new do
         
     | 
| 
       37 
     | 
    
         
            -
                      Puma.set_thread_name " 
     | 
| 
       38 
     | 
    
         
            -
                       
     | 
| 
      
 39 
     | 
    
         
            +
                      Puma.set_thread_name "wrkr check"
         
     | 
| 
      
 40 
     | 
    
         
            +
                      @check_pipe.wait_readable
         
     | 
| 
       39 
41 
     | 
    
         
             
                      log "! Detected parent died, dying"
         
     | 
| 
       40 
42 
     | 
    
         
             
                      exit! 1
         
     | 
| 
       41 
43 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -52,9 +54,17 @@ module Puma 
     | 
|
| 
       52 
54 
     | 
    
         | 
| 
       53 
55 
     | 
    
         
             
                    # Invoke any worker boot hooks so they can get
         
     | 
| 
       54 
56 
     | 
    
         
             
                    # things in shape before booting the app.
         
     | 
| 
       55 
     | 
    
         
            -
                    @ 
     | 
| 
      
 57 
     | 
    
         
            +
                    @config.run_hooks(:before_worker_boot, index, @log_writer, @hook_data)
         
     | 
| 
       56 
58 
     | 
    
         | 
| 
      
 59 
     | 
    
         
            +
                    begin
         
     | 
| 
       57 
60 
     | 
    
         
             
                    server = @server ||= start_server
         
     | 
| 
      
 61 
     | 
    
         
            +
                    rescue Exception => e
         
     | 
| 
      
 62 
     | 
    
         
            +
                      log "! Unable to start worker"
         
     | 
| 
      
 63 
     | 
    
         
            +
                      log e
         
     | 
| 
      
 64 
     | 
    
         
            +
                      log e.backtrace.join("\n    ")
         
     | 
| 
      
 65 
     | 
    
         
            +
                      exit 1
         
     | 
| 
      
 66 
     | 
    
         
            +
                    end
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
       58 
68 
     | 
    
         
             
                    restart_server = Queue.new << true << false
         
     | 
| 
       59 
69 
     | 
    
         | 
| 
       60 
70 
     | 
    
         
             
                    fork_worker = @options[:fork_worker] && index == 0
         
     | 
| 
         @@ -69,15 +79,14 @@ module Puma 
     | 
|
| 
       69 
79 
     | 
    
         
             
                      end
         
     | 
| 
       70 
80 
     | 
    
         | 
| 
       71 
81 
     | 
    
         
             
                      Thread.new do
         
     | 
| 
       72 
     | 
    
         
            -
                        Puma.set_thread_name " 
     | 
| 
      
 82 
     | 
    
         
            +
                        Puma.set_thread_name "wrkr fork"
         
     | 
| 
       73 
83 
     | 
    
         
             
                        while (idx = @fork_pipe.gets)
         
     | 
| 
       74 
84 
     | 
    
         
             
                          idx = idx.to_i
         
     | 
| 
       75 
85 
     | 
    
         
             
                          if idx == -1 # stop server
         
     | 
| 
       76 
86 
     | 
    
         
             
                            if restart_server.length > 0
         
     | 
| 
       77 
87 
     | 
    
         
             
                              restart_server.clear
         
     | 
| 
       78 
88 
     | 
    
         
             
                              server.begin_restart(true)
         
     | 
| 
       79 
     | 
    
         
            -
                              @ 
     | 
| 
       80 
     | 
    
         
            -
                              Puma::Util.nakayoshi_gc @events if @options[:nakayoshi_fork]
         
     | 
| 
      
 89 
     | 
    
         
            +
                              @config.run_hooks(:before_refork, nil, @log_writer, @hook_data)
         
     | 
| 
       81 
90 
     | 
    
         
             
                            end
         
     | 
| 
       82 
91 
     | 
    
         
             
                          elsif idx == 0 # restart server
         
     | 
| 
       83 
92 
     | 
    
         
             
                            restart_server << true << false
         
     | 
| 
         @@ -99,15 +108,20 @@ module Puma 
     | 
|
| 
       99 
108 
     | 
    
         
             
                    begin
         
     | 
| 
       100 
109 
     | 
    
         
             
                      @worker_write << "b#{Process.pid}:#{index}\n"
         
     | 
| 
       101 
110 
     | 
    
         
             
                    rescue SystemCallError, IOError
         
     | 
| 
       102 
     | 
    
         
            -
                       
     | 
| 
      
 111 
     | 
    
         
            +
                      Puma::Util.purge_interrupt_queue
         
     | 
| 
       103 
112 
     | 
    
         
             
                      STDERR.puts "Master seems to have exited, exiting."
         
     | 
| 
       104 
113 
     | 
    
         
             
                      return
         
     | 
| 
       105 
114 
     | 
    
         
             
                    end
         
     | 
| 
       106 
115 
     | 
    
         | 
| 
       107 
116 
     | 
    
         
             
                    while restart_server.pop
         
     | 
| 
       108 
117 
     | 
    
         
             
                      server_thread = server.run
         
     | 
| 
      
 118 
     | 
    
         
            +
             
     | 
| 
      
 119 
     | 
    
         
            +
                      if @log_writer.debug? && index == 0
         
     | 
| 
      
 120 
     | 
    
         
            +
                        debug_loaded_extensions "Loaded Extensions - worker 0:"
         
     | 
| 
      
 121 
     | 
    
         
            +
                      end
         
     | 
| 
      
 122 
     | 
    
         
            +
             
     | 
| 
       109 
123 
     | 
    
         
             
                      stat_thread ||= Thread.new(@worker_write) do |io|
         
     | 
| 
       110 
     | 
    
         
            -
                        Puma.set_thread_name "stat  
     | 
| 
      
 124 
     | 
    
         
            +
                        Puma.set_thread_name "stat pld"
         
     | 
| 
       111 
125 
     | 
    
         
             
                        base_payload = "p#{Process.pid}"
         
     | 
| 
       112 
126 
     | 
    
         | 
| 
       113 
127 
     | 
    
         
             
                        while true
         
     | 
| 
         @@ -120,10 +134,10 @@ module Puma 
     | 
|
| 
       120 
134 
     | 
    
         
             
                            payload = %Q!#{base_payload}{ "backlog":#{b}, "running":#{r}, "pool_capacity":#{t}, "max_threads": #{m}, "requests_count": #{rc} }\n!
         
     | 
| 
       121 
135 
     | 
    
         
             
                            io << payload
         
     | 
| 
       122 
136 
     | 
    
         
             
                          rescue IOError
         
     | 
| 
       123 
     | 
    
         
            -
                             
     | 
| 
      
 137 
     | 
    
         
            +
                            Puma::Util.purge_interrupt_queue
         
     | 
| 
       124 
138 
     | 
    
         
             
                            break
         
     | 
| 
       125 
139 
     | 
    
         
             
                          end
         
     | 
| 
       126 
     | 
    
         
            -
                          sleep  
     | 
| 
      
 140 
     | 
    
         
            +
                          sleep @options[:worker_check_interval]
         
     | 
| 
       127 
141 
     | 
    
         
             
                        end
         
     | 
| 
       128 
142 
     | 
    
         
             
                      end
         
     | 
| 
       129 
143 
     | 
    
         
             
                      server_thread.join
         
     | 
| 
         @@ -131,7 +145,7 @@ module Puma 
     | 
|
| 
       131 
145 
     | 
    
         | 
| 
       132 
146 
     | 
    
         
             
                    # Invoke any worker shutdown hooks so they can prevent the worker
         
     | 
| 
       133 
147 
     | 
    
         
             
                    # exiting until any background operations are completed
         
     | 
| 
       134 
     | 
    
         
            -
                    @ 
     | 
| 
      
 148 
     | 
    
         
            +
                    @config.run_hooks(:before_worker_shutdown, index, @log_writer, @hook_data)
         
     | 
| 
       135 
149 
     | 
    
         
             
                  ensure
         
     | 
| 
       136 
150 
     | 
    
         
             
                    @worker_write << "t#{Process.pid}\n" rescue nil
         
     | 
| 
       137 
151 
     | 
    
         
             
                    @worker_write.close
         
     | 
| 
         @@ -140,7 +154,7 @@ module Puma 
     | 
|
| 
       140 
154 
     | 
    
         
             
                  private
         
     | 
| 
       141 
155 
     | 
    
         | 
| 
       142 
156 
     | 
    
         
             
                  def spawn_worker(idx)
         
     | 
| 
       143 
     | 
    
         
            -
                    @ 
     | 
| 
      
 157 
     | 
    
         
            +
                    @config.run_hooks(:before_worker_fork, idx, @log_writer, @hook_data)
         
     | 
| 
       144 
158 
     | 
    
         | 
| 
       145 
159 
     | 
    
         
             
                    pid = fork do
         
     | 
| 
       146 
160 
     | 
    
         
             
                      new_worker = Worker.new index: idx,
         
     | 
| 
         @@ -158,19 +172,9 @@ module Puma 
     | 
|
| 
       158 
172 
     | 
    
         
             
                      exit! 1
         
     | 
| 
       159 
173 
     | 
    
         
             
                    end
         
     | 
| 
       160 
174 
     | 
    
         | 
| 
       161 
     | 
    
         
            -
                    @ 
     | 
| 
      
 175 
     | 
    
         
            +
                    @config.run_hooks(:after_worker_fork, idx, @log_writer, @hook_data)
         
     | 
| 
       162 
176 
     | 
    
         
             
                    pid
         
     | 
| 
       163 
177 
     | 
    
         
             
                  end
         
     | 
| 
       164 
     | 
    
         
            -
             
     | 
| 
       165 
     | 
    
         
            -
                  def wakeup!
         
     | 
| 
       166 
     | 
    
         
            -
                    return unless @wakeup
         
     | 
| 
       167 
     | 
    
         
            -
             
     | 
| 
       168 
     | 
    
         
            -
                    begin
         
     | 
| 
       169 
     | 
    
         
            -
                      @wakeup.write "!" unless @wakeup.closed?
         
     | 
| 
       170 
     | 
    
         
            -
                    rescue SystemCallError, IOError
         
     | 
| 
       171 
     | 
    
         
            -
                      Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
         
     | 
| 
       172 
     | 
    
         
            -
                    end
         
     | 
| 
       173 
     | 
    
         
            -
                  end
         
     | 
| 
       174 
178 
     | 
    
         
             
                end
         
     | 
| 
       175 
179 
     | 
    
         
             
              end
         
     | 
| 
       176 
180 
     | 
    
         
             
            end
         
     | 
| 
         @@ -2,12 +2,15 @@ 
     | 
|
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            module Puma
         
     | 
| 
       4 
4 
     | 
    
         
             
              class Cluster < Runner
         
     | 
| 
      
 5 
     | 
    
         
            +
                #—————————————————————— DO NOT USE — this class is for internal use only ———
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
       5 
8 
     | 
    
         
             
                # This class represents a worker process from the perspective of the puma
         
     | 
| 
       6 
9 
     | 
    
         
             
                # master process. It contains information about the process and its health
         
     | 
| 
       7 
10 
     | 
    
         
             
                # and it exposes methods to control the process via IPC. It does not
         
     | 
| 
       8 
11 
     | 
    
         
             
                # include the actual logic executed by the worker process itself. For that,
         
     | 
| 
       9 
12 
     | 
    
         
             
                # see Puma::Cluster::Worker.
         
     | 
| 
       10 
     | 
    
         
            -
                class WorkerHandle
         
     | 
| 
      
 13 
     | 
    
         
            +
                class WorkerHandle # :nodoc:
         
     | 
| 
       11 
14 
     | 
    
         
             
                  def initialize(idx, pid, phase, options)
         
     | 
| 
       12 
15 
     | 
    
         
             
                    @index = idx
         
     | 
| 
       13 
16 
     | 
    
         
             
                    @pid = pid
         
     | 
| 
         @@ -31,11 +34,19 @@ module Puma 
     | 
|
| 
       31 
34 
     | 
    
         
             
                    @stage == :booted
         
     | 
| 
       32 
35 
     | 
    
         
             
                  end
         
     | 
| 
       33 
36 
     | 
    
         | 
| 
      
 37 
     | 
    
         
            +
                  def uptime
         
     | 
| 
      
 38 
     | 
    
         
            +
                    Time.now - started_at
         
     | 
| 
      
 39 
     | 
    
         
            +
                  end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
       34 
41 
     | 
    
         
             
                  def boot!
         
     | 
| 
       35 
42 
     | 
    
         
             
                    @last_checkin = Time.now
         
     | 
| 
       36 
43 
     | 
    
         
             
                    @stage = :booted
         
     | 
| 
       37 
44 
     | 
    
         
             
                  end
         
     | 
| 
       38 
45 
     | 
    
         | 
| 
      
 46 
     | 
    
         
            +
                  def term!
         
     | 
| 
      
 47 
     | 
    
         
            +
                    @term = true
         
     | 
| 
      
 48 
     | 
    
         
            +
                  end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
       39 
50 
     | 
    
         
             
                  def term?
         
     | 
| 
       40 
51 
     | 
    
         
             
                    @term
         
     | 
| 
       41 
52 
     | 
    
         
             
                  end
         
     |