puma 4.2.0 → 4.3.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.

@@ -162,7 +162,7 @@ module Puma
162
162
  end
163
163
 
164
164
  o.on "--extra-runtime-dependencies GEM1,GEM2", "Defines any extra needed gems when using --prune-bundler" do |arg|
165
- c.extra_runtime_dependencies arg.split(',')
165
+ user_config.extra_runtime_dependencies arg.split(',')
166
166
  end
167
167
 
168
168
  o.on "-q", "--quiet", "Do not log requests internally (default true)" do
@@ -9,8 +9,8 @@ class IO
9
9
  end
10
10
 
11
11
  require 'puma/detect'
12
- require 'puma/delegation'
13
12
  require 'tempfile'
13
+ require 'forwardable'
14
14
 
15
15
  if Puma::IS_JRUBY
16
16
  # We have to work around some OpenSSL buffer/io-readiness bugs
@@ -41,7 +41,7 @@ module Puma
41
41
  EmptyBody = NullIO.new
42
42
 
43
43
  include Puma::Const
44
- extend Puma::Delegation
44
+ extend Forwardable
45
45
 
46
46
  def initialize(io, env=nil)
47
47
  @io = io
@@ -83,7 +83,7 @@ module Puma
83
83
 
84
84
  attr_accessor :remote_addr_header
85
85
 
86
- forward :closed?, :@io
86
+ def_delegators :@io, :closed?
87
87
 
88
88
  def inspect
89
89
  "#<Puma::Client:0x#{object_id.to_s(16)} @ready=#{@ready.inspect}>"
@@ -529,7 +529,6 @@ module Puma
529
529
  @suicide_pipe.close
530
530
  read.close
531
531
  @wakeup.close
532
- @launcher.close_binder_unix_paths
533
532
  end
534
533
  end
535
534
 
@@ -100,8 +100,8 @@ module Puma
100
100
  # too taxing on performance.
101
101
  module Const
102
102
 
103
- PUMA_VERSION = VERSION = "4.2.0".freeze
104
- CODE_NAME = "Distant Airhorns".freeze
103
+ PUMA_VERSION = VERSION = "4.3.1".freeze
104
+ CODE_NAME = "Mysterious Traveller".freeze
105
105
  PUMA_SERVER_STRING = ['puma', PUMA_VERSION, CODE_NAME].join(' ').freeze
106
106
 
107
107
  FAST_TRACK_KA_TIMEOUT = 0.2
@@ -118,6 +118,13 @@ module Puma
118
118
  # sending data back
119
119
  WRITE_TIMEOUT = 10
120
120
 
121
+ # How many requests to attempt inline before sending a client back to
122
+ # the reactor to be subject to normal ordering. The idea here is that
123
+ # we amortize the cost of going back to the reactor for a well behaved
124
+ # but very "greedy" client across 10 requests. This prevents a not
125
+ # well behaved client from monopolizing the thread forever.
126
+ MAX_FAST_INLINE = 10
127
+
121
128
  # The original URI requested by the client.
122
129
  REQUEST_URI= 'REQUEST_URI'.freeze
123
130
  REQUEST_PATH = 'REQUEST_PATH'.freeze
@@ -22,7 +22,7 @@ module Puma
22
22
  @control_auth_token = nil
23
23
  @config_file = nil
24
24
  @command = nil
25
- @environment = ENV['RACK_ENV'] || "development"
25
+ @environment = ENV['RACK_ENV']
26
26
 
27
27
  @argv = argv.dup
28
28
  @stdout = stdout
@@ -82,8 +82,10 @@ module Puma
82
82
  @command = argv.shift
83
83
 
84
84
  unless @config_file == '-'
85
+ environment = @environment || 'development'
86
+
85
87
  if @config_file.nil?
86
- @config_file = %W(config/puma/#{@environment}.rb config/puma.rb).find do |f|
88
+ @config_file = %W(config/puma/#{environment}.rb config/puma.rb).find do |f|
87
89
  File.exist?(f)
88
90
  end
89
91
  end
@@ -130,7 +132,7 @@ module Puma
130
132
  @pid = sf.pid
131
133
  elsif @pidfile
132
134
  # get pid from pid_file
133
- @pid = File.open(@pidfile).gets.to_i
135
+ File.open(@pidfile) { |f| @pid = f.read.to_i }
134
136
  end
135
137
  end
136
138
 
@@ -139,6 +141,12 @@ module Puma
139
141
 
140
142
  # create server object by scheme
141
143
  server = case uri.scheme
144
+ when "ssl"
145
+ require 'openssl'
146
+ OpenSSL::SSL::SSLSocket.new(
147
+ TCPSocket.new(uri.host, uri.port),
148
+ OpenSSL::SSL::SSLContext.new
149
+ ).tap(&:connect)
142
150
  when "tcp"
143
151
  TCPSocket.new uri.host, uri.port
144
152
  when "unix"
@@ -396,7 +396,7 @@ module Puma
396
396
  # keystore_pass: password
397
397
  # }
398
398
  def ssl_bind(host, port, opts)
399
- verify = opts.fetch(:verify_mode, 'none')
399
+ verify = opts.fetch(:verify_mode, 'none').to_s
400
400
  no_tlsv1 = opts.fetch(:no_tlsv1, 'false')
401
401
  no_tlsv1_1 = opts.fetch(:no_tlsv1_1, 'false')
402
402
  ca_additions = "&ca=#{opts[:ca]}" if ['peer', 'force_peer'].include?(verify)
@@ -583,6 +583,8 @@ module Puma
583
583
  # new Bundler context and thus can float around as the release
584
584
  # dictates.
585
585
  #
586
+ # See also: extra_runtime_dependencies
587
+ #
586
588
  # @note This is incompatible with +preload_app!+.
587
589
  # @note This is only supported for RubyGems 2.2+
588
590
  def prune_bundler(answer=true)
@@ -603,7 +605,7 @@ module Puma
603
605
  end
604
606
 
605
607
  # When using prune_bundler, if extra runtime dependencies need to be loaded to
606
- # initialize your app, then this setting can be used.
608
+ # initialize your app, then this setting can be used. This includes any Puma plugins.
607
609
  #
608
610
  # Before bundler is pruned, the gem names supplied will be looked up in the bundler
609
611
  # context and then loaded again after bundler is pruned.
@@ -612,7 +614,7 @@ module Puma
612
614
  # @example
613
615
  # extra_runtime_dependencies ['gem_name_1', 'gem_name_2']
614
616
  # @example
615
- # extra_runtime_dependencies ['puma_worker_killer']
617
+ # extra_runtime_dependencies ['puma_worker_killer', 'puma-heroku']
616
618
  def extra_runtime_dependencies(answer = [])
617
619
  @options[:extra_runtime_dependencies] = Array(answer)
618
620
  end
@@ -184,6 +184,7 @@ module Puma
184
184
  when :exit
185
185
  # nothing
186
186
  end
187
+ @binder.close_unix_paths
187
188
  end
188
189
 
189
190
  # Return which tcp port the launcher is using, if it's using TCP
@@ -204,10 +205,6 @@ module Puma
204
205
  @binder.close_listeners
205
206
  end
206
207
 
207
- def close_binder_unix_paths
208
- @binder.close_unix_paths
209
- end
210
-
211
208
  private
212
209
 
213
210
  # If configured, write the pid of the current process out
@@ -0,0 +1,76 @@
1
+ module Puma
2
+ module MiniSSL
3
+ class ContextBuilder
4
+ def initialize(params, events)
5
+ require 'puma/minissl'
6
+ MiniSSL.check
7
+
8
+ @params = params
9
+ @events = events
10
+ end
11
+
12
+ def context
13
+ ctx = MiniSSL::Context.new
14
+
15
+ if defined?(JRUBY_VERSION)
16
+ unless params['keystore']
17
+ events.error "Please specify the Java keystore via 'keystore='"
18
+ end
19
+
20
+ ctx.keystore = params['keystore']
21
+
22
+ unless params['keystore-pass']
23
+ events.error "Please specify the Java keystore password via 'keystore-pass='"
24
+ end
25
+
26
+ ctx.keystore_pass = params['keystore-pass']
27
+ ctx.ssl_cipher_list = params['ssl_cipher_list'] if params['ssl_cipher_list']
28
+ else
29
+ unless params['key']
30
+ events.error "Please specify the SSL key via 'key='"
31
+ end
32
+
33
+ ctx.key = params['key']
34
+
35
+ unless params['cert']
36
+ events.error "Please specify the SSL cert via 'cert='"
37
+ end
38
+
39
+ ctx.cert = params['cert']
40
+
41
+ if ['peer', 'force_peer'].include?(params['verify_mode'])
42
+ unless params['ca']
43
+ events.error "Please specify the SSL ca via 'ca='"
44
+ end
45
+ end
46
+
47
+ ctx.ca = params['ca'] if params['ca']
48
+ ctx.ssl_cipher_filter = params['ssl_cipher_filter'] if params['ssl_cipher_filter']
49
+ end
50
+
51
+ ctx.no_tlsv1 = true if params['no_tlsv1'] == 'true'
52
+ ctx.no_tlsv1_1 = true if params['no_tlsv1_1'] == 'true'
53
+
54
+ if params['verify_mode']
55
+ ctx.verify_mode = case params['verify_mode']
56
+ when "peer"
57
+ MiniSSL::VERIFY_PEER
58
+ when "force_peer"
59
+ MiniSSL::VERIFY_PEER | MiniSSL::VERIFY_FAIL_IF_NO_PEER_CERT
60
+ when "none"
61
+ MiniSSL::VERIFY_NONE
62
+ else
63
+ events.error "Please specify a valid verify_mode="
64
+ MiniSSL::VERIFY_NONE
65
+ end
66
+ end
67
+
68
+ ctx
69
+ end
70
+
71
+ private
72
+
73
+ attr_reader :params, :events
74
+ end
75
+ end
76
+ end
@@ -237,7 +237,8 @@ module Puma
237
237
  ssl_socket = c.io
238
238
  begin
239
239
  addr = ssl_socket.peeraddr.last
240
- rescue IOError
240
+ # EINVAL can happen when browser closes socket w/security exception
241
+ rescue IOError, Errno::EINVAL
241
242
  addr = "<unknown>"
242
243
  end
243
244
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'puma/server'
4
4
  require 'puma/const'
5
+ require 'puma/minissl/context_builder'
5
6
 
6
7
  module Puma
7
8
  # Generic class that is used by `Puma::Cluster` and `Puma::Single` to
@@ -64,6 +65,12 @@ module Puma
64
65
  control.max_threads = 1
65
66
 
66
67
  case uri.scheme
68
+ when "ssl"
69
+ log "* Starting control server on #{str}"
70
+ params = Util.parse_query uri.query
71
+ ctx = MiniSSL::ContextBuilder.new(params, @events).context
72
+
73
+ control.add_ssl_listener uri.host, uri.port, ctx
67
74
  when "tcp"
68
75
  log "* Starting control server on #{str}"
69
76
  control.add_tcp_listener uri.host, uri.port
@@ -9,13 +9,13 @@ require 'puma/null_io'
9
9
  require 'puma/reactor'
10
10
  require 'puma/client'
11
11
  require 'puma/binder'
12
- require 'puma/delegation'
13
12
  require 'puma/accept_nonblock'
14
13
  require 'puma/util'
15
14
 
16
15
  require 'puma/puma_http11'
17
16
 
18
17
  require 'socket'
18
+ require 'forwardable'
19
19
 
20
20
  module Puma
21
21
 
@@ -32,7 +32,7 @@ module Puma
32
32
  class Server
33
33
 
34
34
  include Puma::Const
35
- extend Puma::Delegation
35
+ extend Forwardable
36
36
 
37
37
  attr_reader :thread
38
38
  attr_reader :events
@@ -89,10 +89,7 @@ module Puma
89
89
 
90
90
  attr_accessor :binder, :leak_stack_on_error, :early_hints
91
91
 
92
- forward :add_tcp_listener, :@binder
93
- forward :add_ssl_listener, :@binder
94
- forward :add_unix_listener, :@binder
95
- forward :connected_port, :@binder
92
+ def_delegators :@binder, :add_tcp_listener, :add_ssl_listener, :add_unix_listener, :connected_port
96
93
 
97
94
  def inherit_binder(bind)
98
95
  @binder = bind
@@ -469,6 +466,8 @@ module Puma
469
466
  clean_thread_locals = @options[:clean_thread_locals]
470
467
  close_socket = true
471
468
 
469
+ requests = 0
470
+
472
471
  while true
473
472
  case handle_request(client, buffer)
474
473
  when false
@@ -482,7 +481,19 @@ module Puma
482
481
 
483
482
  ThreadPool.clean_thread_locals if clean_thread_locals
484
483
 
485
- unless client.reset(@status == :run)
484
+ requests += 1
485
+
486
+ check_for_more_data = @status == :run
487
+
488
+ if requests >= MAX_FAST_INLINE
489
+ # This will mean that reset will only try to use the data it already
490
+ # has buffered and won't try to read more data. What this means is that
491
+ # every client, independent of their request speed, gets treated like a slow
492
+ # one once every MAX_FAST_INLINE requests.
493
+ check_for_more_data = false
494
+ end
495
+
496
+ unless client.reset(check_for_more_data)
486
497
  close_socket = false
487
498
  client.set_timeout @persistent_timeout
488
499
  @reactor.add client
@@ -118,7 +118,6 @@ module Puma
118
118
  rescue Interrupt
119
119
  # Swallow it
120
120
  end
121
- @launcher.close_binder_unix_paths
122
121
  end
123
122
  end
124
123
  end
@@ -189,7 +189,7 @@ module Puma
189
189
  # request, it might not be added to the `@todo` array right away.
190
190
  # For example if a slow client has only sent a header, but not a body
191
191
  # then the `@todo` array would stay the same size as the reactor works
192
- # to try to buffer the request. In tha scenario the next call to this
192
+ # to try to buffer the request. In that scenario the next call to this
193
193
  # method would not block and another request would be added into the reactor
194
194
  # by the server. This would continue until a fully bufferend request
195
195
  # makes it through the reactor and can then be processed by the thread pool.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: puma
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.2.0
4
+ version: 4.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Evan Phoenix
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-09-23 00:00:00.000000000 Z
11
+ date: 2019-12-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nio4r
@@ -53,6 +53,7 @@ files:
53
53
  - docs/restart.md
54
54
  - docs/signals.md
55
55
  - docs/systemd.md
56
+ - docs/tcp_mode.md
56
57
  - ext/puma_http11/PumaHttp11Service.java
57
58
  - ext/puma_http11/ext_help.h
58
59
  - ext/puma_http11/extconf.rb
@@ -79,8 +80,6 @@ files:
79
80
  - lib/puma/configuration.rb
80
81
  - lib/puma/const.rb
81
82
  - lib/puma/control_cli.rb
82
- - lib/puma/convenient.rb
83
- - lib/puma/delegation.rb
84
83
  - lib/puma/detect.rb
85
84
  - lib/puma/dsl.rb
86
85
  - lib/puma/events.rb
@@ -88,6 +87,7 @@ files:
88
87
  - lib/puma/jruby_restart.rb
89
88
  - lib/puma/launcher.rb
90
89
  - lib/puma/minissl.rb
90
+ - lib/puma/minissl/context_builder.rb
91
91
  - lib/puma/null_io.rb
92
92
  - lib/puma/plugin.rb
93
93
  - lib/puma/plugin/tmp_restart.rb
@@ -1,25 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'puma/launcher'
4
- require 'puma/configuration'
5
-
6
- module Puma
7
- def self.run(opts={})
8
- cfg = Puma::Configuration.new do |user_config|
9
- if port = opts[:port]
10
- user_config.port port
11
- end
12
-
13
- user_config.quiet
14
-
15
- yield c
16
- end
17
-
18
- cfg.clamp
19
-
20
- events = Puma::Events.null
21
-
22
- launcher = Puma::Launcher.new cfg, :events => events
23
- launcher.run
24
- end
25
- end
@@ -1,13 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Puma
4
- module Delegation
5
- def forward(what, who)
6
- module_eval <<-CODE
7
- def #{what}(*args, &block)
8
- #{who}.#{what}(*args, &block)
9
- end
10
- CODE
11
- end
12
- end
13
- end