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.
Files changed (78) hide show
  1. checksums.yaml +5 -5
  2. data/{History.txt → History.md} +489 -70
  3. data/README.md +143 -174
  4. data/docs/architecture.md +36 -0
  5. data/{DEPLOYMENT.md → docs/deployment.md} +1 -1
  6. data/docs/images/puma-connection-flow-no-reactor.png +0 -0
  7. data/docs/images/puma-connection-flow.png +0 -0
  8. data/docs/images/puma-general-arch.png +0 -0
  9. data/docs/nginx.md +2 -2
  10. data/docs/plugins.md +28 -0
  11. data/docs/restart.md +39 -0
  12. data/docs/signals.md +56 -3
  13. data/docs/systemd.md +272 -0
  14. data/ext/puma_http11/extconf.rb +2 -0
  15. data/ext/puma_http11/http11_parser.c +291 -447
  16. data/ext/puma_http11/http11_parser.h +1 -0
  17. data/ext/puma_http11/http11_parser.java.rl +5 -5
  18. data/ext/puma_http11/http11_parser.rl +10 -9
  19. data/ext/puma_http11/http11_parser_common.rl +1 -1
  20. data/ext/puma_http11/io_buffer.c +8 -8
  21. data/ext/puma_http11/mini_ssl.c +64 -6
  22. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +113 -131
  23. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +9 -2
  24. data/ext/puma_http11/puma_http11.c +1 -0
  25. data/lib/puma/app/status.rb +9 -1
  26. data/lib/puma/binder.rb +90 -38
  27. data/lib/puma/cli.rb +134 -491
  28. data/lib/puma/client.rb +142 -4
  29. data/lib/puma/cluster.rb +132 -76
  30. data/lib/puma/commonlogger.rb +19 -20
  31. data/lib/puma/compat.rb +3 -7
  32. data/lib/puma/configuration.rb +206 -67
  33. data/lib/puma/const.rb +21 -31
  34. data/lib/puma/control_cli.rb +92 -103
  35. data/lib/puma/convenient.rb +23 -0
  36. data/lib/puma/daemon_ext.rb +6 -0
  37. data/lib/puma/detect.rb +10 -1
  38. data/lib/puma/dsl.rb +203 -45
  39. data/lib/puma/events.rb +22 -13
  40. data/lib/puma/io_buffer.rb +1 -1
  41. data/lib/puma/jruby_restart.rb +1 -2
  42. data/lib/puma/launcher.rb +431 -0
  43. data/lib/puma/minissl.rb +83 -4
  44. data/lib/puma/null_io.rb +19 -11
  45. data/lib/puma/plugin/tmp_restart.rb +34 -0
  46. data/lib/puma/plugin.rb +115 -0
  47. data/lib/puma/rack/backports/uri/common_193.rb +17 -13
  48. data/lib/puma/rack/builder.rb +3 -0
  49. data/lib/puma/rack/urlmap.rb +9 -8
  50. data/lib/puma/reactor.rb +18 -0
  51. data/lib/puma/runner.rb +43 -15
  52. data/lib/puma/server.rb +141 -35
  53. data/lib/puma/single.rb +16 -6
  54. data/lib/puma/state_file.rb +29 -0
  55. data/lib/puma/tcp_logger.rb +8 -1
  56. data/lib/puma/thread_pool.rb +60 -10
  57. data/lib/puma/util.rb +1 -5
  58. data/lib/puma.rb +13 -4
  59. data/lib/rack/handler/puma.rb +76 -29
  60. data/tools/jungle/README.md +12 -2
  61. data/tools/jungle/init.d/README.md +9 -2
  62. data/tools/jungle/init.d/puma +86 -59
  63. data/tools/jungle/init.d/run-puma +16 -1
  64. data/tools/jungle/rc.d/README.md +74 -0
  65. data/tools/jungle/rc.d/puma +61 -0
  66. data/tools/jungle/rc.d/puma.conf +10 -0
  67. data/tools/jungle/upstart/puma.conf +1 -1
  68. data/tools/trickletest.rb +1 -1
  69. metadata +28 -95
  70. data/COPYING +0 -55
  71. data/Gemfile +0 -13
  72. data/Manifest.txt +0 -74
  73. data/Rakefile +0 -158
  74. data/docs/config.md +0 -0
  75. data/lib/puma/capistrano.rb +0 -94
  76. data/lib/puma/rack/backports/uri/common_18.rb +0 -56
  77. data/lib/puma/rack/backports/uri/common_192.rb +0 -52
  78. data/puma.gemspec +0 -52
data/lib/puma/binder.rb CHANGED
@@ -1,4 +1,8 @@
1
+ require 'uri'
2
+ require 'socket'
3
+
1
4
  require 'puma/const'
5
+ require 'puma/util'
2
6
 
3
7
  module Puma
4
8
  class Binder
@@ -10,6 +14,7 @@ module Puma
10
14
  @events = events
11
15
  @listeners = []
12
16
  @inherited_fds = {}
17
+ @activated_sockets = {}
13
18
  @unix_paths = []
14
19
 
15
20
  @proto_env = {
@@ -21,13 +26,13 @@ module Puma
21
26
  "SCRIPT_NAME".freeze => ENV['SCRIPT_NAME'] || "",
22
27
 
23
28
  # I'd like to set a default CONTENT_TYPE here but some things
24
- # depend on their not being a default set and infering
29
+ # depend on their not being a default set and inferring
25
30
  # it from the content. And so if i set it here, it won't
26
31
  # infer properly.
27
32
 
28
33
  "QUERY_STRING".freeze => "",
29
34
  SERVER_PROTOCOL => HTTP_11,
30
- SERVER_SOFTWARE => PUMA_VERSION,
35
+ SERVER_SOFTWARE => PUMA_SERVER_STRING,
31
36
  GATEWAY_INTERFACE => CGI_VER
32
37
  }
33
38
 
@@ -54,24 +59,23 @@ module Puma
54
59
  fd, url = v.split(":", 2)
55
60
  @inherited_fds[url] = fd.to_i
56
61
  remove << k
57
- end
58
- if k =~ /LISTEN_FDS/ && ENV['LISTEN_PID'].to_i == $$
62
+ elsif k == 'LISTEN_FDS' && ENV['LISTEN_PID'].to_i == $$
59
63
  v.to_i.times do |num|
60
64
  fd = num + 3
61
65
  sock = TCPServer.for_fd(fd)
62
66
  begin
63
- url = "unix://" + Socket.unpack_sockaddr_un(sock.getsockname)
67
+ key = [ :unix, Socket.unpack_sockaddr_un(sock.getsockname) ]
64
68
  rescue ArgumentError
65
69
  port, addr = Socket.unpack_sockaddr_in(sock.getsockname)
66
70
  if addr =~ /\:/
67
71
  addr = "[#{addr}]"
68
72
  end
69
- url = "tcp://#{addr}:#{port}"
73
+ key = [ :tcp, addr, port ]
70
74
  end
71
- @inherited_fds[url] = sock
75
+ @activated_sockets[key] = sock
76
+ @events.debug "Registered #{key.join ':'} for activation from LISTEN_FDS"
72
77
  end
73
- ENV.delete k
74
- ENV.delete 'LISTEN_PID'
78
+ remove << k << 'LISTEN_PID'
75
79
  end
76
80
  end
77
81
 
@@ -88,6 +92,9 @@ module Puma
88
92
  if fd = @inherited_fds.delete(str)
89
93
  logger.log "* Inherited #{str}"
90
94
  io = inherit_tcp_listener uri.host, uri.port, fd
95
+ elsif sock = @activated_sockets.delete([ :tcp, uri.host, uri.port ])
96
+ logger.log "* Activated #{str}"
97
+ io = inherit_tcp_listener uri.host, uri.port, sock
91
98
  else
92
99
  params = Util.parse_query uri.query
93
100
 
@@ -98,18 +105,22 @@ module Puma
98
105
  io = add_tcp_listener uri.host, uri.port, opt, bak
99
106
  end
100
107
 
101
- @listeners << [str, io]
108
+ @listeners << [str, io] if io
102
109
  when "unix"
103
110
  path = "#{uri.host}#{uri.path}".gsub("%20", " ")
104
111
 
105
112
  if fd = @inherited_fds.delete(str)
106
113
  logger.log "* Inherited #{str}"
107
114
  io = inherit_unix_listener path, fd
115
+ elsif sock = @activated_sockets.delete([ :unix, path ])
116
+ logger.log "* Activated #{str}"
117
+ io = inherit_unix_listener path, sock
108
118
  else
109
119
  logger.log "* Listening on #{str}"
110
120
 
111
121
  umask = nil
112
122
  mode = nil
123
+ backlog = 1024
113
124
 
114
125
  if uri.query
115
126
  params = Util.parse_query uri.query
@@ -121,18 +132,22 @@ module Puma
121
132
  if u = params['mode']
122
133
  mode = Integer('0'+u)
123
134
  end
135
+
136
+ if u = params['backlog']
137
+ backlog = Integer(u)
138
+ end
124
139
  end
125
140
 
126
- io = add_unix_listener path, umask, mode
141
+ io = add_unix_listener path, umask, mode, backlog
127
142
  end
128
143
 
129
144
  @listeners << [str, io]
130
145
  when "ssl"
131
- MiniSSL.check
132
-
133
146
  params = Util.parse_query uri.query
134
147
  require 'puma/minissl'
135
148
 
149
+ MiniSSL.check
150
+
136
151
  ctx = MiniSSL::Context.new
137
152
 
138
153
  if defined?(JRUBY_VERSION)
@@ -165,33 +180,36 @@ module Puma
165
180
  @events.error "Please specify the SSL ca via 'ca='"
166
181
  end
167
182
  end
168
-
183
+
169
184
  ctx.ca = params['ca'] if params['ca']
185
+ end
170
186
 
171
- if params['verify_mode']
172
- ctx.verify_mode = case params['verify_mode']
173
- when "peer"
174
- MiniSSL::VERIFY_PEER
175
- when "force_peer"
176
- MiniSSL::VERIFY_PEER | MiniSSL::VERIFY_FAIL_IF_NO_PEER_CERT
177
- when "none"
178
- MiniSSL::VERIFY_NONE
179
- else
180
- @events.error "Please specify a valid verify_mode="
181
- MiniSSL::VERIFY_NONE
182
- end
183
- end
187
+ if params['verify_mode']
188
+ ctx.verify_mode = case params['verify_mode']
189
+ when "peer"
190
+ MiniSSL::VERIFY_PEER
191
+ when "force_peer"
192
+ MiniSSL::VERIFY_PEER | MiniSSL::VERIFY_FAIL_IF_NO_PEER_CERT
193
+ when "none"
194
+ MiniSSL::VERIFY_NONE
195
+ else
196
+ @events.error "Please specify a valid verify_mode="
197
+ MiniSSL::VERIFY_NONE
198
+ end
184
199
  end
185
200
 
186
201
  if fd = @inherited_fds.delete(str)
187
202
  logger.log "* Inherited #{str}"
188
- io = inherited_ssl_listener fd, ctx
203
+ io = inherit_ssl_listener fd, ctx
204
+ elsif sock = @activated_sockets.delete([ :tcp, uri.host, uri.port ])
205
+ logger.log "* Activated #{str}"
206
+ io = inherit_ssl_listener sock, ctx
189
207
  else
190
208
  logger.log "* Listening on #{str}"
191
209
  io = add_ssl_listener uri.host, uri.port, ctx
192
210
  end
193
211
 
194
- @listeners << [str, io]
212
+ @listeners << [str, io] if io
195
213
  else
196
214
  logger.error "Invalid URI: #{str}"
197
215
  end
@@ -203,12 +221,7 @@ module Puma
203
221
  logger.log "* Closing unused inherited connection: #{str}"
204
222
 
205
223
  begin
206
- if fd.kind_of? TCPServer
207
- fd.close
208
- else
209
- IO.for_fd(fd).close
210
- end
211
-
224
+ IO.for_fd(fd).close
212
225
  rescue SystemCallError
213
226
  end
214
227
 
@@ -220,6 +233,22 @@ module Puma
220
233
  end
221
234
  end
222
235
 
236
+ # Also close any unused activated sockets
237
+ @activated_sockets.each do |key, sock|
238
+ logger.log "* Closing unused activated socket: #{key.join ':'}"
239
+ begin
240
+ sock.close
241
+ rescue SystemCallError
242
+ end
243
+ # We have to unlink a unix socket path that's not being used
244
+ File.unlink key[1] if key[0] == :unix
245
+ end
246
+ end
247
+
248
+ def loopback_addresses
249
+ Socket.ip_address_list.select do |addrinfo|
250
+ addrinfo.ipv6_loopback? || addrinfo.ipv4_loopback?
251
+ end.map { |addrinfo| addrinfo.ip_address }.uniq
223
252
  end
224
253
 
225
254
  # Tell the server to listen on host +host+, port +port+.
@@ -230,6 +259,13 @@ module Puma
230
259
  # allow to accumulate before returning connection refused.
231
260
  #
232
261
  def add_tcp_listener(host, port, optimize_for_latency=true, backlog=1024)
262
+ if host == "localhost"
263
+ loopback_addresses.each do |addr|
264
+ add_tcp_listener addr, port, optimize_for_latency, backlog
265
+ end
266
+ return
267
+ end
268
+
233
269
  host = host[1..-2] if host and host[0..0] == '['
234
270
  s = TCPServer.new(host, port)
235
271
  if optimize_for_latency
@@ -237,10 +273,14 @@ module Puma
237
273
  end
238
274
  s.setsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR, true)
239
275
  s.listen backlog
276
+ @connected_port = s.addr[1]
277
+
240
278
  @ios << s
241
279
  s
242
280
  end
243
281
 
282
+ attr_reader :connected_port
283
+
244
284
  def inherit_tcp_listener(host, port, fd)
245
285
  if fd.kind_of? TCPServer
246
286
  s = fd
@@ -258,6 +298,13 @@ module Puma
258
298
 
259
299
  MiniSSL.check
260
300
 
301
+ if host == "localhost"
302
+ loopback_addresses.each do |addr|
303
+ add_ssl_listener addr, port, ctx, optimize_for_latency, backlog
304
+ end
305
+ return
306
+ end
307
+
261
308
  host = host[1..-2] if host[0..0] == '['
262
309
  s = TCPServer.new(host, port)
263
310
  if optimize_for_latency
@@ -275,11 +322,15 @@ module Puma
275
322
  s
276
323
  end
277
324
 
278
- def inherited_ssl_listener(fd, ctx)
325
+ def inherit_ssl_listener(fd, ctx)
279
326
  require 'puma/minissl'
280
327
  MiniSSL.check
281
328
 
282
- s = TCPServer.for_fd(fd)
329
+ if fd.kind_of? TCPServer
330
+ s = fd
331
+ else
332
+ s = TCPServer.for_fd(fd)
333
+ end
283
334
  ssl = MiniSSL::Server.new(s, ctx)
284
335
 
285
336
  env = @proto_env.dup
@@ -293,7 +344,7 @@ module Puma
293
344
 
294
345
  # Tell the server to listen on +path+ as a UNIX domain socket.
295
346
  #
296
- def add_unix_listener(path, umask=nil, mode=nil)
347
+ def add_unix_listener(path, umask=nil, mode=nil, backlog=1024)
297
348
  @unix_paths << path
298
349
 
299
350
  # Let anyone connect by default
@@ -314,6 +365,7 @@ module Puma
314
365
  end
315
366
 
316
367
  s = UNIXServer.new(path)
368
+ s.listen backlog
317
369
  @ios << s
318
370
  ensure
319
371
  File.umask old_mask