puma 2.12.3 → 2.16.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.

data/lib/puma/dsl.rb CHANGED
@@ -42,6 +42,7 @@ module Puma
42
42
  @options[:control_auth_token] = auth_token if auth_token
43
43
 
44
44
  @options[:control_auth_token] = :none if opts[:no_token]
45
+ @options[:control_url_umask] = opts[:umask] if opts[:umask]
45
46
  end
46
47
  end
47
48
 
@@ -132,7 +133,7 @@ module Puma
132
133
  min = Integer(min)
133
134
  max = Integer(max)
134
135
  if min > max
135
- raise "The minimum (#{min}) number of threads must be less than the max (#{max})"
136
+ raise "The minimum (#{min}) number of threads must be less than or equal to the max (#{max})"
136
137
  end
137
138
 
138
139
  @options[:min_threads] = min
@@ -140,7 +141,12 @@ module Puma
140
141
  end
141
142
 
142
143
  def ssl_bind(host, port, opts)
143
- @options[:binds] << "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}"
144
+ if defined?(JRUBY_VERSION)
145
+ keystore_additions = "keystore=#{opts[:keystore]}&keystore-pass=#{opts[:keystore_pass]}"
146
+ @options[:binds] << "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}&#{keystore_additions}"
147
+ else
148
+ @options[:binds] << "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}"
149
+ end
144
150
  end
145
151
 
146
152
  # Use +path+ as the file to store the server info state. This is
@@ -156,6 +162,19 @@ module Puma
156
162
  @options[:workers] = count.to_i
157
163
  end
158
164
 
165
+ # *Cluster mode only* Code to run immediately before master process
166
+ # forks workers (once on boot). These hooks can block if necessary
167
+ # to wait for background operations unknown to puma to finish before
168
+ # the process terminates.
169
+ # This can be used to close any connections to remote servers (database, redis, ...)
170
+ # that were opened when preloading the code
171
+ #
172
+ # This can be called multiple times to add hooks.
173
+ #
174
+ def before_fork(&block)
175
+ @options[:before_fork] << block
176
+ end
177
+
159
178
  # *Cluster mode only* Code to run immediately before a worker shuts
160
179
  # down (after it has finished processing HTTP requests). These hooks
161
180
  # can block if necessary to wait for background operations unknown
@@ -243,11 +262,19 @@ module Puma
243
262
  @options[:tag] = string
244
263
  end
245
264
 
246
- # *Cluster mode only* Set the timeout for workers
265
+ # *Cluster mode only* Set the timeout for workers in seconds
266
+ # When set the master process will terminate any workers
267
+ # that have not checked in within the given +timeout+.
268
+ # This mitigates hung processes. Default value is 60 seconds.
247
269
  def worker_timeout(timeout)
248
270
  @options[:worker_timeout] = timeout
249
271
  end
250
272
 
273
+ # *Cluster mode only* Set the timeout for workers to boot
274
+ def worker_boot_timeout(timeout)
275
+ @options[:worker_boot_timeout] = timeout
276
+ end
277
+
251
278
  # *Cluster mode only* Set the timeout for worker shutdown
252
279
  def worker_shutdown_timeout(timeout)
253
280
  @options[:worker_shutdown_timeout] = timeout
@@ -276,5 +303,46 @@ module Puma
276
303
  def shutdown_debug(val=true)
277
304
  @options[:shutdown_debug] = val
278
305
  end
306
+
307
+ # Control how the remote address of the connection is set. This
308
+ # is configurable because to calculate the true socket peer address
309
+ # a kernel syscall is required which for very fast rack handlers
310
+ # slows down the handling significantly.
311
+ #
312
+ # There are 4 possible values:
313
+ #
314
+ # * :socket (the default) - read the peername from the socket using the
315
+ # syscall. This is the normal behavior.
316
+ # * :localhost - set the remote address to "127.0.0.1"
317
+ # * header: http_header - set the remote address to the value of the
318
+ # provided http header. For instance:
319
+ # `set_remote_address header: "X-Real-IP"`.
320
+ # Only the first word (as separated by spaces or comma)
321
+ # is used, allowing headers such as X-Forwarded-For
322
+ # to be used as well.
323
+ # * Any string - this allows you to hardcode remote address to any value
324
+ # you wish. Because puma never uses this field anyway, it's
325
+ # format is entirely in your hands.
326
+ def set_remote_address(val=:socket)
327
+ case val
328
+ when :socket
329
+ @options[:remote_address] = val
330
+ when :localhost
331
+ @options[:remote_address] = :value
332
+ @options[:remote_address_value] = "127.0.0.1".freeze
333
+ when String
334
+ @options[:remote_address] = :value
335
+ @options[:remote_address_value] = val
336
+ when Hash
337
+ if hdr = val[:header]
338
+ @options[:remote_address] = :header
339
+ @options[:remote_address_header] = "HTTP_" + hdr.upcase.gsub("-", "_")
340
+ else
341
+ raise "Invalid value for set_remote_address - #{val.inspect}"
342
+ end
343
+ else
344
+ raise "Invalid value for set_remote_address - #{val}"
345
+ end
346
+ end
279
347
  end
280
348
  end
data/lib/puma/events.rb CHANGED
@@ -128,7 +128,7 @@ module Puma
128
128
 
129
129
  DEFAULT = new(STDOUT, STDERR)
130
130
 
131
- # Returns an Events object which writes it's status to 2 StringIO
131
+ # Returns an Events object which writes its status to 2 StringIO
132
132
  # objects.
133
133
  #
134
134
  def self.strings
data/lib/puma/minissl.rb CHANGED
@@ -102,6 +102,8 @@ module Puma
102
102
  class SSLError < StandardError
103
103
  # Define this for jruby even though it isn't used.
104
104
  end
105
+
106
+ def self.check; end
105
107
  end
106
108
 
107
109
  class Context
data/lib/puma/runner.rb CHANGED
@@ -52,8 +52,9 @@ module Puma
52
52
  when "unix"
53
53
  log "* Starting control server on #{str}"
54
54
  path = "#{uri.host}#{uri.path}"
55
+ mask = @options[:control_url_umask]
55
56
 
56
- control.add_unix_listener path
57
+ control.add_unix_listener path, mask
57
58
  else
58
59
  error "Invalid control URI: #{str}"
59
60
  end
data/lib/puma/server.rb CHANGED
@@ -45,7 +45,7 @@ module Puma
45
45
  # to be handled. See Puma::Events for the list of current methods to implement.
46
46
  #
47
47
  # Server#run returns a thread that you can join on to wait for the server
48
- # to do it's work.
48
+ # to do its work.
49
49
  #
50
50
  def initialize(app, events=Events.stdio, options={})
51
51
  @app = app
@@ -307,6 +307,16 @@ module Puma
307
307
  pool = @thread_pool
308
308
  queue_requests = @queue_requests
309
309
 
310
+ remote_addr_value = nil
311
+ remote_addr_header = nil
312
+
313
+ case @options[:remote_address]
314
+ when :value
315
+ remote_addr_value = @options[:remote_address_value]
316
+ when :header
317
+ remote_addr_header = @options[:remote_address_header]
318
+ end
319
+
310
320
  while @status == :run
311
321
  begin
312
322
  ios = IO.select sockets
@@ -317,6 +327,12 @@ module Puma
317
327
  begin
318
328
  if io = sock.accept_nonblock
319
329
  client = Client.new io, @binder.env(sock)
330
+ if remote_addr_value
331
+ client.peerip = remote_addr_value
332
+ elsif remote_addr_header
333
+ client.remote_addr_header = remote_addr_header
334
+ end
335
+
320
336
  pool << client
321
337
  pool.wait_until_not_full unless queue_requests
322
338
  end
@@ -481,7 +497,7 @@ module Puma
481
497
 
482
498
  unless env.key?(REMOTE_ADDR)
483
499
  begin
484
- addr = client.peeraddr.last
500
+ addr = client.peerip
485
501
  rescue Errno::ENOTCONN
486
502
  # Client disconnects can result in an inability to get the
487
503
  # peeraddr from the socket; default to localhost.
@@ -513,7 +529,7 @@ module Puma
513
529
  env = req.env
514
530
  client = req.io
515
531
 
516
- normalize_env env, client
532
+ normalize_env env, req
517
533
 
518
534
  env[PUMA_SOCKET] = client
519
535
 
@@ -571,7 +587,7 @@ module Puma
571
587
 
572
588
  http_11 = if env[HTTP_VERSION] == HTTP_11
573
589
  allow_chunked = true
574
- keep_alive = env[HTTP_CONNECTION] != CLOSE
590
+ keep_alive = env.fetch(HTTP_CONNECTION, "").downcase != CLOSE
575
591
  include_keepalive_header = false
576
592
 
577
593
  # An optimization. The most common response is 200, so we can
@@ -589,7 +605,7 @@ module Puma
589
605
  true
590
606
  else
591
607
  allow_chunked = false
592
- keep_alive = env[HTTP_CONNECTION] == KEEP_ALIVE
608
+ keep_alive = env.fetch(HTTP_CONNECTION, "").downcase == KEEP_ALIVE
593
609
  include_keepalive_header = keep_alive
594
610
 
595
611
  # Same optimization as above for HTTP/1.1
@@ -608,7 +624,7 @@ module Puma
608
624
  response_hijack = nil
609
625
 
610
626
  headers.each do |k, vs|
611
- case k
627
+ case k.downcase
612
628
  when CONTENT_LENGTH2
613
629
  content_length = vs
614
630
  next
@@ -644,7 +660,7 @@ module Puma
644
660
  fast_write client, lines.to_s
645
661
  return keep_alive
646
662
  end
647
-
663
+
648
664
  if content_length
649
665
  lines.append CONTENT_LENGTH_S, content_length.to_s, line_ending
650
666
  chunked = false
data/lib/puma/single.rb CHANGED
@@ -62,7 +62,7 @@ module Puma
62
62
  end
63
63
 
64
64
  Signal.trap "SIGCHLD" do
65
- log "! Error starting new process as daemon, exitting"
65
+ log "! Error starting new process as daemon, exiting"
66
66
  exit 1
67
67
  end
68
68
 
@@ -160,7 +160,7 @@ module Puma
160
160
  end
161
161
 
162
162
  # If there are dead threads in the pool make them go away while decreasing
163
- # spwaned counter so that new healty threads could be created again.
163
+ # spawned counter so that new healthy threads could be created again.
164
164
  def reap
165
165
  @mutex.synchronize do
166
166
  dead_workers = @workers.reject(&:alive?)
@@ -235,20 +235,18 @@ module Puma
235
235
  # Tell all threads in the pool to exit and wait for them to finish.
236
236
  #
237
237
  def shutdown
238
- @mutex.synchronize do
238
+ threads = @mutex.synchronize do
239
239
  @shutdown = true
240
240
  @not_empty.broadcast
241
241
  @not_full.broadcast
242
242
 
243
243
  @auto_trim.stop if @auto_trim
244
244
  @reaper.stop if @reaper
245
+ # dup workers so that we join them all safely
246
+ @workers.dup
245
247
  end
246
248
 
247
- # Use this instead of #each so that we don't stop in the middle
248
- # of each and see a mutated object mid #each
249
- if !@workers.empty?
250
- @workers.first.join until @workers.empty?
251
- end
249
+ threads.each(&:join)
252
250
 
253
251
  @spawned = 0
254
252
  @workers = []
@@ -8,7 +8,8 @@ module Rack
8
8
  :Host => '0.0.0.0',
9
9
  :Port => 8080,
10
10
  :Threads => '0:16',
11
- :Verbose => false
11
+ :Verbose => false,
12
+ :Silent => false
12
13
  }
13
14
 
14
15
  def self.run(app, options = {})
@@ -22,13 +23,16 @@ module Rack
22
23
  ENV['RACK_ENV'] = options[:environment].to_s
23
24
  end
24
25
 
25
- server = ::Puma::Server.new(app)
26
+ events_hander = options[:Silent] ? ::Puma::Events.strings : ::Puma::Events.stdio
27
+ server = ::Puma::Server.new(app, events_hander)
26
28
  min, max = options[:Threads].split(':', 2)
27
29
 
28
- puts "Puma #{::Puma::Const::PUMA_VERSION} starting..."
29
- puts "* Min threads: #{min}, max threads: #{max}"
30
- puts "* Environment: #{ENV['RACK_ENV']}"
31
- puts "* Listening on tcp://#{options[:Host]}:#{options[:Port]}"
30
+ log = events_hander.stdout
31
+
32
+ log.puts "Puma #{::Puma::Const::PUMA_VERSION} starting..."
33
+ log.puts "* Min threads: #{min}, max threads: #{max}"
34
+ log.puts "* Environment: #{ENV['RACK_ENV']}"
35
+ log.puts "* Listening on tcp://#{options[:Host]}:#{options[:Port]}"
32
36
 
33
37
  server.add_tcp_listener options[:Host], options[:Port]
34
38
  server.min_threads = min
@@ -38,9 +42,9 @@ module Rack
38
42
  begin
39
43
  server.run.join
40
44
  rescue Interrupt
41
- puts "* Gracefully stopping, waiting for requests to finish"
45
+ log.puts "* Gracefully stopping, waiting for requests to finish"
42
46
  server.stop(true)
43
- puts "* Goodbye!"
47
+ log.puts "* Goodbye!"
44
48
  end
45
49
 
46
50
  end
@@ -50,7 +54,7 @@ module Rack
50
54
  "Host=HOST" => "Hostname to listen on (default: localhost)",
51
55
  "Port=PORT" => "Port to listen on (default: 8080)",
52
56
  "Threads=MIN:MAX" => "min:max threads to use (default 0:16)",
53
- "Quiet" => "Don't report each request"
57
+ "Verbose" => "Don't report each request (default: false)"
54
58
  }
55
59
  end
56
60
  end
@@ -23,6 +23,7 @@ SCRIPTNAME=/etc/init.d/$NAME
23
23
  CONFIG=/etc/puma.conf
24
24
  JUNGLE=`cat $CONFIG`
25
25
  RUNPUMA=/usr/local/bin/run-puma
26
+ USE_LOCAL_BUNDLE=0
26
27
 
27
28
  # Load the VERBOSE setting and other rcS variables
28
29
  . /lib/init/vars.sh
@@ -105,7 +106,11 @@ do_stop_one() {
105
106
  log_daemon_msg "---> Puma $1 isn't running."
106
107
  else
107
108
  log_daemon_msg "---> About to kill PID `cat $PIDFILE`"
108
- pumactl --state $STATEFILE stop
109
+ if [ "$USE_LOCAL_BUNDLE" -eq 1 ]; then
110
+ cd $1 && bundle exec pumactl --state $STATEFILE stop
111
+ else
112
+ pumactl --state $STATEFILE stop
113
+ fi
109
114
  # Many daemons don't delete their pidfiles when they exit.
110
115
  rm -f $PIDFILE $STATEFILE
111
116
  fi
@@ -135,7 +140,11 @@ do_restart_one() {
135
140
 
136
141
  if [ -e $PIDFILE ]; then
137
142
  log_daemon_msg "--> About to restart puma $1"
138
- pumactl --state $dir/tmp/puma/state restart
143
+ if [ "$USE_LOCAL_BUNDLE" -eq 1 ]; then
144
+ cd $1 && bundle exec pumactl --state $dir/tmp/puma/state restart
145
+ else
146
+ pumactl --state $dir/tmp/puma/state restart
147
+ fi
139
148
  # kill -s USR2 `cat $PIDFILE`
140
149
  # TODO Check if process exist
141
150
  else
@@ -175,7 +184,11 @@ do_status_one() {
175
184
 
176
185
  if [ -e $PIDFILE ]; then
177
186
  log_daemon_msg "--> About to status puma $1"
178
- pumactl --state $dir/tmp/puma/state stats
187
+ if [ "$USE_LOCAL_BUNDLE" -eq 1 ]; then
188
+ cd $1 && bundle exec pumactl --state $dir/tmp/puma/state stats
189
+ else
190
+ pumactl --state $dir/tmp/puma/state stats
191
+ fi
179
192
  # kill -s USR2 `cat $PIDFILE`
180
193
  # TODO Check if process exist
181
194
  else
@@ -241,6 +254,40 @@ do_remove() {
241
254
  fi
242
255
  }
243
256
 
257
+ config_bundler() {
258
+ HOME="$(eval echo ~$(id -un))"
259
+ if [ -d "/usr/local/rbenv/bin" ]; then
260
+ PATH="/usr/local/rbenv/bin:/usr/local/rbenv/shims:$PATH"
261
+ eval "$(rbenv init -)"
262
+ USE_LOCAL_BUNDLE=1
263
+ return 0
264
+ elif [ -d "$HOME/.rbenv/bin" ]; then
265
+ PATH="$HOME/.rbenv/bin:$HOME/.rbenv/shims:$PATH"
266
+ eval "$(rbenv init -)"
267
+ USE_LOCAL_BUNDLE=1
268
+ return 0
269
+ # TODO: test rvm
270
+ # elif [ -f /etc/profile.d/rvm.sh ]; then
271
+ # source /etc/profile.d/rvm.sh
272
+ # elif [ -f /usr/local/rvm/scripts/rvm ]; then
273
+ # source /etc/profile.d/rvm.sh
274
+ # elif [ -f "$HOME/.rvm/scripts/rvm" ]; then
275
+ # source "$HOME/.rvm/scripts/rvm"
276
+ # TODO: don't know what to do with chruby
277
+ # elif [ -f /usr/local/share/chruby/chruby.sh ]; then
278
+ # source /usr/local/share/chruby/chruby.sh
279
+ # if [ -f /usr/local/share/chruby/auto.sh ]; then
280
+ # source /usr/local/share/chruby/auto.sh
281
+ # fi
282
+ # if you aren't using auto, set your version here
283
+ # chruby 2.0.0
284
+ fi
285
+
286
+ return 1
287
+ }
288
+
289
+ config_bundler
290
+
244
291
  case "$1" in
245
292
  start)
246
293
  [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
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: 2.12.3
4
+ version: 2.16.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: 2015-08-04 00:00:00.000000000 Z
11
+ date: 2016-01-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rdoc
@@ -64,14 +64,14 @@ dependencies:
64
64
  requirements:
65
65
  - - "~>"
66
66
  - !ruby/object:Gem::Version
67
- version: '3.13'
67
+ version: '3.14'
68
68
  type: :development
69
69
  prerelease: false
70
70
  version_requirements: !ruby/object:Gem::Requirement
71
71
  requirements:
72
72
  - - "~>"
73
73
  - !ruby/object:Gem::Version
74
- version: '3.13'
74
+ version: '3.14'
75
75
  description: Puma is a simple, fast, threaded, and highly concurrent HTTP 1.1 server
76
76
  for Ruby/Rack applications. Puma is intended for use in both development and production
77
77
  environments. In order to get the best throughput, it is highly recommended that
@@ -191,7 +191,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
191
191
  version: '0'
192
192
  requirements: []
193
193
  rubyforge_project:
194
- rubygems_version: 2.4.5
194
+ rubygems_version: 2.5.1
195
195
  signing_key:
196
196
  specification_version: 4
197
197
  summary: Puma is a simple, fast, threaded, and highly concurrent HTTP 1.1 server for