puma 2.16.0 → 3.11.4
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.
- checksums.yaml +5 -5
- data/{History.txt → History.md} +489 -70
- data/README.md +143 -174
- data/docs/architecture.md +36 -0
- data/{DEPLOYMENT.md → docs/deployment.md} +1 -1
- data/docs/images/puma-connection-flow-no-reactor.png +0 -0
- data/docs/images/puma-connection-flow.png +0 -0
- data/docs/images/puma-general-arch.png +0 -0
- data/docs/nginx.md +2 -2
- data/docs/plugins.md +28 -0
- data/docs/restart.md +39 -0
- data/docs/signals.md +56 -3
- data/docs/systemd.md +272 -0
- data/ext/puma_http11/extconf.rb +2 -0
- data/ext/puma_http11/http11_parser.c +291 -447
- data/ext/puma_http11/http11_parser.h +1 -0
- data/ext/puma_http11/http11_parser.java.rl +5 -5
- data/ext/puma_http11/http11_parser.rl +10 -9
- data/ext/puma_http11/http11_parser_common.rl +1 -1
- data/ext/puma_http11/io_buffer.c +8 -8
- data/ext/puma_http11/mini_ssl.c +64 -6
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +113 -131
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +9 -2
- data/ext/puma_http11/puma_http11.c +1 -0
- data/lib/puma/app/status.rb +9 -1
- data/lib/puma/binder.rb +90 -38
- data/lib/puma/cli.rb +134 -491
- data/lib/puma/client.rb +142 -4
- data/lib/puma/cluster.rb +132 -76
- data/lib/puma/commonlogger.rb +19 -20
- data/lib/puma/compat.rb +3 -7
- data/lib/puma/configuration.rb +206 -67
- data/lib/puma/const.rb +21 -31
- data/lib/puma/control_cli.rb +92 -103
- data/lib/puma/convenient.rb +23 -0
- data/lib/puma/daemon_ext.rb +6 -0
- data/lib/puma/detect.rb +10 -1
- data/lib/puma/dsl.rb +203 -45
- data/lib/puma/events.rb +22 -13
- data/lib/puma/io_buffer.rb +1 -1
- data/lib/puma/jruby_restart.rb +1 -2
- data/lib/puma/launcher.rb +431 -0
- data/lib/puma/minissl.rb +83 -4
- data/lib/puma/null_io.rb +19 -11
- data/lib/puma/plugin/tmp_restart.rb +34 -0
- data/lib/puma/plugin.rb +115 -0
- data/lib/puma/rack/backports/uri/common_193.rb +17 -13
- data/lib/puma/rack/builder.rb +3 -0
- data/lib/puma/rack/urlmap.rb +9 -8
- data/lib/puma/reactor.rb +18 -0
- data/lib/puma/runner.rb +43 -15
- data/lib/puma/server.rb +141 -35
- data/lib/puma/single.rb +16 -6
- data/lib/puma/state_file.rb +29 -0
- data/lib/puma/tcp_logger.rb +8 -1
- data/lib/puma/thread_pool.rb +60 -10
- data/lib/puma/util.rb +1 -5
- data/lib/puma.rb +13 -4
- data/lib/rack/handler/puma.rb +76 -29
- data/tools/jungle/README.md +12 -2
- data/tools/jungle/init.d/README.md +9 -2
- data/tools/jungle/init.d/puma +86 -59
- data/tools/jungle/init.d/run-puma +16 -1
- data/tools/jungle/rc.d/README.md +74 -0
- data/tools/jungle/rc.d/puma +61 -0
- data/tools/jungle/rc.d/puma.conf +10 -0
- data/tools/jungle/upstart/puma.conf +1 -1
- data/tools/trickletest.rb +1 -1
- metadata +28 -95
- data/COPYING +0 -55
- data/Gemfile +0 -13
- data/Manifest.txt +0 -74
- data/Rakefile +0 -158
- data/docs/config.md +0 -0
- data/lib/puma/capistrano.rb +0 -94
- data/lib/puma/rack/backports/uri/common_18.rb +0 -56
- data/lib/puma/rack/backports/uri/common_192.rb +0 -52
- data/puma.gemspec +0 -52
data/lib/puma/plugin.rb
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
module Puma
|
|
2
|
+
class UnknownPlugin < RuntimeError; end
|
|
3
|
+
|
|
4
|
+
class PluginLoader
|
|
5
|
+
def initialize
|
|
6
|
+
@instances = []
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def create(name)
|
|
10
|
+
if cls = Plugins.find(name)
|
|
11
|
+
plugin = cls.new(Plugin)
|
|
12
|
+
@instances << plugin
|
|
13
|
+
return plugin
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
raise UnknownPlugin, "File failed to register properly named plugin"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def fire_starts(launcher)
|
|
20
|
+
@instances.each do |i|
|
|
21
|
+
if i.respond_to? :start
|
|
22
|
+
i.start(launcher)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
class PluginRegistry
|
|
29
|
+
def initialize
|
|
30
|
+
@plugins = {}
|
|
31
|
+
@background = []
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def register(name, cls)
|
|
35
|
+
@plugins[name] = cls
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def find(name)
|
|
39
|
+
name = name.to_s
|
|
40
|
+
|
|
41
|
+
if cls = @plugins[name]
|
|
42
|
+
return cls
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
begin
|
|
46
|
+
require "puma/plugin/#{name}"
|
|
47
|
+
rescue LoadError
|
|
48
|
+
raise UnknownPlugin, "Unable to find plugin: #{name}"
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
if cls = @plugins[name]
|
|
52
|
+
return cls
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
raise UnknownPlugin, "file failed to register a plugin"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def add_background(blk)
|
|
59
|
+
@background << blk
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def fire_background
|
|
63
|
+
@background.each do |b|
|
|
64
|
+
Thread.new(&b)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
Plugins = PluginRegistry.new
|
|
70
|
+
|
|
71
|
+
class Plugin
|
|
72
|
+
# Matches
|
|
73
|
+
# "C:/Ruby22/lib/ruby/gems/2.2.0/gems/puma-3.0.1/lib/puma/plugin/tmp_restart.rb:3:in `<top (required)>'"
|
|
74
|
+
# AS
|
|
75
|
+
# C:/Ruby22/lib/ruby/gems/2.2.0/gems/puma-3.0.1/lib/puma/plugin/tmp_restart.rb
|
|
76
|
+
CALLER_FILE = /
|
|
77
|
+
\A # start of string
|
|
78
|
+
.+ # file path (one or more characters)
|
|
79
|
+
(?= # stop previous match when
|
|
80
|
+
:\d+ # a colon is followed by one or more digits
|
|
81
|
+
:in # followed by a colon followed by in
|
|
82
|
+
)
|
|
83
|
+
/x
|
|
84
|
+
|
|
85
|
+
def self.extract_name(ary)
|
|
86
|
+
path = ary.first[CALLER_FILE]
|
|
87
|
+
|
|
88
|
+
m = %r!puma/plugin/([^/]*)\.rb$!.match(path)
|
|
89
|
+
return m[1]
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def self.create(&blk)
|
|
93
|
+
name = extract_name(caller)
|
|
94
|
+
|
|
95
|
+
cls = Class.new(self)
|
|
96
|
+
|
|
97
|
+
cls.class_eval(&blk)
|
|
98
|
+
|
|
99
|
+
Plugins.register name, cls
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def initialize(loader)
|
|
103
|
+
@loader = loader
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def in_background(&blk)
|
|
107
|
+
Plugins.add_background blk
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def workers_supported?
|
|
111
|
+
return false if Puma.jruby? || Puma.windows?
|
|
112
|
+
true
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
@@ -8,22 +8,26 @@ require 'uri/common'
|
|
|
8
8
|
# Relevant commit:
|
|
9
9
|
# https://github.com/ruby/ruby/commit/edb7cdf1eabaff78dfa5ffedfbc2e91b29fa9ca1
|
|
10
10
|
|
|
11
|
+
|
|
11
12
|
module URI
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
begin
|
|
14
|
+
256.times do |i|
|
|
15
|
+
TBLENCWWWCOMP_[i.chr] = '%%%02X' % i
|
|
16
|
+
end
|
|
17
|
+
TBLENCWWWCOMP_[' '] = '+'
|
|
18
|
+
TBLENCWWWCOMP_.freeze
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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
|
|
24
30
|
end
|
|
25
|
-
TBLDECWWWCOMP_['+'] = ' '
|
|
26
|
-
TBLDECWWWCOMP_.freeze
|
|
27
31
|
end
|
|
28
32
|
|
|
29
33
|
# :startdoc:
|
data/lib/puma/rack/builder.rb
CHANGED
data/lib/puma/rack/urlmap.rb
CHANGED
|
@@ -43,15 +43,17 @@ module Puma::Rack
|
|
|
43
43
|
def call(env)
|
|
44
44
|
path = env['PATH_INFO']
|
|
45
45
|
script_name = env['SCRIPT_NAME']
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
http_host = env['HTTP_HOST']
|
|
47
|
+
server_name = env['SERVER_NAME']
|
|
48
|
+
server_port = env['SERVER_PORT']
|
|
49
|
+
|
|
50
|
+
is_same_server = casecmp?(http_host, server_name) ||
|
|
51
|
+
casecmp?(http_host, "#{server_name}:#{server_port}")
|
|
49
52
|
|
|
50
53
|
@mapping.each do |host, location, match, app|
|
|
51
|
-
unless casecmp?(
|
|
52
|
-
|| casecmp?(
|
|
53
|
-
|| (!host &&
|
|
54
|
-
casecmp?(hHost, sName+':'+sPort)))
|
|
54
|
+
unless casecmp?(http_host, host) \
|
|
55
|
+
|| casecmp?(server_name, host) \
|
|
56
|
+
|| (!host && is_same_server)
|
|
55
57
|
next
|
|
56
58
|
end
|
|
57
59
|
|
|
@@ -87,4 +89,3 @@ module Puma::Rack
|
|
|
87
89
|
end
|
|
88
90
|
end
|
|
89
91
|
end
|
|
90
|
-
|
data/lib/puma/reactor.rb
CHANGED
|
@@ -28,6 +28,7 @@ module Puma
|
|
|
28
28
|
begin
|
|
29
29
|
ready = IO.select sockets, nil, nil, @sleep_for
|
|
30
30
|
rescue IOError => e
|
|
31
|
+
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
|
|
31
32
|
if sockets.any? { |socket| socket.closed? }
|
|
32
33
|
STDERR.puts "Error in select: #{e.message} (#{e.class})"
|
|
33
34
|
STDERR.puts e.backtrace
|
|
@@ -75,8 +76,19 @@ module Puma
|
|
|
75
76
|
sockets.delete c
|
|
76
77
|
end
|
|
77
78
|
|
|
79
|
+
# Don't report these to the lowlevel_error handler, otherwise
|
|
80
|
+
# will be flooding them with errors when persistent connections
|
|
81
|
+
# are closed.
|
|
82
|
+
rescue ConnectionError
|
|
83
|
+
c.write_500
|
|
84
|
+
c.close
|
|
85
|
+
|
|
86
|
+
sockets.delete c
|
|
87
|
+
|
|
78
88
|
# SSL handshake failure
|
|
79
89
|
rescue MiniSSL::SSLError => e
|
|
90
|
+
@server.lowlevel_error(e, c.env)
|
|
91
|
+
|
|
80
92
|
ssl_socket = c.io
|
|
81
93
|
addr = ssl_socket.peeraddr.last
|
|
82
94
|
cert = ssl_socket.peercert
|
|
@@ -88,6 +100,8 @@ module Puma
|
|
|
88
100
|
|
|
89
101
|
# The client doesn't know HTTP well
|
|
90
102
|
rescue HttpParserError => e
|
|
103
|
+
@server.lowlevel_error(e, c.env)
|
|
104
|
+
|
|
91
105
|
c.write_400
|
|
92
106
|
c.close
|
|
93
107
|
|
|
@@ -95,6 +109,8 @@ module Puma
|
|
|
95
109
|
|
|
96
110
|
@events.parse_error @server, c.env, e
|
|
97
111
|
rescue StandardError => e
|
|
112
|
+
@server.lowlevel_error(e, c.env)
|
|
113
|
+
|
|
98
114
|
c.write_500
|
|
99
115
|
c.close
|
|
100
116
|
|
|
@@ -180,6 +196,7 @@ module Puma
|
|
|
180
196
|
begin
|
|
181
197
|
@trigger << "c"
|
|
182
198
|
rescue IOError
|
|
199
|
+
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
|
|
183
200
|
end
|
|
184
201
|
end
|
|
185
202
|
|
|
@@ -187,6 +204,7 @@ module Puma
|
|
|
187
204
|
begin
|
|
188
205
|
@trigger << "!"
|
|
189
206
|
rescue IOError
|
|
207
|
+
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
|
|
190
208
|
end
|
|
191
209
|
|
|
192
210
|
@thread.join
|
data/lib/puma/runner.rb
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
+
require 'puma/server'
|
|
2
|
+
require 'puma/const'
|
|
3
|
+
|
|
1
4
|
module Puma
|
|
2
5
|
class Runner
|
|
3
|
-
def initialize(cli)
|
|
4
|
-
@
|
|
6
|
+
def initialize(cli, events)
|
|
7
|
+
@launcher = cli
|
|
8
|
+
@events = events
|
|
5
9
|
@options = cli.options
|
|
6
10
|
@app = nil
|
|
7
11
|
@control = nil
|
|
@@ -16,15 +20,19 @@ module Puma
|
|
|
16
20
|
end
|
|
17
21
|
|
|
18
22
|
def log(str)
|
|
19
|
-
@
|
|
23
|
+
@events.log str
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def before_restart
|
|
27
|
+
@control.stop(true) if @control
|
|
20
28
|
end
|
|
21
29
|
|
|
22
30
|
def error(str)
|
|
23
|
-
@
|
|
31
|
+
@events.error str
|
|
24
32
|
end
|
|
25
33
|
|
|
26
|
-
def
|
|
27
|
-
@
|
|
34
|
+
def debug(str)
|
|
35
|
+
@events.log "- #{str}" if @options[:debug]
|
|
28
36
|
end
|
|
29
37
|
|
|
30
38
|
def start_control
|
|
@@ -35,13 +43,13 @@ module Puma
|
|
|
35
43
|
|
|
36
44
|
uri = URI.parse str
|
|
37
45
|
|
|
38
|
-
app = Puma::App::Status.new @
|
|
46
|
+
app = Puma::App::Status.new @launcher
|
|
39
47
|
|
|
40
48
|
if token = @options[:control_auth_token]
|
|
41
49
|
app.auth_token = token unless token.empty? or token == :none
|
|
42
50
|
end
|
|
43
51
|
|
|
44
|
-
control = Puma::Server.new app, @
|
|
52
|
+
control = Puma::Server.new app, @launcher.events
|
|
45
53
|
control.min_threads = 0
|
|
46
54
|
control.max_threads = 1
|
|
47
55
|
|
|
@@ -67,7 +75,11 @@ module Puma
|
|
|
67
75
|
if !defined?(RUBY_ENGINE) || RUBY_ENGINE == "ruby"
|
|
68
76
|
"ruby #{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}"
|
|
69
77
|
else
|
|
70
|
-
|
|
78
|
+
if defined?(RUBY_ENGINE_VERSION)
|
|
79
|
+
"#{RUBY_ENGINE} #{RUBY_ENGINE_VERSION} - ruby #{RUBY_VERSION}"
|
|
80
|
+
else
|
|
81
|
+
"#{RUBY_ENGINE} #{RUBY_VERSION}"
|
|
82
|
+
end
|
|
71
83
|
end
|
|
72
84
|
end
|
|
73
85
|
|
|
@@ -85,18 +97,30 @@ module Puma
|
|
|
85
97
|
end
|
|
86
98
|
end
|
|
87
99
|
|
|
100
|
+
def redirected_io?
|
|
101
|
+
@options[:redirect_stdout] || @options[:redirect_stderr]
|
|
102
|
+
end
|
|
103
|
+
|
|
88
104
|
def redirect_io
|
|
89
105
|
stdout = @options[:redirect_stdout]
|
|
90
106
|
stderr = @options[:redirect_stderr]
|
|
91
107
|
append = @options[:redirect_append]
|
|
92
108
|
|
|
93
109
|
if stdout
|
|
110
|
+
unless Dir.exist?(File.dirname(stdout))
|
|
111
|
+
raise "Cannot redirect STDOUT to #{stdout}"
|
|
112
|
+
end
|
|
113
|
+
|
|
94
114
|
STDOUT.reopen stdout, (append ? "a" : "w")
|
|
95
115
|
STDOUT.sync = true
|
|
96
116
|
STDOUT.puts "=== puma startup: #{Time.now} ==="
|
|
97
117
|
end
|
|
98
118
|
|
|
99
119
|
if stderr
|
|
120
|
+
unless Dir.exist?(File.dirname(stderr))
|
|
121
|
+
raise "Cannot redirect STDERR to #{stderr}"
|
|
122
|
+
end
|
|
123
|
+
|
|
100
124
|
STDERR.reopen stderr, (append ? "a" : "w")
|
|
101
125
|
STDERR.sync = true
|
|
102
126
|
STDERR.puts "=== puma startup: #{Time.now} ==="
|
|
@@ -104,39 +128,43 @@ module Puma
|
|
|
104
128
|
end
|
|
105
129
|
|
|
106
130
|
def load_and_bind
|
|
107
|
-
unless @
|
|
131
|
+
unless @launcher.config.app_configured?
|
|
108
132
|
error "No application configured, nothing to run"
|
|
109
133
|
exit 1
|
|
110
134
|
end
|
|
111
135
|
|
|
112
136
|
# Load the app before we daemonize.
|
|
113
137
|
begin
|
|
114
|
-
@app = @
|
|
138
|
+
@app = @launcher.config.app
|
|
115
139
|
rescue Exception => e
|
|
116
140
|
log "! Unable to load application: #{e.class}: #{e.message}"
|
|
117
141
|
raise e
|
|
118
142
|
end
|
|
119
143
|
|
|
120
|
-
@
|
|
144
|
+
@launcher.binder.parse @options[:binds], self
|
|
121
145
|
end
|
|
122
146
|
|
|
123
147
|
def app
|
|
124
|
-
@app ||= @
|
|
148
|
+
@app ||= @launcher.config.app
|
|
125
149
|
end
|
|
126
150
|
|
|
127
151
|
def start_server
|
|
128
152
|
min_t = @options[:min_threads]
|
|
129
153
|
max_t = @options[:max_threads]
|
|
130
154
|
|
|
131
|
-
server = Puma::Server.new app, @
|
|
155
|
+
server = Puma::Server.new app, @launcher.events, @options
|
|
132
156
|
server.min_threads = min_t
|
|
133
157
|
server.max_threads = max_t
|
|
134
|
-
server.inherit_binder @
|
|
158
|
+
server.inherit_binder @launcher.binder
|
|
135
159
|
|
|
136
160
|
if @options[:mode] == :tcp
|
|
137
161
|
server.tcp_mode!
|
|
138
162
|
end
|
|
139
163
|
|
|
164
|
+
if @options[:early_hints]
|
|
165
|
+
server.early_hints = true
|
|
166
|
+
end
|
|
167
|
+
|
|
140
168
|
unless development?
|
|
141
169
|
server.leak_stack_on_error = false
|
|
142
170
|
end
|