puma 5.6.4 → 6.1.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of puma might be problematic. Click here for more details.

Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +199 -3
  3. data/README.md +22 -17
  4. data/bin/puma-wild +1 -1
  5. data/docs/compile_options.md +34 -0
  6. data/docs/fork_worker.md +1 -3
  7. data/docs/nginx.md +1 -1
  8. data/docs/systemd.md +1 -2
  9. data/docs/testing_benchmarks_local_files.md +150 -0
  10. data/docs/testing_test_rackup_ci_files.md +36 -0
  11. data/ext/puma_http11/extconf.rb +18 -10
  12. data/ext/puma_http11/http11_parser.c +1 -1
  13. data/ext/puma_http11/http11_parser.h +1 -1
  14. data/ext/puma_http11/http11_parser.java.rl +2 -2
  15. data/ext/puma_http11/http11_parser.rl +2 -2
  16. data/ext/puma_http11/http11_parser_common.rl +2 -2
  17. data/ext/puma_http11/mini_ssl.c +63 -24
  18. data/ext/puma_http11/org/jruby/puma/Http11.java +3 -3
  19. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +1 -1
  20. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +166 -65
  21. data/ext/puma_http11/puma_http11.c +17 -9
  22. data/lib/puma/app/status.rb +6 -3
  23. data/lib/puma/binder.rb +41 -46
  24. data/lib/puma/cli.rb +11 -17
  25. data/lib/puma/client.rb +54 -16
  26. data/lib/puma/cluster/worker.rb +18 -11
  27. data/lib/puma/cluster/worker_handle.rb +4 -1
  28. data/lib/puma/cluster.rb +33 -30
  29. data/lib/puma/configuration.rb +75 -58
  30. data/lib/puma/const.rb +76 -88
  31. data/lib/puma/control_cli.rb +21 -18
  32. data/lib/puma/detect.rb +4 -0
  33. data/lib/puma/dsl.rb +111 -49
  34. data/lib/puma/error_logger.rb +17 -9
  35. data/lib/puma/events.rb +6 -126
  36. data/lib/puma/io_buffer.rb +39 -4
  37. data/lib/puma/jruby_restart.rb +2 -1
  38. data/lib/puma/launcher/bundle_pruner.rb +104 -0
  39. data/lib/puma/launcher.rb +111 -175
  40. data/lib/puma/log_writer.rb +141 -0
  41. data/lib/puma/minissl/context_builder.rb +23 -12
  42. data/lib/puma/minissl.rb +91 -15
  43. data/lib/puma/null_io.rb +5 -0
  44. data/lib/puma/plugin/systemd.rb +90 -0
  45. data/lib/puma/plugin/tmp_restart.rb +1 -1
  46. data/lib/puma/rack/builder.rb +4 -4
  47. data/lib/puma/rack_default.rb +19 -4
  48. data/lib/puma/reactor.rb +4 -4
  49. data/lib/puma/request.rb +344 -161
  50. data/lib/puma/runner.rb +52 -20
  51. data/lib/puma/sd_notify.rb +149 -0
  52. data/lib/puma/server.rb +57 -69
  53. data/lib/puma/single.rb +13 -11
  54. data/lib/puma/state_file.rb +2 -4
  55. data/lib/puma/thread_pool.rb +16 -16
  56. data/lib/puma/util.rb +12 -14
  57. data/lib/puma.rb +12 -11
  58. data/lib/rack/handler/puma.rb +115 -94
  59. metadata +10 -5
  60. data/lib/puma/queue_close.rb +0 -26
  61. data/lib/puma/systemd.rb +0 -46
data/lib/puma/runner.rb CHANGED
@@ -1,23 +1,29 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'puma/server'
4
- require 'puma/const'
3
+ require_relative 'server'
4
+ require_relative 'const'
5
5
 
6
6
  module Puma
7
7
  # Generic class that is used by `Puma::Cluster` and `Puma::Single` to
8
8
  # serve requests. This class spawns a new instance of `Puma::Server` via
9
9
  # a call to `start_server`.
10
10
  class Runner
11
- def initialize(cli, events)
12
- @launcher = cli
13
- @events = events
14
- @options = cli.options
11
+ def initialize(launcher)
12
+ @launcher = launcher
13
+ @log_writer = launcher.log_writer
14
+ @events = launcher.events
15
+ @config = launcher.config
16
+ @options = launcher.options
15
17
  @app = nil
16
18
  @control = nil
17
19
  @started_at = Time.now
18
20
  @wakeup = nil
19
21
  end
20
22
 
23
+ # Returns the hash of configuration options.
24
+ # @return [Puma::UserFileDefaultOptions]
25
+ attr_reader :options
26
+
21
27
  def wakeup!
22
28
  return unless @wakeup
23
29
 
@@ -36,27 +42,27 @@ module Puma
36
42
  end
37
43
 
38
44
  def log(str)
39
- @events.log str
45
+ @log_writer.log str
40
46
  end
41
47
 
42
48
  # @version 5.0.0
43
49
  def stop_control
44
- @control.stop(true) if @control
50
+ @control&.stop true
45
51
  end
46
52
 
47
53
  def error(str)
48
- @events.error str
54
+ @log_writer.error str
49
55
  end
50
56
 
51
57
  def debug(str)
52
- @events.log "- #{str}" if @options[:debug]
58
+ @log_writer.log "- #{str}" if @options[:debug]
53
59
  end
54
60
 
55
61
  def start_control
56
62
  str = @options[:control_url]
57
63
  return unless str
58
64
 
59
- require 'puma/app/status'
65
+ require_relative 'app/status'
60
66
 
61
67
  if token = @options[:control_auth_token]
62
68
  token = nil if token.empty? || token == 'none'
@@ -64,10 +70,12 @@ module Puma
64
70
 
65
71
  app = Puma::App::Status.new @launcher, token
66
72
 
67
- control = Puma::Server.new app, @launcher.events,
68
- { min_threads: 0, max_threads: 1, queue_requests: false }
73
+ # A Reactor is not created aand nio4r is not loaded when 'queue_requests: false'
74
+ # Use `nil` for events, no hooks in control server
75
+ control = Puma::Server.new app, nil,
76
+ { min_threads: 0, max_threads: 1, queue_requests: false, log_writer: @log_writer }
69
77
 
70
- control.binder.parse [str], self, 'Starting control server'
78
+ control.binder.parse [str], nil, 'Starting control server'
71
79
 
72
80
  control.run thread_name: 'ctl'
73
81
  @control = control
@@ -141,29 +149,29 @@ module Puma
141
149
  end
142
150
 
143
151
  def load_and_bind
144
- unless @launcher.config.app_configured?
152
+ unless @config.app_configured?
145
153
  error "No application configured, nothing to run"
146
154
  exit 1
147
155
  end
148
156
 
149
157
  begin
150
- @app = @launcher.config.app
158
+ @app = @config.app
151
159
  rescue Exception => e
152
160
  log "! Unable to load application: #{e.class}: #{e.message}"
153
161
  raise e
154
162
  end
155
163
 
156
- @launcher.binder.parse @options[:binds], self
164
+ @launcher.binder.parse @options[:binds]
157
165
  end
158
166
 
159
167
  # @!attribute [r] app
160
168
  def app
161
- @app ||= @launcher.config.app
169
+ @app ||= @config.app
162
170
  end
163
171
 
164
172
  def start_server
165
- server = Puma::Server.new app, @launcher.events, @options
166
- server.inherit_binder @launcher.binder
173
+ server = Puma::Server.new(app, @events, @options)
174
+ server.inherit_binder(@launcher.binder)
167
175
  server
168
176
  end
169
177
 
@@ -173,5 +181,29 @@ module Puma
173
181
  raise "Cannot redirect #{io_name} to #{path}"
174
182
  end
175
183
  end
184
+
185
+ def utc_iso8601(val)
186
+ "#{val.utc.strftime '%FT%T'}Z"
187
+ end
188
+
189
+ def stats
190
+ {
191
+ versions: {
192
+ puma: Puma::Const::PUMA_VERSION,
193
+ ruby: {
194
+ engine: RUBY_ENGINE,
195
+ version: RUBY_VERSION,
196
+ patchlevel: RUBY_PATCHLEVEL
197
+ }
198
+ }
199
+ }
200
+ end
201
+
202
+ # this method call should always be guarded by `@log_writer.debug?`
203
+ def debug_loaded_extensions(str)
204
+ @log_writer.debug "────────────────────────────────── #{str}"
205
+ re_ext = /\.#{RbConfig::CONFIG['DLEXT']}\z/i
206
+ $LOADED_FEATURES.grep(re_ext).each { |f| @log_writer.debug(" #{f}") }
207
+ end
176
208
  end
177
209
  end
@@ -0,0 +1,149 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "socket"
4
+
5
+ module Puma
6
+ # The MIT License
7
+ #
8
+ # Copyright (c) 2017-2022 Agis Anastasopoulos
9
+ #
10
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of
11
+ # this software and associated documentation files (the "Software"), to deal in
12
+ # the Software without restriction, including without limitation the rights to
13
+ # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
14
+ # the Software, and to permit persons to whom the Software is furnished to do so,
15
+ # subject to the following conditions:
16
+ #
17
+ # The above copyright notice and this permission notice shall be included in all
18
+ # copies or substantial portions of the Software.
19
+ #
20
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
22
+ # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
23
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
24
+ # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25
+ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
+ #
27
+ # This is a copy of https://github.com/agis/ruby-sdnotify as of commit cca575c
28
+ # The only changes made was "rehoming" it within the Puma module to avoid
29
+ # namespace collisions and applying standard's code formatting style.
30
+ #
31
+ # SdNotify is a pure-Ruby implementation of sd_notify(3). It can be used to
32
+ # notify systemd about state changes. Methods of this package are no-op on
33
+ # non-systemd systems (eg. Darwin).
34
+ #
35
+ # The API maps closely to the original implementation of sd_notify(3),
36
+ # therefore be sure to check the official man pages prior to using SdNotify.
37
+ #
38
+ # @see https://www.freedesktop.org/software/systemd/man/sd_notify.html
39
+ module SdNotify
40
+ # Exception raised when there's an error writing to the notification socket
41
+ class NotifyError < RuntimeError; end
42
+
43
+ READY = "READY=1"
44
+ RELOADING = "RELOADING=1"
45
+ STOPPING = "STOPPING=1"
46
+ STATUS = "STATUS="
47
+ ERRNO = "ERRNO="
48
+ MAINPID = "MAINPID="
49
+ WATCHDOG = "WATCHDOG=1"
50
+ FDSTORE = "FDSTORE=1"
51
+
52
+ def self.ready(unset_env=false)
53
+ notify(READY, unset_env)
54
+ end
55
+
56
+ def self.reloading(unset_env=false)
57
+ notify(RELOADING, unset_env)
58
+ end
59
+
60
+ def self.stopping(unset_env=false)
61
+ notify(STOPPING, unset_env)
62
+ end
63
+
64
+ # @param status [String] a custom status string that describes the current
65
+ # state of the service
66
+ def self.status(status, unset_env=false)
67
+ notify("#{STATUS}#{status}", unset_env)
68
+ end
69
+
70
+ # @param errno [Integer]
71
+ def self.errno(errno, unset_env=false)
72
+ notify("#{ERRNO}#{errno}", unset_env)
73
+ end
74
+
75
+ # @param pid [Integer]
76
+ def self.mainpid(pid, unset_env=false)
77
+ notify("#{MAINPID}#{pid}", unset_env)
78
+ end
79
+
80
+ def self.watchdog(unset_env=false)
81
+ notify(WATCHDOG, unset_env)
82
+ end
83
+
84
+ def self.fdstore(unset_env=false)
85
+ notify(FDSTORE, unset_env)
86
+ end
87
+
88
+ # @param [Boolean] true if the service manager expects watchdog keep-alive
89
+ # notification messages to be sent from this process.
90
+ #
91
+ # If the $WATCHDOG_USEC environment variable is set,
92
+ # and the $WATCHDOG_PID variable is unset or set to the PID of the current
93
+ # process
94
+ #
95
+ # @note Unlike sd_watchdog_enabled(3), this method does not mutate the
96
+ # environment.
97
+ def self.watchdog?
98
+ wd_usec = ENV["WATCHDOG_USEC"]
99
+ wd_pid = ENV["WATCHDOG_PID"]
100
+
101
+ return false if !wd_usec
102
+
103
+ begin
104
+ wd_usec = Integer(wd_usec)
105
+ rescue
106
+ return false
107
+ end
108
+
109
+ return false if wd_usec <= 0
110
+ return true if !wd_pid || wd_pid == $$.to_s
111
+
112
+ false
113
+ end
114
+
115
+ # Notify systemd with the provided state, via the notification socket, if
116
+ # any.
117
+ #
118
+ # Generally this method will be used indirectly through the other methods
119
+ # of the library.
120
+ #
121
+ # @param state [String]
122
+ # @param unset_env [Boolean]
123
+ #
124
+ # @return [Fixnum, nil] the number of bytes written to the notification
125
+ # socket or nil if there was no socket to report to (eg. the program wasn't
126
+ # started by systemd)
127
+ #
128
+ # @raise [NotifyError] if there was an error communicating with the systemd
129
+ # socket
130
+ #
131
+ # @see https://www.freedesktop.org/software/systemd/man/sd_notify.html
132
+ def self.notify(state, unset_env=false)
133
+ sock = ENV["NOTIFY_SOCKET"]
134
+
135
+ return nil if !sock
136
+
137
+ ENV.delete("NOTIFY_SOCKET") if unset_env
138
+
139
+ begin
140
+ Addrinfo.unix(sock, :DGRAM).connect do |s|
141
+ s.close_on_exec = true
142
+ s.write(state)
143
+ end
144
+ rescue StandardError => e
145
+ raise NotifyError, "#{e.class}: #{e.message}", e.backtrace
146
+ end
147
+ end
148
+ end
149
+ end
data/lib/puma/server.rb CHANGED
@@ -2,19 +2,19 @@
2
2
 
3
3
  require 'stringio'
4
4
 
5
- require 'puma/thread_pool'
6
- require 'puma/const'
7
- require 'puma/events'
8
- require 'puma/null_io'
9
- require 'puma/reactor'
10
- require 'puma/client'
11
- require 'puma/binder'
12
- require 'puma/util'
13
- require 'puma/io_buffer'
14
- require 'puma/request'
5
+ require_relative 'thread_pool'
6
+ require_relative 'const'
7
+ require_relative 'log_writer'
8
+ require_relative 'events'
9
+ require_relative 'null_io'
10
+ require_relative 'reactor'
11
+ require_relative 'client'
12
+ require_relative 'binder'
13
+ require_relative 'util'
14
+ require_relative 'request'
15
15
 
16
16
  require 'socket'
17
- require 'io/wait'
17
+ require 'io/wait' unless Puma::HAS_NATIVE_IO_WAIT
18
18
  require 'forwardable'
19
19
 
20
20
  module Puma
@@ -30,12 +30,12 @@ module Puma
30
30
  #
31
31
  # Each `Puma::Server` will have one reactor and one thread pool.
32
32
  class Server
33
-
34
33
  include Puma::Const
35
34
  include Request
36
35
  extend Forwardable
37
36
 
38
37
  attr_reader :thread
38
+ attr_reader :log_writer
39
39
  attr_reader :events
40
40
  attr_reader :min_threads, :max_threads # for #stats
41
41
  attr_reader :requests_count # @version 5.0.0
@@ -45,11 +45,6 @@ module Puma
45
45
  :leak_stack_on_error,
46
46
  :persistent_timeout, :reaping_time
47
47
 
48
- # @deprecated v6.0.0
49
- attr_writer :auto_trim_time, :early_hints, :first_data_timeout,
50
- :leak_stack_on_error, :min_threads, :max_threads,
51
- :persistent_timeout, :reaping_time
52
-
53
48
  attr_accessor :app
54
49
  attr_accessor :binder
55
50
 
@@ -60,8 +55,9 @@ module Puma
60
55
 
61
56
  # Create a server for the rack app +app+.
62
57
  #
63
- # +events+ is an object which will be called when certain error events occur
64
- # to be handled. See Puma::Events for the list of current methods to implement.
58
+ # +log_writer+ is a Puma::LogWriter object used to log info and error messages.
59
+ #
60
+ # +events+ is a Puma::Events object used to notify application status events.
65
61
  #
66
62
  # Server#run returns a thread that you can join on to wait for the server
67
63
  # to do its work.
@@ -70,34 +66,41 @@ module Puma
70
66
  # and have default values set via +fetch+. Normally the values are set via
71
67
  # `::Puma::Configuration.puma_default_options`.
72
68
  #
73
- def initialize(app, events=Events.stdio, options={})
69
+ # @note The `events` parameter is set to nil, and set to `Events.new` in code.
70
+ # Often `options` needs to be passed, but `events` does not. Using nil allows
71
+ # calling code to not require events.rb.
72
+ #
73
+ def initialize(app, events = nil, options = {})
74
74
  @app = app
75
- @events = events
75
+ @events = events || Events.new
76
76
 
77
77
  @check, @notify = nil
78
78
  @status = :stop
79
79
 
80
- @auto_trim_time = 30
81
- @reaping_time = 1
82
-
83
80
  @thread = nil
84
81
  @thread_pool = nil
85
82
 
86
- @options = options
83
+ @options = if options.is_a?(UserFileDefaultOptions)
84
+ options
85
+ else
86
+ UserFileDefaultOptions.new(options, Configuration::DEFAULTS)
87
+ end
87
88
 
88
- @early_hints = options.fetch :early_hints, nil
89
- @first_data_timeout = options.fetch :first_data_timeout, FIRST_DATA_TIMEOUT
90
- @min_threads = options.fetch :min_threads, 0
91
- @max_threads = options.fetch :max_threads , (Puma.mri? ? 5 : 16)
92
- @persistent_timeout = options.fetch :persistent_timeout, PERSISTENT_TIMEOUT
93
- @queue_requests = options.fetch :queue_requests, true
94
- @max_fast_inline = options.fetch :max_fast_inline, MAX_FAST_INLINE
95
- @io_selector_backend = options.fetch :io_selector_backend, :auto
89
+ @log_writer = @options.fetch :log_writer, LogWriter.stdio
90
+ @early_hints = @options[:early_hints]
91
+ @first_data_timeout = @options[:first_data_timeout]
92
+ @min_threads = @options[:min_threads]
93
+ @max_threads = @options[:max_threads]
94
+ @persistent_timeout = @options[:persistent_timeout]
95
+ @queue_requests = @options[:queue_requests]
96
+ @max_fast_inline = @options[:max_fast_inline]
97
+ @io_selector_backend = @options[:io_selector_backend]
98
+ @http_content_length_limit = @options[:http_content_length_limit]
96
99
 
97
100
  temp = !!(@options[:environment] =~ /\A(development|test)\z/)
98
101
  @leak_stack_on_error = @options[:environment] ? temp : true
99
102
 
100
- @binder = Binder.new(events)
103
+ @binder = Binder.new(log_writer)
101
104
 
102
105
  ENV['RACK_ENV'] ||= "development"
103
106
 
@@ -193,12 +196,12 @@ module Puma
193
196
 
194
197
  # @!attribute [r] backlog
195
198
  def backlog
196
- @thread_pool and @thread_pool.backlog
199
+ @thread_pool&.backlog
197
200
  end
198
201
 
199
202
  # @!attribute [r] running
200
203
  def running
201
- @thread_pool and @thread_pool.spawned
204
+ @thread_pool&.spawned
202
205
  end
203
206
 
204
207
 
@@ -211,7 +214,7 @@ module Puma
211
214
  # value would be 4 until it finishes processing.
212
215
  # @!attribute [r] pool_capacity
213
216
  def pool_capacity
214
- @thread_pool and @thread_pool.pool_capacity
217
+ @thread_pool&.pool_capacity
215
218
  end
216
219
 
217
220
  # Runs the server.
@@ -227,29 +230,16 @@ module Puma
227
230
 
228
231
  @status = :run
229
232
 
230
- @thread_pool = ThreadPool.new(
231
- thread_name,
232
- @min_threads,
233
- @max_threads,
234
- ::Puma::IOBuffer,
235
- &method(:process_client)
236
- )
237
-
238
- @thread_pool.out_of_band_hook = @options[:out_of_band]
239
- @thread_pool.clean_thread_locals = @options[:clean_thread_locals]
233
+ @thread_pool = ThreadPool.new(thread_name, @options) { |client| process_client client }
240
234
 
241
235
  if @queue_requests
242
- @reactor = Reactor.new(@io_selector_backend, &method(:reactor_wakeup))
236
+ @reactor = Reactor.new(@io_selector_backend) { |c| reactor_wakeup c }
243
237
  @reactor.run
244
238
  end
245
239
 
246
- if @reaping_time
247
- @thread_pool.auto_reap!(@reaping_time)
248
- end
249
240
 
250
- if @auto_trim_time
251
- @thread_pool.auto_trim!(@auto_trim_time)
252
- end
241
+ @thread_pool.auto_reap! if @options[:reaping_time]
242
+ @thread_pool.auto_trim! if @options[:auto_trim_time]
253
243
 
254
244
  @check, @notify = Puma::Util.pipe unless @notify
255
245
 
@@ -345,6 +335,7 @@ module Puma
345
335
  drain += 1 if shutting_down?
346
336
  pool << Client.new(io, @binder.env(sock)).tap { |c|
347
337
  c.listener = sock
338
+ c.http_content_length_limit = @http_content_length_limit
348
339
  c.send(addr_send_name, addr_value) if addr_value
349
340
  }
350
341
  end
@@ -353,11 +344,11 @@ module Puma
353
344
  # In the case that any of the sockets are unexpectedly close.
354
345
  raise
355
346
  rescue StandardError => e
356
- @events.unknown_error e, nil, "Listen loop"
347
+ @log_writer.unknown_error e, nil, "Listen loop"
357
348
  end
358
349
  end
359
350
 
360
- @events.debug "Drained #{drain} additional connections." if drain
351
+ @log_writer.debug "Drained #{drain} additional connections." if drain
361
352
  @events.fire :state, @status
362
353
 
363
354
  if queue_requests
@@ -366,14 +357,13 @@ module Puma
366
357
  end
367
358
  graceful_shutdown if @status == :stop || @status == :restart
368
359
  rescue Exception => e
369
- @events.unknown_error e, nil, "Exception handling servers"
360
+ @log_writer.unknown_error e, nil, "Exception handling servers"
370
361
  ensure
371
- # RuntimeError is Ruby 2.2 issue, can't modify frozen IOError
372
362
  # Errno::EBADF is infrequently raised
373
363
  [@check, @notify].each do |io|
374
364
  begin
375
365
  io.close unless io.closed?
376
- rescue Errno::EBADF, RuntimeError
366
+ rescue Errno::EBADF
377
367
  end
378
368
  end
379
369
  @notify = nil
@@ -412,7 +402,7 @@ module Puma
412
402
  # returning.
413
403
  #
414
404
  # Return true if one or more requests were processed.
415
- def process_client(client, buffer)
405
+ def process_client(client)
416
406
  # Advertise this server into the thread
417
407
  Thread.current[ThreadLocalKey] = self
418
408
 
@@ -438,15 +428,13 @@ module Puma
438
428
 
439
429
  while true
440
430
  @requests_count += 1
441
- case handle_request(client, buffer, requests + 1)
431
+ case handle_request(client, requests + 1)
442
432
  when false
443
433
  break
444
434
  when :async
445
435
  close_socket = false
446
436
  break
447
437
  when true
448
- buffer.reset
449
-
450
438
  ThreadPool.clean_thread_locals if clean_thread_locals
451
439
 
452
440
  requests += 1
@@ -480,7 +468,7 @@ module Puma
480
468
  # The ensure tries to close +client+ down
481
469
  requests > 0
482
470
  ensure
483
- buffer.reset
471
+ client.io_buffer.reset
484
472
 
485
473
  begin
486
474
  client.close if close_socket
@@ -488,7 +476,7 @@ module Puma
488
476
  Puma::Util.purge_interrupt_queue
489
477
  # Already closed
490
478
  rescue StandardError => e
491
- @events.unknown_error e, nil, "Client"
479
+ @log_writer.unknown_error e, nil, "Client"
492
480
  end
493
481
  end
494
482
  end
@@ -511,16 +499,16 @@ module Puma
511
499
  lowlevel_error(e, client.env)
512
500
  case e
513
501
  when MiniSSL::SSLError
514
- @events.ssl_error e, client.io
502
+ @log_writer.ssl_error e, client.io
515
503
  when HttpParserError
516
504
  client.write_error(400)
517
- @events.parse_error e, client
505
+ @log_writer.parse_error e, client
518
506
  when HttpParserError501
519
507
  client.write_error(501)
520
- @events.parse_error e, client
508
+ @log_writer.parse_error e, client
521
509
  else
522
510
  client.write_error(500)
523
- @events.unknown_error e, nil, "Read"
511
+ @log_writer.unknown_error e, nil, "Read"
524
512
  end
525
513
  end
526
514
 
data/lib/puma/single.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'puma/runner'
4
- require 'puma/detect'
5
- require 'puma/plugin'
3
+ require_relative 'runner'
4
+ require_relative 'detect'
5
+ require_relative 'plugin'
6
6
 
7
7
  module Puma
8
8
  # This class is instantiated by the `Puma::Launcher` and used
@@ -16,26 +16,26 @@ module Puma
16
16
  # @!attribute [r] stats
17
17
  def stats
18
18
  {
19
- started_at: @started_at.utc.iso8601
20
- }.merge(@server.stats)
19
+ started_at: utc_iso8601(@started_at)
20
+ }.merge(@server.stats).merge(super)
21
21
  end
22
22
 
23
23
  def restart
24
- @server.begin_restart
24
+ @server&.begin_restart
25
25
  end
26
26
 
27
27
  def stop
28
- @server.stop(false) if @server
28
+ @server&.stop false
29
29
  end
30
30
 
31
31
  def halt
32
- @server.halt
32
+ @server&.halt
33
33
  end
34
34
 
35
35
  def stop_blocked
36
36
  log "- Gracefully stopping, waiting for requests to finish"
37
- @control.stop(true) if @control
38
- @server.stop(true) if @server
37
+ @control&.stop true
38
+ @server&.stop true
39
39
  end
40
40
 
41
41
  def run
@@ -55,7 +55,9 @@ module Puma
55
55
  log "Use Ctrl-C to stop"
56
56
  redirect_io
57
57
 
58
- @launcher.events.fire_on_booted!
58
+ @events.fire_on_booted!
59
+
60
+ debug_loaded_extensions("Loaded Extensions:") if @log_writer.debug?
59
61
 
60
62
  begin
61
63
  server_thread.join
@@ -15,15 +15,12 @@ module Puma
15
15
 
16
16
  ALLOWED_FIELDS = %w!control_url control_auth_token pid running_from!
17
17
 
18
- # @deprecated 6.0.0
19
- FIELDS = ALLOWED_FIELDS
20
-
21
18
  def initialize
22
19
  @options = {}
23
20
  end
24
21
 
25
22
  def save(path, permission = nil)
26
- contents = "---\n".dup
23
+ contents = +"---\n"
27
24
  @options.each do |k,v|
28
25
  next unless ALLOWED_FIELDS.include? k
29
26
  case v
@@ -50,6 +47,7 @@ module Puma
50
47
  v = v.strip
51
48
  @options[k] =
52
49
  case v
50
+ when '' then nil
53
51
  when /\A\d+\z/ then v.to_i
54
52
  when /\A\d+\.\d+\z/ then v.to_f
55
53
  else v.gsub(/\A"|"\z/, '')