puma 3.12.6 → 4.0.0

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.

@@ -55,7 +55,7 @@ module Puma
55
55
  app = Puma::App::Status.new @launcher
56
56
 
57
57
  if token = @options[:control_auth_token]
58
- app.auth_token = token unless token.empty? or token == :none
58
+ app.auth_token = token unless token.empty? || token == 'none'
59
59
  end
60
60
 
61
61
  control = Puma::Server.new app, @launcher.events
@@ -6,7 +6,6 @@ require 'puma/thread_pool'
6
6
  require 'puma/const'
7
7
  require 'puma/events'
8
8
  require 'puma/null_io'
9
- require 'puma/compat'
10
9
  require 'puma/reactor'
11
10
  require 'puma/client'
12
11
  require 'puma/binder'
@@ -16,10 +15,6 @@ require 'puma/util'
16
15
 
17
16
  require 'puma/puma_http11'
18
17
 
19
- unless Puma.const_defined? "IOBuffer"
20
- require 'puma/io_buffer'
21
- end
22
-
23
18
  require 'socket'
24
19
 
25
20
  module Puma
@@ -28,7 +23,7 @@ module Puma
28
23
  #
29
24
  # This class is used by the `Puma::Single` and `Puma::Cluster` classes
30
25
  # to generate one or more `Puma::Server` instances capable of handling requests.
31
- # Each Puma process will contain one `Puma::Server` instacne.
26
+ # Each Puma process will contain one `Puma::Server` instance.
32
27
  #
33
28
  # The `Puma::Server` instance pulls requests from the socket, adds them to a
34
29
  # `Puma::Reactor` where they get eventually passed to a `Puma::ThreadPool`.
@@ -79,7 +74,6 @@ module Puma
79
74
  @first_data_timeout = options.fetch(:first_data_timeout, FIRST_DATA_TIMEOUT)
80
75
 
81
76
  @binder = Binder.new(events)
82
- @own_binder = true
83
77
 
84
78
  @leak_stack_on_error = true
85
79
 
@@ -102,7 +96,6 @@ module Puma
102
96
 
103
97
  def inherit_binder(bind)
104
98
  @binder = bind
105
- @own_binder = false
106
99
  end
107
100
 
108
101
  def tcp_mode!
@@ -270,10 +263,11 @@ module Puma
270
263
  Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
271
264
  end
272
265
 
273
- @notify.close
274
-
275
- if @status != :restart and @own_binder
276
- @binder.close
266
+ # Prevent can't modify frozen IOError (RuntimeError)
267
+ begin
268
+ @notify.close
269
+ rescue IOError
270
+ # no biggy
277
271
  end
278
272
  end
279
273
 
@@ -398,7 +392,10 @@ module Puma
398
392
  end
399
393
 
400
394
  pool << client
401
- pool.wait_until_not_full
395
+ busy_threads = pool.wait_until_not_full
396
+ if busy_threads == 0
397
+ @options[:out_of_band].each(&:call) if @options[:out_of_band]
398
+ end
402
399
  end
403
400
  rescue SystemCallError
404
401
  # nothing
@@ -430,10 +427,6 @@ module Puma
430
427
  ensure
431
428
  @check.close
432
429
  @notify.close
433
-
434
- if @status != :restart and @own_binder
435
- @binder.close
436
- end
437
430
  end
438
431
 
439
432
  @events.fire :state, :done
@@ -470,8 +463,6 @@ module Puma
470
463
  clean_thread_locals = @options[:clean_thread_locals]
471
464
  close_socket = true
472
465
 
473
- requests = 0
474
-
475
466
  while true
476
467
  case handle_request(client, buffer)
477
468
  when false
@@ -485,19 +476,7 @@ module Puma
485
476
 
486
477
  ThreadPool.clean_thread_locals if clean_thread_locals
487
478
 
488
- requests += 1
489
-
490
- check_for_more_data = @status == :run
491
-
492
- if requests >= MAX_FAST_INLINE
493
- # This will mean that reset will only try to use the data it already
494
- # has buffered and won't try to read more data. What this means is that
495
- # every client, independent of their request speed, gets treated like a slow
496
- # one once every MAX_FAST_INLINE requests.
497
- check_for_more_data = false
498
- end
499
-
500
- unless client.reset(check_for_more_data)
479
+ unless client.reset(@status == :run)
501
480
  close_socket = false
502
481
  client.set_timeout @persistent_timeout
503
482
  @reactor.add client
@@ -613,15 +592,19 @@ module Puma
613
592
  env['HTTP_X_FORWARDED_PROTO'] == 'https' ? PORT_443 : PORT_80
614
593
  end
615
594
 
616
- # Given the request +env+ from +client+ and a partial request body
617
- # in +body+, finish reading the body if there is one and invoke
618
- # the rack app. Then construct the response and write it back to
619
- # +client+
595
+ # Takes the request +req+, invokes the Rack application to construct
596
+ # the response and writes it back to +req.io+.
597
+ #
598
+ # The second parameter +lines+ is a IO-like object unique to this thread.
599
+ # This is normally an instance of Puma::IOBuffer.
620
600
  #
621
- # +cl+ is the previously fetched Content-Length header if there
622
- # was one. This is an optimization to keep from having to look
623
- # it up again.
601
+ # It'll return +false+ when the connection is closed, this doesn't mean
602
+ # that the response wasn't successful.
624
603
  #
604
+ # It'll return +:async+ if the connection remains open but will be handled
605
+ # elsewhere, i.e. the connection has been hijacked by the Rack application.
606
+ #
607
+ # Finally, it'll return +true+ on keep-alive connections.
625
608
  def handle_request(req, lines)
626
609
  env = req.env
627
610
  client = req.io
@@ -653,7 +636,6 @@ module Puma
653
636
  headers.each_pair do |k, vs|
654
637
  if vs.respond_to?(:to_s) && !vs.to_s.empty?
655
638
  vs.to_s.split(NEWLINE).each do |v|
656
- next if possible_header_injection?(v)
657
639
  fast_write client, "#{k}: #{v}\r\n"
658
640
  end
659
641
  else
@@ -665,37 +647,6 @@ module Puma
665
647
  }
666
648
  end
667
649
 
668
- # Fixup any headers with , in the name to have _ now. We emit
669
- # headers with , in them during the parse phase to avoid ambiguity
670
- # with the - to _ conversion for critical headers. But here for
671
- # compatibility, we'll convert them back. This code is written to
672
- # avoid allocation in the common case (ie there are no headers
673
- # with , in their names), that's why it has the extra conditionals.
674
-
675
- to_delete = nil
676
- to_add = nil
677
-
678
- env.each do |k,v|
679
- if k.start_with?("HTTP_") and k.include?(",") and k != "HTTP_TRANSFER,ENCODING"
680
- if to_delete
681
- to_delete << k
682
- else
683
- to_delete = [k]
684
- end
685
-
686
- unless to_add
687
- to_add = {}
688
- end
689
-
690
- to_add[k.gsub(",", "_")] = v
691
- end
692
- end
693
-
694
- if to_delete
695
- to_delete.each { |k| env.delete(k) }
696
- env.merge! to_add
697
- end
698
-
699
650
  # A rack extension. If the app writes #call'ables to this
700
651
  # array, we will invoke them when the request is done.
701
652
  #
@@ -783,7 +734,6 @@ module Puma
783
734
  headers.each do |k, vs|
784
735
  case k.downcase
785
736
  when CONTENT_LENGTH2
786
- next if possible_header_injection?(vs)
787
737
  content_length = vs
788
738
  next
789
739
  when TRANSFER_ENCODING
@@ -796,7 +746,6 @@ module Puma
796
746
 
797
747
  if vs.respond_to?(:to_s) && !vs.to_s.empty?
798
748
  vs.to_s.split(NEWLINE).each do |v|
799
- next if possible_header_injection?(v)
800
749
  lines.append k, colon, v, line_ending
801
750
  end
802
751
  else
@@ -990,6 +939,10 @@ module Puma
990
939
  @events.debug "Drained #{count} additional connections."
991
940
  end
992
941
 
942
+ if @status != :restart
943
+ @binder.close
944
+ end
945
+
993
946
  if @thread_pool
994
947
  if timeout = @options[:force_shutdown_after]
995
948
  @thread_pool.shutdown timeout.to_i
@@ -1063,10 +1016,5 @@ module Puma
1063
1016
  def shutting_down?
1064
1017
  @status == :stop || @status == :restart
1065
1018
  end
1066
-
1067
- def possible_header_injection?(header_value)
1068
- HTTP_INJECTION_REGEX =~ header_value.to_s
1069
- end
1070
- private :possible_header_injection?
1071
1019
  end
1072
1020
  end
@@ -26,7 +26,7 @@ module Puma
26
26
  end
27
27
 
28
28
  def stop
29
- @server.stop false
29
+ @server.stop(false) if @server
30
30
  end
31
31
 
32
32
  def halt
@@ -36,7 +36,7 @@ module Puma
36
36
  def stop_blocked
37
37
  log "- Gracefully stopping, waiting for requests to finish"
38
38
  @control.stop(true) if @control
39
- @server.stop(true)
39
+ @server.stop(true) if @server
40
40
  end
41
41
 
42
42
  def jruby_daemon?
@@ -194,6 +194,9 @@ module Puma
194
194
  # method would not block and another request would be added into the reactor
195
195
  # by the server. This would continue until a fully bufferend request
196
196
  # makes it through the reactor and can then be processed by the thread pool.
197
+ #
198
+ # Returns the current number of busy threads, or +nil+ if shutting down.
199
+ #
197
200
  def wait_until_not_full
198
201
  @mutex.synchronize do
199
202
  while true
@@ -203,7 +206,8 @@ module Puma
203
206
  # is work queued that cannot be handled by waiting
204
207
  # threads, then accept more work until we would
205
208
  # spin up the max number of threads.
206
- return if @todo.size - @waiting < @max - @spawned
209
+ busy_threads = @spawned - @waiting + @todo.size
210
+ return busy_threads if @max > busy_threads
207
211
 
208
212
  @not_full.wait @mutex
209
213
  end
@@ -1,11 +1,6 @@
1
1
  # frozen_string_literal: true
2
- major, minor, patch = RUBY_VERSION.split('.').map { |v| v.to_i }
3
2
 
4
- if major == 1 && minor == 9 && patch == 3 && RUBY_PATCHLEVEL < 125
5
- require 'puma/rack/backports/uri/common_193'
6
- else
7
- require 'uri/common'
8
- end
3
+ require 'uri/common'
9
4
 
10
5
  module Puma
11
6
  module Util
@@ -47,11 +47,11 @@ do_start_one() {
47
47
  PIDFILE=$1/tmp/puma/pid
48
48
  if [ -e $PIDFILE ]; then
49
49
  PID=`cat $PIDFILE`
50
- # If the puma isn't running, run it, otherwise restart it.
50
+ # If the puma is running, restart it, otherwise run it.
51
51
  if ps -p $PID > /dev/null; then
52
- do_start_one_do $1
53
- else
54
52
  do_restart_one $1
53
+ else
54
+ do_start_one_do $1
55
55
  fi
56
56
  else
57
57
  do_start_one_do $1
@@ -106,8 +106,6 @@ do_stop_one() {
106
106
  if [ -e $PIDFILE ]; then
107
107
  PID=`cat $PIDFILE`
108
108
  if ps -p $PID > /dev/null; then
109
- log_daemon_msg "---> Puma $1 isn't running."
110
- else
111
109
  log_daemon_msg "---> About to kill PID `cat $PIDFILE`"
112
110
  if [ "$USE_LOCAL_BUNDLE" -eq 1 ]; then
113
111
  cd $1 && bundle exec pumactl --state $STATEFILE stop
@@ -116,6 +114,8 @@ do_stop_one() {
116
114
  fi
117
115
  # Many daemons don't delete their pidfiles when they exit.
118
116
  rm -f $PIDFILE $STATEFILE
117
+ else
118
+ log_daemon_msg "---> Puma $1 isn't running."
119
119
  fi
120
120
  else
121
121
  log_daemon_msg "---> No puma here..."
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: puma
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.12.6
4
+ version: 4.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Evan Phoenix
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-05-19 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2019-06-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: nio4r
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
13
27
  description: Puma is a simple, fast, threaded, and highly concurrent HTTP 1.1 server
14
28
  for Ruby/Rack applications. Puma is intended for use in both development and production
15
29
  environments. It's great for highly concurrent Ruby implementations such as Rubinius
@@ -51,6 +65,7 @@ files:
51
65
  - ext/puma_http11/mini_ssl.c
52
66
  - ext/puma_http11/org/jruby/puma/Http11.java
53
67
  - ext/puma_http11/org/jruby/puma/Http11Parser.java
68
+ - ext/puma_http11/org/jruby/puma/IOBuffer.java
54
69
  - ext/puma_http11/org/jruby/puma/MiniSSL.java
55
70
  - ext/puma_http11/puma_http11.c
56
71
  - lib/puma.rb
@@ -61,7 +76,6 @@ files:
61
76
  - lib/puma/client.rb
62
77
  - lib/puma/cluster.rb
63
78
  - lib/puma/commonlogger.rb
64
- - lib/puma/compat.rb
65
79
  - lib/puma/configuration.rb
66
80
  - lib/puma/const.rb
67
81
  - lib/puma/control_cli.rb
@@ -72,14 +86,12 @@ files:
72
86
  - lib/puma/dsl.rb
73
87
  - lib/puma/events.rb
74
88
  - lib/puma/io_buffer.rb
75
- - lib/puma/java_io_buffer.rb
76
89
  - lib/puma/jruby_restart.rb
77
90
  - lib/puma/launcher.rb
78
91
  - lib/puma/minissl.rb
79
92
  - lib/puma/null_io.rb
80
93
  - lib/puma/plugin.rb
81
94
  - lib/puma/plugin/tmp_restart.rb
82
- - lib/puma/rack/backports/uri/common_193.rb
83
95
  - lib/puma/rack/builder.rb
84
96
  - lib/puma/rack/urlmap.rb
85
97
  - lib/puma/rack_default.rb
@@ -1,14 +0,0 @@
1
- # Provides code to work properly on 1.8 and 1.9
2
-
3
- class String
4
- unless method_defined? :bytesize
5
- alias_method :bytesize, :size
6
- end
7
-
8
- unless method_defined? :byteslice
9
- def byteslice(*arg)
10
- enc = self.encoding
11
- self.dup.force_encoding(Encoding::ASCII_8BIT).slice(*arg).force_encoding(enc)
12
- end
13
- end
14
- end
@@ -1,47 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'java'
4
-
5
- # Conservative native JRuby/Java implementation of IOBuffer
6
- # backed by a ByteArrayOutputStream and conversion between
7
- # Ruby String and Java bytes
8
- module Puma
9
- class JavaIOBuffer < java.io.ByteArrayOutputStream
10
- field_reader :buf
11
- end
12
-
13
- class IOBuffer
14
- BUF_DEFAULT_SIZE = 4096
15
-
16
- def initialize
17
- @buf = JavaIOBuffer.new(BUF_DEFAULT_SIZE)
18
- end
19
-
20
- def reset
21
- @buf.reset
22
- end
23
-
24
- def <<(str)
25
- bytes = str.to_java_bytes
26
- @buf.write(bytes, 0, bytes.length)
27
- end
28
-
29
- def append(*strs)
30
- strs.each { |s| self << s; }
31
- end
32
-
33
- def to_s
34
- String.from_java_bytes @buf.to_byte_array
35
- end
36
-
37
- alias_method :to_str, :to_s
38
-
39
- def used
40
- @buf.size
41
- end
42
-
43
- def capacity
44
- @buf.buf.length
45
- end
46
- end
47
- end
@@ -1,33 +0,0 @@
1
- # :stopdoc:
2
-
3
- require 'uri/common'
4
-
5
- # Issue:
6
- # http://bugs.ruby-lang.org/issues/5925
7
- #
8
- # Relevant commit:
9
- # https://github.com/ruby/ruby/commit/edb7cdf1eabaff78dfa5ffedfbc2e91b29fa9ca1
10
-
11
-
12
- module URI
13
- begin
14
- 256.times do |i|
15
- TBLENCWWWCOMP_[i.chr] = '%%%02X' % i
16
- end
17
- TBLENCWWWCOMP_[' '] = '+'
18
- TBLENCWWWCOMP_.freeze
19
-
20
- 256.times do |i|
21
- h, l = i>>4, i&15
22
- TBLDECWWWCOMP_['%%%X%X' % [h, l]] = i.chr
23
- TBLDECWWWCOMP_['%%%x%X' % [h, l]] = i.chr
24
- TBLDECWWWCOMP_['%%%X%x' % [h, l]] = i.chr
25
- TBLDECWWWCOMP_['%%%x%x' % [h, l]] = i.chr
26
- end
27
- TBLDECWWWCOMP_['+'] = ' '
28
- TBLDECWWWCOMP_.freeze
29
- rescue Exception
30
- end
31
- end
32
-
33
- # :startdoc: