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
@@ -1,20 +1,27 @@
1
1
  require 'optparse'
2
+ require 'puma/state_file'
2
3
  require 'puma/const'
4
+ require 'puma/detect'
3
5
  require 'puma/configuration'
4
- require 'yaml'
5
6
  require 'uri'
6
7
  require 'socket'
8
+
7
9
  module Puma
8
10
  class ControlCLI
9
11
 
10
- COMMANDS = %w{halt restart phased-restart start stats status stop reload-worker-directory}
11
-
12
- def is_windows?
13
- RUBY_PLATFORM =~ /(win|w)32$/ ? true : false
14
- end
12
+ COMMANDS = %w{halt restart phased-restart start stats status stop reload-worker-directory gc gc-stats}
15
13
 
16
14
  def initialize(argv, stdout=STDOUT, stderr=STDERR)
17
- @argv = argv
15
+ @state = nil
16
+ @quiet = false
17
+ @pidfile = nil
18
+ @pid = nil
19
+ @control_url = nil
20
+ @control_auth_token = nil
21
+ @config_file = nil
22
+ @command = nil
23
+
24
+ @argv = argv.dup
18
25
  @stdout = stdout
19
26
  @stderr = stderr
20
27
  @cli_options = {}
@@ -23,31 +30,31 @@ module Puma
23
30
  o.banner = "Usage: pumactl (-p PID | -P pidfile | -S status_file | -C url -T token | -F config.rb) (#{COMMANDS.join("|")})"
24
31
 
25
32
  o.on "-S", "--state PATH", "Where the state file to use is" do |arg|
26
- @cli_options[:state] = arg
33
+ @state = arg
27
34
  end
28
35
 
29
36
  o.on "-Q", "--quiet", "Not display messages" do |arg|
30
- @cli_options[:quiet_flag] = true
37
+ @quiet = true
31
38
  end
32
39
 
33
40
  o.on "-P", "--pidfile PATH", "Pid file" do |arg|
34
- @cli_options[:pidfile] = arg
41
+ @pidfile = arg
35
42
  end
36
43
 
37
44
  o.on "-p", "--pid PID", "Pid" do |arg|
38
- @cli_options[:pid] = arg.to_i
45
+ @pid = arg.to_i
39
46
  end
40
47
 
41
48
  o.on "-C", "--control-url URL", "The bind url to use for the control server" do |arg|
42
- @cli_options[:control_url] = arg
49
+ @control_url = arg
43
50
  end
44
51
 
45
52
  o.on "-T", "--control-token TOKEN", "The token to use as authentication for the control server" do |arg|
46
- @cli_options[:control_auth_token] = arg
53
+ @control_auth_token = arg
47
54
  end
48
55
 
49
56
  o.on "-F", "--config-file PATH", "Puma config script" do |arg|
50
- @cli_options[:config_file] = arg
57
+ @config_file = arg
51
58
  end
52
59
 
53
60
  o.on_tail("-H", "--help", "Show this message") do
@@ -62,80 +69,64 @@ module Puma
62
69
  end
63
70
 
64
71
  opts.order!(argv) { |a| opts.terminate a }
72
+ opts.parse!
65
73
 
66
- command = argv.shift
67
- @cli_options[:command] = command if command
68
-
69
- @options = nil
74
+ @command = argv.shift
70
75
 
71
- unless @cli_options[:config_file] == '-'
72
- if @cli_options[:config_file].nil? and File.exist?('config/puma.rb')
73
- @cli_options[:config_file] = 'config/puma.rb'
76
+ unless @config_file == '-'
77
+ if @config_file.nil? and File.exist?('config/puma.rb')
78
+ @config_file = 'config/puma.rb'
74
79
  end
75
80
 
76
- if @cli_options[:config_file]
77
- config = Puma::Configuration.new(@cli_options)
81
+ if @config_file
82
+ config = Puma::Configuration.new({ config_files: [@config_file] }, {})
78
83
  config.load
79
- @options = config.options
84
+ @state ||= config.options[:state]
85
+ @control_url ||= config.options[:control_url]
86
+ @control_auth_token ||= config.options[:control_auth_token]
87
+ @pidfile ||= config.options[:pidfile]
80
88
  end
81
89
  end
82
90
 
83
- @options ||= @cli_options
84
-
85
91
  # check present of command
86
- unless @options[:command]
92
+ unless @command
87
93
  raise "Available commands: #{COMMANDS.join(", ")}"
88
94
  end
89
95
 
90
- unless COMMANDS.include? @options[:command]
91
- raise "Invalid command: #{@options[:command]}"
96
+ unless COMMANDS.include? @command
97
+ raise "Invalid command: #{@command}"
92
98
  end
93
99
 
94
100
  rescue => e
95
101
  @stdout.puts e.message
102
+ @stdout.puts e.backtrace
96
103
  exit 1
97
104
  end
98
105
 
99
106
  def message(msg)
100
- @stdout.puts msg unless @options[:quiet_flag]
107
+ @stdout.puts msg unless @quiet
101
108
  end
102
109
 
103
110
  def prepare_configuration
104
- if @options.has_key? :state
105
- unless File.exist? @options[:state]
106
- raise "Status file not found: #{@options[:state]}"
111
+ if @state
112
+ unless File.exist? @state
113
+ raise "State file not found: #{@state}"
107
114
  end
108
115
 
109
- status = YAML.load File.read(@options[:state])
110
-
111
- if status.kind_of?(Hash) && status.has_key?("config")
112
-
113
- conf = status["config"]
114
-
115
- # get control_url
116
- if url = conf.options[:control_url]
117
- @options[:control_url] = url
118
- end
116
+ sf = Puma::StateFile.new
117
+ sf.load @state
119
118
 
120
- # get control_auth_token
121
- if token = conf.options[:control_auth_token]
122
- @options[:control_auth_token] = token
123
- end
124
-
125
- # get pid
126
- @options[:pid] = status["pid"].to_i
127
- else
128
- raise "Invalid status file: #{@options[:state]}"
129
- end
130
-
131
- elsif @options.has_key? :pidfile
119
+ @control_url = sf.control_url
120
+ @control_auth_token = sf.control_auth_token
121
+ @pid = sf.pid
122
+ elsif @pidfile
132
123
  # get pid from pid_file
133
- @options[:pid] = File.open(@options[:pidfile]).gets.to_i
124
+ @pid = File.open(@pidfile).gets.to_i
134
125
  end
135
126
  end
136
127
 
137
128
  def send_request
138
- uri = URI.parse @options[:control_url]
129
+ uri = URI.parse @control_url
139
130
 
140
131
  # create server object by scheme
141
132
  @server = case uri.scheme
@@ -147,13 +138,13 @@ module Puma
147
138
  raise "Invalid scheme: #{uri.scheme}"
148
139
  end
149
140
 
150
- if @options[:command] == "status"
141
+ if @command == "status"
151
142
  message "Puma is started"
152
143
  else
153
- url = "/#{@options[:command]}"
144
+ url = "/#{@command}"
154
145
 
155
- if @options.has_key?(:control_auth_token)
156
- url = url + "?token=#{@options[:control_auth_token]}"
146
+ if @control_auth_token
147
+ url = url + "?token=#{@control_auth_token}"
157
148
  end
158
149
 
159
150
  @server << "GET #{url} HTTP/1.0\r\n\r\n"
@@ -178,71 +169,70 @@ module Puma
178
169
  raise "Bad response from server: #{@code}"
179
170
  end
180
171
 
181
- message "Command #{@options[:command]} sent success"
182
- message response.last if @options[:command] == "stats"
172
+ message "Command #{@command} sent success"
173
+ message response.last if @command == "stats" || @command == "gc-stats"
183
174
  end
184
175
 
185
176
  @server.close
186
177
  end
187
178
 
188
179
  def send_signal
189
- unless pid = @options[:pid]
180
+ unless @pid
190
181
  raise "Neither pid nor control url available"
191
182
  end
192
183
 
193
184
  begin
194
- Process.getpgid pid
195
- rescue SystemCallError
196
- if @options[:command] == "restart"
197
- @options.delete(:command)
198
- start
199
- else
200
- raise "No pid '#{pid}' found"
201
- end
202
- end
203
185
 
204
- case @options[:command]
205
- when "restart"
206
- Process.kill "SIGUSR2", pid
186
+ case @command
187
+ when "restart"
188
+ Process.kill "SIGUSR2", @pid
207
189
 
208
- when "halt"
209
- Process.kill "QUIT", pid
190
+ when "halt"
191
+ Process.kill "QUIT", @pid
210
192
 
211
- when "stop"
212
- Process.kill "SIGTERM", pid
193
+ when "stop"
194
+ Process.kill "SIGTERM", @pid
213
195
 
214
- when "stats"
215
- puts "Stats not available via pid only"
216
- return
196
+ when "stats"
197
+ puts "Stats not available via pid only"
198
+ return
217
199
 
218
- when "reload-worker-directory"
219
- puts "reload-worker-directory not available via pid only"
220
- return
200
+ when "reload-worker-directory"
201
+ puts "reload-worker-directory not available via pid only"
202
+ return
221
203
 
222
- when "phased-restart"
223
- Process.kill "SIGUSR1", pid
204
+ when "phased-restart"
205
+ Process.kill "SIGUSR1", @pid
224
206
 
225
- else
226
- message "Puma is started"
227
- return
207
+ else
208
+ return
209
+ end
210
+
211
+ rescue SystemCallError
212
+ if @command == "restart"
213
+ start
214
+ else
215
+ raise "No pid '#{@pid}' found"
216
+ end
228
217
  end
229
218
 
230
- message "Command #{@options[:command]} sent success"
219
+ message "Command #{@command} sent success"
231
220
  end
232
221
 
233
222
  def run
234
- start if @options[:command] == "start"
223
+ start if @command == "start"
235
224
 
236
225
  prepare_configuration
237
226
 
238
- if is_windows?
227
+ if Puma.windows?
239
228
  send_request
240
229
  else
241
- @options.has_key?(:control_url) ? send_request : send_signal
230
+ @control_url ? send_request : send_signal
242
231
  end
243
232
 
244
233
  rescue => e
245
234
  message e.message
235
+ message e.backtrace
246
236
  exit 1
247
237
  end
248
238
 
@@ -250,15 +240,14 @@ module Puma
250
240
  def start
251
241
  require 'puma/cli'
252
242
 
253
- run_args = @argv
243
+ run_args = []
254
244
 
255
- if path = @options[:state]
256
- run_args = ["-S", path] + run_args
257
- end
258
-
259
- if path = @options[:config_file]
260
- run_args = ["-C", path] + run_args
261
- end
245
+ run_args += ["-S", @state] if @state
246
+ run_args += ["-q"] if @quiet
247
+ run_args += ["--pidfile", @pidfile] if @pidfile
248
+ run_args += ["--control-url", @control_url] if @control_url
249
+ run_args += ["--control-token", @control_auth_token] if @control_auth_token
250
+ run_args += ["-C", @config_file] if @config_file
262
251
 
263
252
  events = Puma::Events.new @stdout, @stderr
264
253
 
@@ -0,0 +1,23 @@
1
+ require 'puma/launcher'
2
+ require 'puma/configuration'
3
+
4
+ module Puma
5
+ def self.run(opts={})
6
+ cfg = Puma::Configuration.new do |user_config|
7
+ if port = opts[:port]
8
+ user_config.port port
9
+ end
10
+
11
+ user_config.quiet
12
+
13
+ yield c
14
+ end
15
+
16
+ cfg.clamp
17
+
18
+ events = Puma::Events.null
19
+
20
+ launcher = Puma::Launcher.new cfg, :events => events
21
+ launcher.run
22
+ end
23
+ end
@@ -3,6 +3,12 @@ module Process
3
3
  # This overrides the default version because it is broken if it
4
4
  # exists.
5
5
 
6
+ if respond_to? :daemon
7
+ class << self
8
+ remove_method :daemon
9
+ end
10
+ end
11
+
6
12
  def self.daemon(nochdir=false, noclose=false)
7
13
  exit if fork # Parent exits, child continues.
8
14
 
data/lib/puma/detect.rb CHANGED
@@ -1,4 +1,13 @@
1
1
  module Puma
2
2
  IS_JRUBY = defined?(JRUBY_VERSION)
3
- end
4
3
 
4
+ def self.jruby?
5
+ IS_JRUBY
6
+ end
7
+
8
+ IS_WINDOWS = RUBY_PLATFORM =~ /mswin|ming|cygwin/
9
+
10
+ def self.windows?
11
+ IS_WINDOWS
12
+ end
13
+ end