puma 2.11.1 → 2.11.2

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.

@@ -28,7 +28,7 @@ module Puma
28
28
  # too taxing on performance.
29
29
  module Const
30
30
 
31
- PUMA_VERSION = VERSION = "2.11.1".freeze
31
+ PUMA_VERSION = VERSION = "2.11.2".freeze
32
32
  CODE_NAME = "Intrepid Squirrel".freeze
33
33
 
34
34
  FAST_TRACK_KA_TIMEOUT = 0.2
@@ -0,0 +1,280 @@
1
+ module Puma
2
+ # The methods that are available for use inside the config file.
3
+ #
4
+ class DSL
5
+ include ConfigDefault
6
+
7
+ def self.load(options, path)
8
+ new(options).tap do |obj|
9
+ obj._load_from(path)
10
+ end
11
+
12
+ options
13
+ end
14
+
15
+ def initialize(options)
16
+ @options = options
17
+ end
18
+
19
+ def _load_from(path)
20
+ instance_eval(File.read(path), path, 1) if path
21
+ end
22
+
23
+ # Use +obj+ or +block+ as the Rack app. This allows a config file to
24
+ # be the app itself.
25
+ #
26
+ def app(obj=nil, &block)
27
+ obj ||= block
28
+
29
+ raise "Provide either a #call'able or a block" unless obj
30
+
31
+ @options[:app] = obj
32
+ end
33
+
34
+ # Start the Puma control rack app on +url+. This app can be communicated
35
+ # with to control the main server.
36
+ #
37
+ def activate_control_app(url="auto", opts=nil)
38
+ @options[:control_url] = url
39
+
40
+ if opts
41
+ auth_token = opts[:auth_token]
42
+ @options[:control_auth_token] = auth_token if auth_token
43
+
44
+ @options[:control_auth_token] = :none if opts[:no_token]
45
+ end
46
+ end
47
+
48
+ # Bind the server to +url+. tcp:// and unix:// are the only accepted
49
+ # protocols.
50
+ #
51
+ def bind(url)
52
+ @options[:binds] << url
53
+ end
54
+
55
+ # Define the TCP port to bind to. Use +bind+ for more advanced options.
56
+ #
57
+ def port(port)
58
+ @options[:binds] << "tcp://#{Configuration::DefaultTCPHost}:#{port}"
59
+ end
60
+
61
+ # Work around leaky apps that leave garbage in Thread locals
62
+ # across requests
63
+ #
64
+ def clean_thread_locals(which=true)
65
+ @options[:clean_thread_locals] = which
66
+ end
67
+
68
+ # Daemonize the server into the background. Highly suggest that
69
+ # this be combined with +pidfile+ and +stdout_redirect+.
70
+ def daemonize(which=true)
71
+ @options[:daemon] = which
72
+ end
73
+
74
+ # When shutting down, drain the accept socket of pending
75
+ # connections and proces them. This loops over the accept
76
+ # socket until there are no more read events and then stops
77
+ # looking and waits for the requests to finish.
78
+ def drain_on_shutdown(which=true)
79
+ @options[:drain_on_shutdown] = which
80
+ end
81
+
82
+ # Set the environment in which the Rack's app will run.
83
+ def environment(environment)
84
+ @options[:environment] = environment
85
+ end
86
+
87
+ # Code to run before doing a restart. This code should
88
+ # close logfiles, database connections, etc.
89
+ #
90
+ # This can be called multiple times to add code each time.
91
+ #
92
+ def on_restart(&block)
93
+ @options[:on_restart] << block
94
+ end
95
+
96
+ # Command to use to restart puma. This should be just how to
97
+ # load puma itself (ie. 'ruby -Ilib bin/puma'), not the arguments
98
+ # to puma, as those are the same as the original process.
99
+ #
100
+ def restart_command(cmd)
101
+ @options[:restart_cmd] = cmd
102
+ end
103
+
104
+ # Store the pid of the server in the file at +path+.
105
+ def pidfile(path)
106
+ @options[:pidfile] = path
107
+ end
108
+
109
+ # Disable request logging.
110
+ #
111
+ def quiet
112
+ @options[:quiet] = true
113
+ end
114
+
115
+ # Load +path+ as a rackup file.
116
+ #
117
+ def rackup(path)
118
+ @options[:rackup] = path.to_s
119
+ end
120
+
121
+ # Redirect STDOUT and STDERR to files specified.
122
+ def stdout_redirect(stdout=nil, stderr=nil, append=false)
123
+ @options[:redirect_stdout] = stdout
124
+ @options[:redirect_stderr] = stderr
125
+ @options[:redirect_append] = append
126
+ end
127
+
128
+ # Configure +min+ to be the minimum number of threads to use to answer
129
+ # requests and +max+ the maximum.
130
+ #
131
+ def threads(min, max)
132
+ min = Integer(min)
133
+ max = Integer(max)
134
+ if min > max
135
+ raise "The minimum (#{min}) number of threads must be less than the max (#{max})"
136
+ end
137
+
138
+ @options[:min_threads] = min
139
+ @options[:max_threads] = max
140
+ end
141
+
142
+ def ssl_bind(host, port, opts)
143
+ @options[:binds] << "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}"
144
+ end
145
+
146
+ # Use +path+ as the file to store the server info state. This is
147
+ # used by pumactl to query and control the server.
148
+ #
149
+ def state_path(path)
150
+ @options[:state] = path.to_s
151
+ end
152
+
153
+ # *Cluster mode only* How many worker processes to run.
154
+ #
155
+ def workers(count)
156
+ @options[:workers] = count.to_i
157
+ end
158
+
159
+ # *Cluster mode only* Code to run immediately before a worker shuts
160
+ # down (after it has finished processing HTTP requests). These hooks
161
+ # can block if necessary to wait for background operations unknown
162
+ # to puma to finish before the process terminates.
163
+ #
164
+ # This can be called multiple times to add hooks.
165
+ #
166
+ def on_worker_shutdown(&block)
167
+ @options[:before_worker_shutdown] << block
168
+ end
169
+
170
+ # *Cluster mode only* Code to run when a worker boots to setup
171
+ # the process before booting the app.
172
+ #
173
+ # This can be called multiple times to add hooks.
174
+ #
175
+ def on_worker_boot(&block)
176
+ @options[:before_worker_boot] << block
177
+ end
178
+
179
+ # *Cluster mode only* Code to run when a master process is
180
+ # about to create the worker by forking itself.
181
+ #
182
+ # This can be called multiple times to add hooks.
183
+ #
184
+ def on_worker_fork(&block)
185
+ @options[:before_worker_fork] << block
186
+ end
187
+
188
+ # *Cluster mode only* Code to run when a worker boots to setup
189
+ # the process after booting the app.
190
+ #
191
+ # This can be called multiple times to add hooks.
192
+ #
193
+ def after_worker_boot(&block)
194
+ @options[:after_worker_boot] << block
195
+ end
196
+
197
+ # The directory to operate out of.
198
+ def directory(dir)
199
+ @options[:directory] = dir.to_s
200
+ @options[:worker_directory] = dir.to_s
201
+ end
202
+
203
+ # Run the app as a raw TCP app instead of an HTTP rack app
204
+ def tcp_mode
205
+ @options[:mode] = :tcp
206
+ end
207
+
208
+ # *Cluster mode only* Preload the application before starting
209
+ # the workers and setting up the listen ports. This conflicts
210
+ # with using the phased restart feature, you can't use both.
211
+ #
212
+ def preload_app!(answer=true)
213
+ @options[:preload_app] = answer
214
+ end
215
+
216
+ # Use +obj+ or +block+ as the low level error handler. This allows a config file to
217
+ # change the default error on the server.
218
+ #
219
+ def lowlevel_error_handler(obj=nil, &block)
220
+ obj ||= block
221
+ raise "Provide either a #call'able or a block" unless obj
222
+ @options[:lowlevel_error_handler] = obj
223
+ end
224
+
225
+ # This option is used to allow your app and its gems to be
226
+ # properly reloaded when not using preload.
227
+ #
228
+ # When set, if puma detects that it's been invoked in the
229
+ # context of Bundler, it will cleanup the environment and
230
+ # re-run itself outside the Bundler environment, but directly
231
+ # using the files that Bundler has setup.
232
+ #
233
+ # This means that puma is now decoupled from your Bundler
234
+ # context and when each worker loads, it will be loading a
235
+ # new Bundler context and thus can float around as the release
236
+ # dictates.
237
+ def prune_bundler(answer=true)
238
+ @options[:prune_bundler] = answer
239
+ end
240
+
241
+ # Additional text to display in process listing
242
+ def tag(string)
243
+ @options[:tag] = string
244
+ end
245
+
246
+ # *Cluster mode only* Set the timeout for workers
247
+ def worker_timeout(timeout)
248
+ @options[:worker_timeout] = timeout
249
+ end
250
+
251
+ # *Cluster mode only* Set the timeout for worker shutdown
252
+ def worker_shutdown_timeout(timeout)
253
+ @options[:worker_shutdown_timeout] = timeout
254
+ end
255
+
256
+ # When set to true (the default), workers accept all requests
257
+ # and queue them before passing them to the handlers.
258
+ # When set to false, each worker process accepts exactly as
259
+ # many requests as it is configured to simultaneously handle.
260
+ #
261
+ # Queueing requests generally improves performance. In some
262
+ # cases, such as a single threaded application, it may be
263
+ # better to ensure requests get balanced across workers.
264
+ #
265
+ # Note that setting this to false disables HTTP keepalive and
266
+ # slow clients will occupy a handler thread while the request
267
+ # is being sent. A reverse proxy, such as nginx, can handle
268
+ # slow clients and queue requests before they reach puma.
269
+ def queue_requests(answer=true)
270
+ @options[:queue_requests] = answer
271
+ end
272
+
273
+ # When a shutdown is requested, the backtraces of all the
274
+ # threads will be written to $stdout. This can help figure
275
+ # out why shutdown is hanging.
276
+ def shutdown_debug(val=true)
277
+ @options[:shutdown_debug] = val
278
+ end
279
+ end
280
+ end
@@ -535,7 +535,7 @@ module Puma
535
535
  line_ending = LINE_END
536
536
  colon = COLON
537
537
 
538
- if env[HTTP_VERSION] == HTTP_11
538
+ http_11 = if env[HTTP_VERSION] == HTTP_11
539
539
  allow_chunked = true
540
540
  keep_alive = env[HTTP_CONNECTION] != CLOSE
541
541
  include_keepalive_header = false
@@ -552,6 +552,7 @@ module Puma
552
552
 
553
553
  no_body ||= status < 200 || STATUS_WITH_NO_ENTITY_BODY[status]
554
554
  end
555
+ true
555
556
  else
556
557
  allow_chunked = false
557
558
  keep_alive = env[HTTP_CONNECTION] == KEEP_ALIVE
@@ -567,6 +568,7 @@ module Puma
567
568
 
568
569
  no_body ||= status < 200 || STATUS_WITH_NO_ENTITY_BODY[status]
569
570
  end
571
+ false
570
572
  end
571
573
 
572
574
  response_hijack = nil
@@ -593,6 +595,12 @@ module Puma
593
595
  end
594
596
  end
595
597
 
598
+ if include_keepalive_header
599
+ lines << CONNECTION_KEEP_ALIVE
600
+ elsif http_11 && !keep_alive
601
+ lines << CONNECTION_CLOSE
602
+ end
603
+
596
604
  if no_body
597
605
  if content_length and status != 204
598
606
  lines.append CONTENT_LENGTH_S, content_length.to_s, line_ending
@@ -603,12 +611,6 @@ module Puma
603
611
  return keep_alive
604
612
  end
605
613
 
606
- if include_keepalive_header
607
- lines << CONNECTION_KEEP_ALIVE
608
- elsif !keep_alive
609
- lines << CONNECTION_CLOSE
610
- end
611
-
612
614
  unless response_hijack
613
615
  if content_length
614
616
  lines.append CONTENT_LENGTH_S, content_length.to_s, line_ending
@@ -738,6 +740,21 @@ module Puma
738
740
  # Wait for all outstanding requests to finish.
739
741
  #
740
742
  def graceful_shutdown
743
+ if @options[:shutdown_debug]
744
+ threads = Thread.list
745
+ total = threads.size
746
+
747
+ pid = Process.pid
748
+
749
+ $stdout.syswrite "#{pid}: === Begin thread backtrace dump ===\n"
750
+
751
+ threads.each_with_index do |t,i|
752
+ $stdout.syswrite "#{pid}: Thread #{i+1}/#{total}: #{t.inspect}\n"
753
+ $stdout.syswrite "#{pid}: #{t.backtrace.join("\n#{pid}: ")}\n\n"
754
+ end
755
+ $stdout.syswrite "#{pid}: === End thread backtrace dump ===\n"
756
+ end
757
+
741
758
  if @options[:drain_on_shutdown]
742
759
  count = 0
743
760
 
@@ -17,7 +17,7 @@ Gem::Specification.new do |s|
17
17
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
18
18
  s.authors = ["Evan Phoenix"]
19
19
  s.date = `git log --pretty="%ai" -n 1`.split(" ").first
20
- s.description = "Puma is a simple, fast, threaded, and highly concurrent HTTP 1.1 server for Ruby/Rack applications. Puma is intended for use in both development and production environments. In order to get the best throughput, it is highly recommended that you use a Ruby implementation with real threads like Rubinius or JRuby."
20
+ s.description = "Puma is a simple, fast, threaded, and highly concurrent HTTP 1.1 server for Ruby/Rack applications. Puma is intended for use in both development and production environments. In order to get the best throughput, it is highly recommended that you use a Ruby implementation with real threads like Rubinius or JRuby."
21
21
  s.email = ["evan@phx.io"]
22
22
  s.executables = ["puma", "pumactl"]
23
23
  s.extensions = ["ext/puma_http11/extconf.rb"]
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.11.1
4
+ version: 2.11.2
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-02-11 00:00:00.000000000 Z
11
+ date: 2015-04-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -138,6 +138,7 @@ files:
138
138
  - lib/puma/daemon_ext.rb
139
139
  - lib/puma/delegation.rb
140
140
  - lib/puma/detect.rb
141
+ - lib/puma/dsl.rb
141
142
  - lib/puma/events.rb
142
143
  - lib/puma/io_buffer.rb
143
144
  - lib/puma/java_io_buffer.rb
@@ -155,24 +156,6 @@ files:
155
156
  - lib/puma/util.rb
156
157
  - lib/rack/handler/puma.rb
157
158
  - puma.gemspec
158
- - test/test_app_status.rb
159
- - test/test_cli.rb
160
- - test/test_config.rb
161
- - test/test_http10.rb
162
- - test/test_http11.rb
163
- - test/test_integration.rb
164
- - test/test_iobuffer.rb
165
- - test/test_minissl.rb
166
- - test/test_null_io.rb
167
- - test/test_persistent.rb
168
- - test/test_puma_server.rb
169
- - test/test_puma_server_ssl.rb
170
- - test/test_rack_handler.rb
171
- - test/test_rack_server.rb
172
- - test/test_tcp_rack.rb
173
- - test/test_thread_pool.rb
174
- - test/test_unix_socket.rb
175
- - test/test_ws.rb
176
159
  - tools/jungle/README.md
177
160
  - tools/jungle/init.d/README.md
178
161
  - tools/jungle/init.d/puma
@@ -208,22 +191,4 @@ signing_key:
208
191
  specification_version: 4
209
192
  summary: Puma is a simple, fast, threaded, and highly concurrent HTTP 1.1 server for
210
193
  Ruby/Rack applications
211
- test_files:
212
- - test/test_app_status.rb
213
- - test/test_cli.rb
214
- - test/test_config.rb
215
- - test/test_http10.rb
216
- - test/test_http11.rb
217
- - test/test_integration.rb
218
- - test/test_iobuffer.rb
219
- - test/test_minissl.rb
220
- - test/test_null_io.rb
221
- - test/test_persistent.rb
222
- - test/test_puma_server.rb
223
- - test/test_puma_server_ssl.rb
224
- - test/test_rack_handler.rb
225
- - test/test_rack_server.rb
226
- - test/test_tcp_rack.rb
227
- - test/test_thread_pool.rb
228
- - test/test_unix_socket.rb
229
- - test/test_ws.rb
194
+ test_files: []
@@ -1,92 +0,0 @@
1
- require 'test/unit'
2
- require 'rack'
3
- require 'puma/app/status'
4
-
5
- class TestAppStatus < Test::Unit::TestCase
6
- class FakeServer
7
- def initialize
8
- @status = :running
9
- @backlog = 0
10
- @running = 0
11
- end
12
-
13
- attr_reader :status
14
- attr_accessor :backlog, :running
15
-
16
- def stop
17
- @status = :stop
18
- end
19
-
20
- def halt
21
- @status = :halt
22
- end
23
-
24
- def stats
25
- "{}"
26
- end
27
- end
28
-
29
- def setup
30
- @server = FakeServer.new
31
- @app = Puma::App::Status.new(@server)
32
- @app.auth_token = nil
33
- end
34
-
35
- def lint(uri)
36
- app = Rack::Lint.new @app
37
- mock_env = Rack::MockRequest.env_for uri
38
- app.call mock_env
39
- end
40
-
41
- def test_bad_token
42
- @app.auth_token = "abcdef"
43
-
44
- status, _, _ = lint('/whatever')
45
-
46
- assert_equal 403, status
47
- end
48
-
49
- def test_good_token
50
- @app.auth_token = "abcdef"
51
-
52
- status, _, _ = lint('/whatever?token=abcdef')
53
-
54
- assert_equal 404, status
55
- end
56
-
57
- def test_unsupported
58
- status, _, _ = lint('/not-real')
59
-
60
- assert_equal 404, status
61
- end
62
-
63
- def test_stop
64
- status, _ , app = lint('/stop')
65
-
66
- assert_equal :stop, @server.status
67
- assert_equal 200, status
68
- assert_equal ['{ "status": "ok" }'], app.enum_for.to_a
69
- end
70
-
71
- def test_halt
72
- status, _ , app = lint('/halt')
73
-
74
- assert_equal :halt, @server.status
75
- assert_equal 200, status
76
- assert_equal ['{ "status": "ok" }'], app.enum_for.to_a
77
- end
78
-
79
- def test_stats
80
- @server.backlog = 1
81
- @server.running = 9
82
- status, _ , app = lint('/stats')
83
-
84
- assert_equal 200, status
85
- assert_equal ['{}'], app.enum_for.to_a
86
- end
87
-
88
- def test_alternate_location
89
- status, _ , _ = lint('__alternatE_location_/stats')
90
- assert_equal 200, status
91
- end
92
- end