puma 3.0.0.rc1 → 3.0.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.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ec0eeb5886074470b19df49db748d9fad55c57c6
4
- data.tar.gz: 74521d8b05a10a149cf6aa0fb4dc4c7e199ab124
3
+ metadata.gz: 3aaeb164dd6e399e4155a81117c4ad6cde4a0420
4
+ data.tar.gz: d040b98c0015ce89e4d5c7d793a488eace1d6422
5
5
  SHA512:
6
- metadata.gz: d64e58108913abf1b2252ba3038553ec28c82cfe96aa8812de7bdc58215881aea90a1048b490cee8699df99c73f3ea2b9d1dd3b472d082fbcc7974003c79e16c
7
- data.tar.gz: 35befe3e0a9d01fa14f58841ecbcef2fa84a99ba8b3c564ceacb99101e52d50a855c7ab65c983caf816a09bf5547fb35b4e6f111985bea1cb5940e46a01b4dc8
6
+ metadata.gz: aa50dc14fdac0d976b3f0e480039f301aad9c09cd898eb0fc8c901f900b5f1167ff50818d10c68601c8a70122a7ae865b75f5702c83425cd6005ecca11862236
7
+ data.tar.gz: e2da1eb6e42bdad2925391be65b152af26ac784f70dcbc1c4074cd0a269eff58e6b2cc22572b60febc46777a488bfca402b71ed0f1dcbcbe6655b561d7460543
data/Gemfile CHANGED
@@ -8,6 +8,6 @@ gem "rake-compiler"
8
8
  gem "test-unit", "~> 3.0"
9
9
 
10
10
  gem "rack"
11
- gem 'minitest', '~> 4.0'
11
+ gem 'minitest', '~> 5.8'
12
12
 
13
13
  gem "jruby-openssl", :platform => "jruby"
@@ -1,3 +1,53 @@
1
+ === 3.0.0 / 2016-02-25
2
+
3
+ * 2 major changes:
4
+
5
+ * Ruby pre-2.0 is no longer supported. We'll do our best to not add
6
+ features that break those rubies but will no longer be testing
7
+ with them.
8
+ * Don't log requests by default. Fixes #852
9
+
10
+ * 2 major features:
11
+
12
+ * Plugin support! Plugins can interact with configuration as well
13
+ as provide augment server functionality!
14
+ * Experimental env['async.callback'] support
15
+
16
+ * 4 minor features:
17
+
18
+ * Listen to unix socket with provided backlog if any
19
+ * Improves the clustered stats to report worker stats
20
+ * Pass the env to the lowlevel_error handler. Fixes #854
21
+ * Treat path-like hosts as unix sockets. Fixes #824
22
+
23
+ * 5 bug fixes:
24
+
25
+ * Clean thread locals when using keepalive. Fixes #823
26
+ * Cleanup compiler warnings. Fixes #815
27
+ * Expose closed? for use by the reactor. Fixes #835
28
+ * Move signal handlers to separate method to prevent space leak. Fixes #798
29
+ * Signal not full on worker exit #876
30
+
31
+ * 5 doc fixes:
32
+
33
+ * Update README.md with various grammar fixes
34
+ * Use newest version of Minitest
35
+ * Add directory configuration docs, fix typo [ci skip]
36
+ * Remove old COPYING notice. Fixes #849
37
+
38
+ * 10 merged PRs:
39
+
40
+ * Merge pull request #871 from deepj/travis
41
+ * Merge pull request #874 from wallclockbuilder/master
42
+ * Merge pull request #883 from dadah89/igor/trim_only_worker
43
+ * Merge pull request #884 from uistudio/async-callback
44
+ * Merge pull request #888 from mlarraz/tick_minitest
45
+ * Merge pull request #890 from todd/directory_docs
46
+ * Merge pull request #891 from ctaintor/improve_clustered_status
47
+ * Merge pull request #893 from spastorino/add_missing_require
48
+ * Merge pull request #897 from zendesk/master
49
+ * Merge pull request #899 from kch/kch-readme-fixes
50
+
1
51
  === 2.16.0 / 2016-01-27
2
52
 
3
53
  * 7 minor features:
@@ -1,4 +1,3 @@
1
- COPYING
2
1
  DEPLOYMENT.md
3
2
  Gemfile
4
3
  History.txt
data/README.md CHANGED
@@ -74,7 +74,7 @@ Puma utilizes a dynamic thread pool which you can modify. You can set the minimu
74
74
 
75
75
  $ puma -t 8:32
76
76
 
77
- Puma will automatically scale the number of threads based on how much traffic is present. The current default is `0:16`. Feel free to experiment, but be careful not to set the number of maximum threads to a very large number, as you may exhaust resources on the system (or hit resource limits).
77
+ Puma will automatically scale the number of threads, from the minimum until it caps out at the maximum, based on how much traffic is present. The current default is `0:16`. Feel free to experiment, but be careful not to set the number of maximum threads to a very large number, as you may exhaust resources on the system (or hit resource limits).
78
78
 
79
79
  ### Clustered mode
80
80
 
@@ -111,7 +111,7 @@ you to do some Puma-specific things that you don't want to embed in your applica
111
111
  For instance, you could fire a log notification that a worker booted or send something to statsd.
112
112
  This can be called multiple times to add hooks.
113
113
 
114
- If you're preloading your application and using ActiveRecord, it's recommend you setup your connection pool here:
114
+ If you're preloading your application and using ActiveRecord, it's recommended that you setup your connection pool here:
115
115
 
116
116
  # config/puma.rb
117
117
  on_worker_boot do
@@ -130,7 +130,7 @@ On top of that, you can specify a block in your configuration file that will be
130
130
  This code can be used to clean up before forking to clients, allowing
131
131
  you to do some Puma-specific things that you don't want to embed in your application.
132
132
 
133
- If you're preloading your application and using ActiveRecord, it's recommend you close any connections to the database here to prevent connection leakage:
133
+ If you're preloading your application and using ActiveRecord, it's recommended that you close any connections to the database here to prevent connection leakage:
134
134
 
135
135
  # config/puma.rb
136
136
  before_fork do
@@ -139,7 +139,7 @@ If you're preloading your application and using ActiveRecord, it's recommend you
139
139
 
140
140
  This rule applies to any connections to external services (Redis, databases, memcache, ...) that might be started automatically by the framework.
141
141
 
142
- When you use preload_app, your new code goes all in the master process, and is then copied in the workers (meaning it’s only compatible with cluster mode). General rule is to use preload_app when your workers die often and need fast starts. If you don’t have many workers, you probably should not use preload_app.
142
+ When you use preload_app, all of your new code goes into the master process, and is then copied into the workers (meaning it’s only compatible with cluster mode). General rule is to use preload_app when your workers die often and need fast starts. If you don’t have many workers, you probably should not use preload_app.
143
143
 
144
144
  Note that preload_app can’t be used with phased restart, since phased restart kills and restarts workers one-by-one, and preload_app is all about copying the code of master into the workers.
145
145
 
@@ -177,7 +177,7 @@ Need a bit of security? Use SSL sockets!
177
177
 
178
178
  ### Control/Status Server
179
179
 
180
- Puma comes with a builtin status/control app that can be used query and control Puma itself. Here is an example of starting Puma with the control server:
180
+ Puma comes with a builtin status/control app that can be used to query and control Puma itself. Here is an example of starting Puma with the control server:
181
181
 
182
182
  $ puma --control tcp://127.0.0.1:9293 --control-token foo
183
183
 
@@ -212,26 +212,35 @@ If the new process is unable to load, it will simply exit. You should therefore
212
212
 
213
213
  ### Normal vs Hot vs Phased Restart
214
214
 
215
- A hot restart means that no requests while deploying your new code will be lost, since the server socket is kept open between restarts.
215
+ A hot restart means that no requests will be lost while deploying your new code, since the server socket is kept open between restarts.
216
216
 
217
217
  But beware, hot restart does not mean that the incoming requests won’t hang for multiple seconds while your new code has not fully deployed. If you need a zero downtime and zero hanging requests deploy, you must use phased restart.
218
218
 
219
- When you run pumactl phased-restart, Puma kills workers one-by-one, meaning that at least another worker is still available to serve requests, which lead in zero hanging request (yay!).
219
+ When you run pumactl phased-restart, Puma kills workers one-by-one, meaning that at least another worker is still available to serve requests, which lead to zero hanging requests (yay!).
220
220
 
221
221
  But again beware, upgrading an application sometimes involves upgrading the database schema. With phased restart, there may be a moment during the deployment where processes belonging to the previous version and processes belonging to the new version both exist at the same time. Any database schema upgrades you perform must therefore be backwards-compatible with the old application version.
222
222
 
223
- if you perform a lot of database migrations, you probably should not use phased restart and use a normal/hot restart instead (pumactl restart). That way, no code is shared while deploying (in that case, preload_app might help for quicker deployment, see below).
223
+ If you perform a lot of database migrations, you probably should not use phased restart and use a normal/hot restart instead (pumactl restart). That way, no code is shared while deploying (in that case, preload_app might help for quicker deployment, see below).
224
224
 
225
+ ### Release Directory
226
+
227
+ If you symlink releases into a common working directory (i.e., `/current` from Capistrano), Puma won't pick up your new changes when running phased restarts without additional configuration. You should set your working directory within Puma's config to specify the directory it should use. This is a change from earlier versions of Puma (< 2.15) that would infer the directory for you.
228
+
229
+ ```ruby
230
+ # config/puma.rb
231
+
232
+ directory '/var/www/current'
233
+ ```
225
234
 
226
235
  ### Cleanup Code
227
236
 
228
237
  Puma isn't able to understand all the resources that your app may use, so it provides a hook in the configuration file you pass to `-C` called `on_restart`. The block passed to `on_restart` will be called, unsurprisingly, just before Puma restarts itself.
229
238
 
230
- You should place code to close global log files, redis connections, etc in this block so that their file descriptors don't leak into the restarted process. Failure to do so will result in slowly running out of descriptors and eventually obscure crashes as the server is restart many times.
239
+ You should place code to close global log files, redis connections, etc in this block so that their file descriptors don't leak into the restarted process. Failure to do so will result in slowly running out of descriptors and eventually obscure crashes as the server is restarted many times.
231
240
 
232
241
  ### Platform Constraints
233
242
 
234
- Because of various platforms not being implement certain things, the following differences occur when Puma is used on different platforms:
243
+ Because of various platforms not being able to implement certain things, the following differences occur when Puma is used on different platforms:
235
244
 
236
245
  * **JRuby**, **Windows**: server sockets are not seamless on restart, they must be closed and reopened. These platforms have no way to pass descriptors into a new process that is exposed to ruby
237
246
  * **JRuby**, **Windows**: cluster mode is not supported due to a lack of fork(2)
@@ -243,7 +252,7 @@ Because of various platforms not being implement certain things, the following d
243
252
 
244
253
  ## Managing multiple Pumas / init.d / upstart scripts
245
254
 
246
- If you want an easy way to manage multiple scripts at once check [tools/jungle](https://github.com/puma/puma/tree/master/tools/jungle) for init.d and upstart scripts.
255
+ If you want an easy way to manage multiple scripts at once, check [tools/jungle](https://github.com/puma/puma/tree/master/tools/jungle) for init.d and upstart scripts.
247
256
 
248
257
  ## Capistrano deployment
249
258
 
@@ -284,4 +293,4 @@ $ bundle exec rake
284
293
 
285
294
  ## License
286
295
 
287
- Puma is copyright 2014 Evan Phoenix and contributors. It is licensed under the BSD 3-Clause license. See the include LICENSE file for details.
296
+ Puma is copyright 2014 Evan Phoenix and contributors. It is licensed under the BSD 3-Clause license. See the included LICENSE file for details.
@@ -116,7 +116,7 @@ static VALUE buf_to_str(VALUE self) {
116
116
  struct buf_int* b;
117
117
  Data_Get_Struct(self, struct buf_int, b);
118
118
 
119
- return rb_str_new(b->top, b->cur - b->top);
119
+ return rb_str_new((const char*)(b->top), b->cur - b->top);
120
120
  }
121
121
 
122
122
  static VALUE buf_used(VALUE self) {
@@ -1,7 +1,13 @@
1
1
  #define RSTRING_NOT_MODIFIED 1
2
2
 
3
3
  #include <ruby.h>
4
+ #include <ruby/version.h>
5
+
6
+ #if RUBY_API_VERSION_MAJOR == 1
4
7
  #include <rubyio.h>
8
+ #else
9
+ #include <ruby/io.h>
10
+ #endif
5
11
 
6
12
  #ifdef HAVE_OPENSSL_BIO_H
7
13
 
@@ -347,7 +353,7 @@ VALUE engine_peercert(VALUE self) {
347
353
  }
348
354
  }
349
355
 
350
- rb_cert_buf = rb_str_new(buf, bytes);
356
+ rb_cert_buf = rb_str_new((const char*)(buf), bytes);
351
357
  if(!cert_buf) {
352
358
  OPENSSL_free(buf);
353
359
  }
@@ -111,6 +111,7 @@ module Puma
111
111
 
112
112
  umask = nil
113
113
  mode = nil
114
+ backlog = nil
114
115
 
115
116
  if uri.query
116
117
  params = Util.parse_query uri.query
@@ -122,9 +123,13 @@ module Puma
122
123
  if u = params['mode']
123
124
  mode = Integer('0'+u)
124
125
  end
126
+
127
+ if u = params['backlog']
128
+ backlog = Integer(u)
129
+ end
125
130
  end
126
131
 
127
- io = add_unix_listener path, umask, mode
132
+ io = add_unix_listener path, umask, mode, backlog
128
133
  end
129
134
 
130
135
  @listeners << [str, io]
@@ -298,7 +303,7 @@ module Puma
298
303
 
299
304
  # Tell the server to listen on +path+ as a UNIX domain socket.
300
305
  #
301
- def add_unix_listener(path, umask=nil, mode=nil)
306
+ def add_unix_listener(path, umask=nil, mode=nil, backlog=nil)
302
307
  @unix_paths << path
303
308
 
304
309
  # Let anyone connect by default
@@ -319,6 +324,7 @@ module Puma
319
324
  end
320
325
 
321
326
  s = UNIXServer.new(path)
327
+ s.listen backlog if backlog
322
328
  @ios << s
323
329
  ensure
324
330
  File.umask old_mask
@@ -147,10 +147,14 @@ module Puma
147
147
  c.prune_bundler
148
148
  end
149
149
 
150
- o.on "-q", "--quiet", "Quiet down the output" do
150
+ o.on "-q", "--quiet", "Do not log requests internally (default true)" do
151
151
  c.quiet
152
152
  end
153
153
 
154
+ o.on "-v", "--log-requests", "Log requests as they occur" do
155
+ c.log_requests
156
+ end
157
+
154
158
  o.on "-R", "--restart-cmd CMD",
155
159
  "The puma command to run during a hot restart",
156
160
  "Default: inferred" do |cmd|
@@ -7,6 +7,7 @@ class IO
7
7
  end
8
8
 
9
9
  require 'puma/detect'
10
+ require 'puma/delegation'
10
11
 
11
12
  if Puma::IS_JRUBY
12
13
  # We have to work around some OpenSSL buffer/io-readiness bugs
@@ -21,6 +22,7 @@ module Puma
21
22
 
22
23
  class Client
23
24
  include Puma::Const
25
+ extend Puma::Delegation
24
26
 
25
27
  def initialize(io, env=nil)
26
28
  @io = io
@@ -57,6 +59,8 @@ module Puma
57
59
 
58
60
  attr_accessor :remote_addr_header
59
61
 
62
+ forward :closed?, :@io
63
+
60
64
  def inspect
61
65
  "#<Puma::Client:0x#{object_id.to_s(16)} @ready=#{@ready.inspect}>"
62
66
  end
@@ -52,10 +52,11 @@ module Puma
52
52
  @options = options
53
53
  @first_term_sent = nil
54
54
  @last_checkin = Time.now
55
+ @last_status = '{}'
55
56
  @dead = false
56
57
  end
57
58
 
58
- attr_reader :index, :pid, :phase, :signal, :last_checkin
59
+ attr_reader :index, :pid, :phase, :signal, :last_checkin, :last_status
59
60
 
60
61
  def booted?
61
62
  @stage == :booted
@@ -74,8 +75,9 @@ module Puma
74
75
  @dead = true
75
76
  end
76
77
 
77
- def ping!
78
+ def ping!(status)
78
79
  @last_checkin = Time.now
80
+ @last_status = status
79
81
  end
80
82
 
81
83
  def ping_timeout?(which)
@@ -238,11 +240,14 @@ module Puma
238
240
  end
239
241
 
240
242
  Thread.new(@worker_write) do |io|
241
- payload = "p#{Process.pid}\n"
243
+ base_payload = "p#{Process.pid}"
242
244
 
243
245
  while true
244
246
  sleep 5
245
247
  begin
248
+ b = server.backlog
249
+ r = server.running
250
+ payload = %Q!#{base_payload}{ "backlog":#{b}, "running":#{r} }\n!
246
251
  io << payload
247
252
  rescue IOError
248
253
  break
@@ -301,13 +306,47 @@ module Puma
301
306
  def stats
302
307
  old_worker_count = @workers.count { |w| w.phase != @phase }
303
308
  booted_worker_count = @workers.count { |w| w.booted? }
304
- %Q!{ "workers": #{@workers.size}, "phase": #{@phase}, "booted_workers": #{booted_worker_count}, "old_workers": #{old_worker_count} }!
309
+ worker_status = '[' + @workers.map{ |w| %Q!{ "pid": #{w.pid}, "index": #{w.index}, "phase": #{w.phase}, "booted": #{w.booted?}, "last_checkin": "#{w.last_checkin.utc.iso8601}", "last_status": #{w.last_status} }!}.join(",") + ']'
310
+ %Q!{ "workers": #{@workers.size}, "phase": #{@phase}, "booted_workers": #{booted_worker_count}, "old_workers": #{old_worker_count}, "worker_status": #{worker_status} }!
305
311
  end
306
312
 
307
313
  def preload?
308
314
  @options[:preload_app]
309
315
  end
310
316
 
317
+ # We do this in a separate method to keep the lambad scope
318
+ # of the signals handlers as small as possible.
319
+ def setup_signals
320
+ Signal.trap "SIGCHLD" do
321
+ wakeup!
322
+ end
323
+
324
+ Signal.trap "TTIN" do
325
+ @options[:workers] += 1
326
+ wakeup!
327
+ end
328
+
329
+ Signal.trap "TTOU" do
330
+ @options[:workers] -= 1 if @options[:workers] >= 2
331
+ @workers.last.term
332
+ wakeup!
333
+ end
334
+
335
+ master_pid = Process.pid
336
+
337
+ Signal.trap "SIGTERM" do
338
+ # The worker installs their own SIGTERM when booted.
339
+ # Until then, this is run by the worker and the worker
340
+ # should just exit if they get it.
341
+ if Process.pid != master_pid
342
+ log "Early termination of worker"
343
+ exit! 0
344
+ else
345
+ stop
346
+ end
347
+ end
348
+ end
349
+
311
350
  def run
312
351
  @status = :run
313
352
 
@@ -347,34 +386,7 @@ module Puma
347
386
 
348
387
  read, @wakeup = Puma::Util.pipe
349
388
 
350
- Signal.trap "SIGCHLD" do
351
- wakeup!
352
- end
353
-
354
- Signal.trap "TTIN" do
355
- @options[:workers] += 1
356
- wakeup!
357
- end
358
-
359
- Signal.trap "TTOU" do
360
- @options[:workers] -= 1 if @options[:workers] >= 2
361
- @workers.last.term
362
- wakeup!
363
- end
364
-
365
- master_pid = Process.pid
366
-
367
- Signal.trap "SIGTERM" do
368
- # The worker installs their own SIGTERM when booted.
369
- # Until then, this is run by the worker and the worker
370
- # should just exit if they get it.
371
- if Process.pid != master_pid
372
- log "Early termination of worker"
373
- exit! 0
374
- else
375
- stop
376
- end
377
- end
389
+ setup_signals
378
390
 
379
391
  # Used by the workers to detect if the master process dies.
380
392
  # If select says that @check_pipe is ready, it's because the
@@ -420,7 +432,8 @@ module Puma
420
432
 
421
433
  next if !req || req == "!"
422
434
 
423
- pid = read.gets.to_i
435
+ result = read.gets
436
+ pid = result.to_i
424
437
 
425
438
  if w = @workers.find { |x| x.pid == pid }
426
439
  case req
@@ -432,7 +445,7 @@ module Puma
432
445
  w.dead!
433
446
  force_check = true
434
447
  when "p"
435
- w.ping!
448
+ w.ping!(result.sub(/^\d+/,'').chomp)
436
449
  end
437
450
  else
438
451
  log "! Out-of-sync worker list, no #{pid} worker"
@@ -165,7 +165,7 @@ module Puma
165
165
  {
166
166
  :min_threads => 0,
167
167
  :max_threads => 16,
168
- :quiet => false,
168
+ :log_requests => false,
169
169
  :debug => false,
170
170
  :binds => ["tcp://#{DefaultTCPHost}:#{DefaultTCPPort}"],
171
171
  :workers => 0,
@@ -242,10 +242,10 @@ module Puma
242
242
  require 'puma/tcp_logger'
243
243
 
244
244
  logger = @options[:logger]
245
- return TCPLogger.new(logger, found, @options[:quiet])
245
+ return TCPLogger.new(logger, found, @options[:log_requests])
246
246
  end
247
247
 
248
- if !@options[:quiet] and @options[:environment] == "development"
248
+ if @options[:log_requests]
249
249
  logger = @options[:logger]
250
250
  found = CommonLogger.new(found, logger)
251
251
  end
@@ -99,8 +99,8 @@ module Puma
99
99
  # too taxing on performance.
100
100
  module Const
101
101
 
102
- PUMA_VERSION = VERSION = "3.0.0.rc1".freeze
103
- CODE_NAME = "Schneems Sleak Shoes".freeze
102
+ PUMA_VERSION = VERSION = "3.0.0".freeze
103
+ CODE_NAME = "Plethora of Penguin Pinatas".freeze
104
104
 
105
105
  FAST_TRACK_KA_TIMEOUT = 0.2
106
106
 
@@ -1,9 +1,9 @@
1
1
  require 'optparse'
2
2
  require 'puma/const'
3
3
  require 'puma/configuration'
4
- require 'yaml'
5
4
  require 'uri'
6
5
  require 'socket'
6
+
7
7
  module Puma
8
8
  class ControlCLI
9
9
 
@@ -160,8 +160,14 @@ module Puma
160
160
 
161
161
  # Disable request logging.
162
162
  #
163
- def quiet
164
- @options[:quiet] = true
163
+ def quiet(which=true)
164
+ @options[:log_requests] = !which
165
+ end
166
+
167
+ # Enable request logging
168
+ #
169
+ def log_requests(which=true)
170
+ @options[:log_requests] = which
165
171
  end
166
172
 
167
173
  # Show debugging info
@@ -399,6 +399,7 @@ module Puma
399
399
  #
400
400
  def process_client(client, buffer)
401
401
  begin
402
+ clean_thread_locals = @options[:clean_thread_locals]
402
403
  close_socket = true
403
404
 
404
405
  while true
@@ -412,6 +413,8 @@ module Puma
412
413
  return unless @queue_requests
413
414
  buffer.reset
414
415
 
416
+ ThreadPool.clean_thread_locals if clean_thread_locals
417
+
415
418
  unless client.reset(@status == :run)
416
419
  close_socket = false
417
420
  client.set_timeout @persistent_timeout
@@ -517,63 +520,20 @@ module Puma
517
520
  env['HTTP_X_FORWARDED_PROTO'] == 'https' ? PORT_443 : PORT_80
518
521
  end
519
522
 
520
- # Given the request +env+ from +client+ and a partial request body
521
- # in +body+, finish reading the body if there is one and invoke
522
- # the rack app. Then construct the response and write it back to
523
- # +client+
524
- #
525
- # +cl+ is the previously fetched Content-Length header if there
526
- # was one. This is an optimization to keep from having to look
527
- # it up again.
528
- #
529
- def handle_request(req, lines)
530
- env = req.env
523
+ def handle_app_response(req, lines, env, status, headers, res_body)
531
524
  client = req.io
532
525
 
533
- normalize_env env, req
534
-
535
- env[PUMA_SOCKET] = client
536
-
537
- if env[HTTPS_KEY] && client.peercert
538
- env[PUMA_PEERCERT] = client.peercert
539
- end
540
-
541
- env[HIJACK_P] = true
542
- env[HIJACK] = req
543
-
544
526
  body = req.body
545
527
 
546
528
  head = env[REQUEST_METHOD] == HEAD
547
529
 
548
- env[RACK_INPUT] = body
549
- env[RACK_URL_SCHEME] = env[HTTPS_KEY] ? HTTPS : HTTP
550
-
551
530
  # A rack extension. If the app writes #call'ables to this
552
531
  # array, we will invoke them when the request is done.
553
532
  #
554
- after_reply = env[RACK_AFTER_REPLY] = []
533
+ # (This is already initialized in `handle_request`, just getting here)
534
+ after_reply = env[RACK_AFTER_REPLY]
555
535
 
556
536
  begin
557
- begin
558
- status, headers, res_body = @app.call(env)
559
-
560
- return :async if req.hijacked
561
-
562
- status = status.to_i
563
-
564
- if status == -1
565
- unless headers.empty? and res_body == []
566
- raise "async response must have empty headers and body"
567
- end
568
-
569
- return :async
570
- end
571
- rescue StandardError => e
572
- @events.unknown_error self, e, "Rack app"
573
-
574
- status, headers, res_body = lowlevel_error(e)
575
- end
576
-
577
537
  content_length = nil
578
538
  no_body = head
579
539
 
@@ -715,6 +675,75 @@ module Puma
715
675
  return keep_alive
716
676
  end
717
677
 
678
+ # Given the request +env+ from +client+ and a partial request body
679
+ # in +body+, finish reading the body if there is one and invoke
680
+ # the rack app. Then construct the response and write it back to
681
+ # +client+
682
+ #
683
+ # +cl+ is the previously fetched Content-Length header if there
684
+ # was one. This is an optimization to keep from having to look
685
+ # it up again.
686
+ #
687
+ def handle_request(req, lines)
688
+ env = req.env
689
+ client = req.io
690
+
691
+ normalize_env env, req
692
+
693
+ env[PUMA_SOCKET] = client
694
+
695
+ if env[HTTPS_KEY] && client.peercert
696
+ env[PUMA_PEERCERT] = client.peercert
697
+ end
698
+
699
+ env[HIJACK_P] = true
700
+ env[HIJACK] = req
701
+
702
+ env['async.callback'] = lambda { |__response|
703
+ _status, _headers, _res_body = __response
704
+ # Faye websocket gem also calls this (when available)
705
+ # with status=101, and res_body being a stream
706
+ # but calling here just finishes the response
707
+ # that's why we only response if the request is not
708
+ # hijacked. not sure if this is a correct solution
709
+ # but working. for now.
710
+ unless req.hijacked
711
+ handle_app_response(req, lines, env, _status, _headers, _res_body)
712
+ end
713
+ }
714
+
715
+ body = req.body
716
+
717
+ env[RACK_INPUT] = body
718
+ env[RACK_URL_SCHEME] = env[HTTPS_KEY] ? HTTPS : HTTP
719
+
720
+ env[RACK_AFTER_REPLY] = []
721
+
722
+ begin
723
+ status, headers, res_body = @app.call(env)
724
+
725
+ return :async if req.hijacked
726
+
727
+ status = status.to_i
728
+
729
+ if status == -1
730
+ # unless headers.empty? and res_body == []
731
+ # puts "HEADERS: ".white.on_green + headers.inspect
732
+ # puts "BODY: ".white.on_green + res_body.inspect
733
+ # raise "async response must have empty headers and body"
734
+ # end
735
+
736
+ return :async
737
+ end
738
+ rescue StandardError => e
739
+ @events.unknown_error self, e, "Rack app"
740
+
741
+ status, headers, res_body = lowlevel_error(e, env)
742
+ end
743
+
744
+ return handle_app_response(req, lines, env, status, headers, res_body)
745
+ end
746
+
718
747
  def fetch_status_code(status)
719
748
  HTTP_STATUS_CODES.fetch(status) { 'CUSTOM' }
720
749
  end
@@ -776,9 +805,13 @@ module Puma
776
805
 
777
806
  # A fallback rack response if +@app+ raises as exception.
778
807
  #
779
- def lowlevel_error(e)
808
+ def lowlevel_error(e, env)
780
809
  if handler = @options[:lowlevel_error_handler]
781
- return handler.call(e)
810
+ if handler.arity == 1
811
+ return handler.call(e)
812
+ else
813
+ return handler.call(e, env)
814
+ end
782
815
  end
783
816
 
784
817
  if @leak_stack_on_error
@@ -1,3 +1,5 @@
1
+ require 'yaml'
2
+
1
3
  module Puma
2
4
  class StateFile
3
5
  def initialize
@@ -45,6 +45,12 @@ module Puma
45
45
  attr_reader :spawned, :trim_requested
46
46
  attr_accessor :clean_thread_locals
47
47
 
48
+ def self.clean_thread_locals
49
+ Thread.current.keys.each do |key|
50
+ Thread.current[key] = nil unless key == :__recursive_key__
51
+ end
52
+ end
53
+
48
54
  # How many objects have yet to be processed by the pool?
49
55
  #
50
56
  def backlog
@@ -77,6 +83,7 @@ module Puma
77
83
  if @trim_requested > 0
78
84
  @trim_requested -= 1
79
85
  continue = false
86
+ not_full.signal
80
87
  break
81
88
  end
82
89
 
@@ -97,9 +104,7 @@ module Puma
97
104
  break unless continue
98
105
 
99
106
  if @clean_thread_locals
100
- Thread.current.keys.each do |key|
101
- Thread.current[key] = nil unless key == :__recursive_key__
102
- end
107
+ ThreadPool.clean_thread_locals
103
108
  end
104
109
 
105
110
  begin
@@ -13,6 +13,8 @@ module Rack
13
13
  options = DEFAULT_OPTIONS.merge(options)
14
14
 
15
15
  conf = ::Puma::Configuration.new do |c|
16
+ c.quiet
17
+
16
18
  if options.delete(:Verbose)
17
19
  app = Rack::CommonLogger.new(app, STDOUT)
18
20
  end
@@ -26,10 +28,16 @@ module Rack
26
28
  c.threads min, max
27
29
  end
28
30
 
29
- host = options[:Host] || ::Puma::Configuration::DefaultTCPHost
30
- port = options[:Port] || ::Puma::Configuration::DefaultTCPPort
31
+ host = options[:Host]
32
+
33
+ if host && (host[0,1] == '.' || host[0,1] == '/')
34
+ c.bind "unix://#{host}"
35
+ else
36
+ host ||= ::Puma::Configuration::DefaultTCPHost
37
+ port = options[:Port] || ::Puma::Configuration::DefaultTCPPort
31
38
 
32
- c.port port, host
39
+ c.port port, host
40
+ end
33
41
 
34
42
  c.app app
35
43
  end
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: 3.0.0.rc1
4
+ version: 3.0.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: 2016-02-20 00:00:00.000000000 Z
11
+ date: 2016-02-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rdoc
@@ -95,7 +95,6 @@ extra_rdoc_files:
95
95
  - tools/jungle/init.d/README.md
96
96
  - tools/jungle/upstart/README.md
97
97
  files:
98
- - COPYING
99
98
  - DEPLOYMENT.md
100
99
  - Gemfile
101
100
  - History.txt
@@ -191,9 +190,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
191
190
  version: 1.8.7
192
191
  required_rubygems_version: !ruby/object:Gem::Requirement
193
192
  requirements:
194
- - - ">"
193
+ - - ">="
195
194
  - !ruby/object:Gem::Version
196
- version: 1.3.1
195
+ version: '0'
197
196
  requirements: []
198
197
  rubyforge_project:
199
198
  rubygems_version: 2.5.1
data/COPYING DELETED
@@ -1,55 +0,0 @@
1
- Mongrel Web Server (Mongrel) is copyrighted free software by Zed A. Shaw
2
- <zedshaw at zedshaw dot com> You can redistribute it and/or modify it under
3
- either the terms of the GPL or the conditions below:
4
-
5
- 1. You may make and give away verbatim copies of the source form of the
6
- software without restriction, provided that you duplicate all of the
7
- original copyright notices and associated disclaimers.
8
-
9
- 2. You may modify your copy of the software in any way, provided that
10
- you do at least ONE of the following:
11
-
12
- a) place your modifications in the Public Domain or otherwise make them
13
- Freely Available, such as by posting said modifications to Usenet or an
14
- equivalent medium, or by allowing the author to include your
15
- modifications in the software.
16
-
17
- b) use the modified software only within your corporation or
18
- organization.
19
-
20
- c) rename any non-standard executables so the names do not conflict with
21
- standard executables, which must also be provided.
22
-
23
- d) make other distribution arrangements with the author.
24
-
25
- 3. You may distribute the software in object code or executable
26
- form, provided that you do at least ONE of the following:
27
-
28
- a) distribute the executables and library files of the software,
29
- together with instructions (in the manual page or equivalent) on where
30
- to get the original distribution.
31
-
32
- b) accompany the distribution with the machine-readable source of the
33
- software.
34
-
35
- c) give non-standard executables non-standard names, with
36
- instructions on where to get the original software distribution.
37
-
38
- d) make other distribution arrangements with the author.
39
-
40
- 4. You may modify and include the part of the software into any other
41
- software (possibly commercial). But some files in the distribution
42
- are not written by the author, so that they are not under this terms.
43
-
44
- 5. The scripts and library files supplied as input to or produced as
45
- output from the software do not automatically fall under the
46
- copyright of the software, but belong to whomever generated them,
47
- and may be sold commercially, and may be aggregated with this
48
- software.
49
-
50
- 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
51
- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
52
- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
53
- PURPOSE.
54
-
55
-