puma 2.9.2 → 2.10.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: a3ba7fc9d6258288ee3ccd24615ee3f1cb9bb24e
4
- data.tar.gz: 7acc27c67161d2ccb65cd8dfeabca6bbbafcdc14
3
+ metadata.gz: 2765b2cc720002160a156261825e5c66dcb9fba4
4
+ data.tar.gz: d86005b282c74c803e773f12deeff31f039ee38b
5
5
  SHA512:
6
- metadata.gz: 21029428eda1b5b455a3e8257438211d6635da18ee17375af4ee588a0b968c8d542b86e8d3f73629926b690071c184e47db5e2af159a8ab24302be9f56aad9c4
7
- data.tar.gz: e6e4b25b8e2aa6c8aee2ec52b274ef9af44b2fab47d99396c0cc4f207f394727d4a804348d13008e17a5db6b32e27989ce373a3f2d1af338453c0c03d05c18a4
6
+ metadata.gz: 50322764a2f4962dbda6b6f042a7172493363928829140e4b896cf359285cc8ea4de0830afb9c21bed42aae465f4a04cfce700a9d9cb9a6cfe9e77084ee58e5e
7
+ data.tar.gz: a8e2ea53d31c3f6418fcd9aa2e6d87ae17068fd8bb393d72ec46596b89996b0ab7199a6a6ec747697f4e2977af4229a87fcb3507dac7964e2670fbda16820f1b
@@ -1,4 +1,33 @@
1
- === 2.9.2 / 1024-10-25
1
+ === 2.10.0 / 2014-11-23
2
+
3
+ * 3 minor features:
4
+ * Added on_worker_shutdown hook mechanism
5
+ * Allow binding to ipv6 addresses for ssl URIs
6
+ * Warn about any threads started during app preload
7
+
8
+ * 5 bug fixes:
9
+ * Clean out a threads local data before doing work
10
+ * Disable SSLv3. Fixes #591
11
+ * First change the directory to use the correct Gemfile.
12
+ * Only use config.ru binds if specified. Fixes #606
13
+ * Strongish cipher suite with FS support for some browsers
14
+
15
+ * 2 doc changes:
16
+ * Change umask examples to more permissive values
17
+ * fix typo in README.md
18
+
19
+ * 9 Merged PRs:
20
+ * Merge pull request #560 from raskhadafi/prune_bundler-bug
21
+ * Merge pull request #566 from sheltond/master
22
+ * Merge pull request #593 from andruby/patch-1
23
+ * Merge pull request #594 from hassox/thread-cleanliness
24
+ * Merge pull request #596 from burningTyger/patch-1
25
+ * Merge pull request #601 from sorentwo/friendly-umask
26
+ * Merge pull request #602 from 1334/patch-1
27
+ * Merge pull request #608 from Gu1/master
28
+ * Merge remote-tracking branch 'origin/pr/538'
29
+
30
+ === 2.9.2 / 2014-10-25
2
31
 
3
32
  * 8 bug fixes:
4
33
  * Fix puma-wild handling a restart properly. Fixes #550
data/README.md CHANGED
@@ -116,7 +116,7 @@ If you're preloading your application and using ActiveRecord, it's recommend you
116
116
  ActiveRecord::Base.establish_connection
117
117
  end
118
118
  end
119
-
119
+
120
120
  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.
121
121
 
122
122
  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.
@@ -133,7 +133,7 @@ Want to use UNIX Sockets instead of TCP (which can provide a 5-10% performance b
133
133
 
134
134
  If you need to change the permissions of the UNIX socket, just add a umask parameter:
135
135
 
136
- $ puma -b 'unix:///var/run/puma.sock?umask=0777'
136
+ $ puma -b 'unix:///var/run/puma.sock?umask=0111'
137
137
 
138
138
  Need a bit of security? Use SSL sockets!
139
139
 
@@ -3,6 +3,7 @@
3
3
  #include <rubyio.h>
4
4
  #include <openssl/bio.h>
5
5
  #include <openssl/ssl.h>
6
+ #include <openssl/dh.h>
6
7
  #include <openssl/err.h>
7
8
 
8
9
  typedef struct {
@@ -36,6 +37,42 @@ ms_conn* engine_alloc(VALUE klass, VALUE* obj) {
36
37
  return conn;
37
38
  }
38
39
 
40
+ DH *get_dh1024() {
41
+ /* `openssl dhparam 1024 -C`
42
+ * -----BEGIN DH PARAMETERS-----
43
+ * MIGHAoGBALPwcEv0OstmQCZdfHw0N5r+07lmXMxkpQacy1blwj0LUqC+Divp6pBk
44
+ * usTJ9W2/dOYr1X7zi6yXNLp4oLzc/31PUL3D9q8CpGS7vPz5gijKSw9BwCTT5z9+
45
+ * KF9v46qw8XqT5HHV87sWFlGQcVFq+pEkA2kPikkKZ/X/CCcpCAV7AgEC
46
+ * -----END DH PARAMETERS-----
47
+ */
48
+ static unsigned char dh1024_p[] = {
49
+ 0xB3,0xF0,0x70,0x4B,0xF4,0x3A,0xCB,0x66,0x40,0x26,0x5D,0x7C,
50
+ 0x7C,0x34,0x37,0x9A,0xFE,0xD3,0xB9,0x66,0x5C,0xCC,0x64,0xA5,
51
+ 0x06,0x9C,0xCB,0x56,0xE5,0xC2,0x3D,0x0B,0x52,0xA0,0xBE,0x0E,
52
+ 0x2B,0xE9,0xEA,0x90,0x64,0xBA,0xC4,0xC9,0xF5,0x6D,0xBF,0x74,
53
+ 0xE6,0x2B,0xD5,0x7E,0xF3,0x8B,0xAC,0x97,0x34,0xBA,0x78,0xA0,
54
+ 0xBC,0xDC,0xFF,0x7D,0x4F,0x50,0xBD,0xC3,0xF6,0xAF,0x02,0xA4,
55
+ 0x64,0xBB,0xBC,0xFC,0xF9,0x82,0x28,0xCA,0x4B,0x0F,0x41,0xC0,
56
+ 0x24,0xD3,0xE7,0x3F,0x7E,0x28,0x5F,0x6F,0xE3,0xAA,0xB0,0xF1,
57
+ 0x7A,0x93,0xE4,0x71,0xD5,0xF3,0xBB,0x16,0x16,0x51,0x90,0x71,
58
+ 0x51,0x6A,0xFA,0x91,0x24,0x03,0x69,0x0F,0x8A,0x49,0x0A,0x67,
59
+ 0xF5,0xFF,0x08,0x27,0x29,0x08,0x05,0x7B
60
+ };
61
+ static unsigned char dh1024_g[] = { 0x02 };
62
+
63
+ DH *dh;
64
+ dh = DH_new();
65
+ dh->p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), NULL);
66
+ dh->g = BN_bin2bn(dh1024_g, sizeof(dh1024_g), NULL);
67
+
68
+ if ((dh->p == NULL) || (dh->g == NULL)) {
69
+ DH_free(dh);
70
+ return NULL;
71
+ }
72
+
73
+ return dh;
74
+ }
75
+
39
76
  VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) {
40
77
  VALUE obj;
41
78
  SSL_CTX* ctx;
@@ -54,7 +91,20 @@ VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) {
54
91
 
55
92
  SSL_CTX_use_certificate_file(ctx, RSTRING_PTR(cert), SSL_FILETYPE_PEM);
56
93
  SSL_CTX_use_PrivateKey_file(ctx, RSTRING_PTR(key), SSL_FILETYPE_PEM);
57
- /* SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE); */
94
+
95
+ SSL_CTX_set_options(ctx, SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_SINGLE_DH_USE | SSL_OP_SINGLE_ECDH_USE);
96
+ SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
97
+
98
+ SSL_CTX_set_cipher_list(ctx, "HIGH:!aNULL@STRENGTH");
99
+
100
+ DH *dh = get_dh1024();
101
+ SSL_CTX_set_tmp_dh(ctx, dh);
102
+
103
+ EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_secp521r1);
104
+ if (ecdh) {
105
+ SSL_CTX_set_tmp_ecdh(ctx, ecdh);
106
+ EC_KEY_free(ecdh);
107
+ }
58
108
 
59
109
  ssl = SSL_new(ctx);
60
110
  conn->ssl = ssl;
@@ -227,6 +227,7 @@ module Puma
227
227
  optimize_for_latency=true, backlog=1024)
228
228
  require 'puma/minissl'
229
229
 
230
+ host = host[1..-2] if host[0..0] == '['
230
231
  s = TCPServer.new(host, port)
231
232
  if optimize_for_latency
232
233
  s.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
@@ -99,6 +99,7 @@ module Puma
99
99
  :binds => [],
100
100
  :workers => 0,
101
101
  :daemon => false,
102
+ :before_worker_shutdown => [],
102
103
  :before_worker_boot => [],
103
104
  :after_worker_boot => []
104
105
  }
@@ -228,7 +229,7 @@ module Puma
228
229
 
229
230
  cfg = @config.dup
230
231
 
231
- [ :logger, :before_worker_boot, :after_worker_boot, :on_restart ].each { |o| cfg.options.delete o }
232
+ [ :logger, :before_worker_shutdown, :before_worker_boot, :after_worker_boot, :on_restart ].each { |o| cfg.options.delete o }
232
233
 
233
234
  state["config"] = cfg
234
235
 
@@ -454,6 +455,10 @@ module Puma
454
455
  exit 1
455
456
  end
456
457
 
458
+ if dir = @options[:directory]
459
+ Dir.chdir dir
460
+ end
461
+
457
462
  if prune_bundler? && defined?(Bundler)
458
463
  puma = Bundler.rubygems.loaded_specs("puma")
459
464
 
@@ -483,10 +488,6 @@ module Puma
483
488
  log "! Unable to prune Bundler environment, continuing"
484
489
  end
485
490
 
486
- if dir = @options[:directory]
487
- Dir.chdir dir
488
- end
489
-
490
491
  set_rack_environment
491
492
 
492
493
  if clustered?
@@ -73,7 +73,7 @@ module Puma
73
73
 
74
74
  def term
75
75
  begin
76
- if @first_term_sent && (Time.new - @first_term_sent) > 30
76
+ if @first_term_sent && (Time.new - @first_term_sent) > @options[:worker_shutdown_timeout]
77
77
  @signal = "KILL"
78
78
  else
79
79
  @first_term_sent ||= Time.new
@@ -228,6 +228,10 @@ module Puma
228
228
 
229
229
  server.run.join
230
230
 
231
+ # Invoke any worker shutdown hooks so they can prevent the worker
232
+ # exiting until any background operations are completed
233
+ hooks = @options[:before_worker_shutdown]
234
+ hooks.each { |h| h.call(index) }
231
235
  ensure
232
236
  @worker_write.close
233
237
  end
@@ -278,9 +282,25 @@ module Puma
278
282
 
279
283
  log "* Process workers: #{@options[:workers]}"
280
284
 
285
+ before = Thread.list
286
+
281
287
  if preload?
282
288
  log "* Preloading application"
283
289
  load_and_bind
290
+
291
+ after = Thread.list
292
+
293
+ if after.size > before.size
294
+ threads = (after - before)
295
+ if threads.first.respond_to? :backtrace
296
+ log "! WARNING: Detected #{after.size-before.size} Thread(s) started in app boot:"
297
+ threads.each do |t|
298
+ log "! #{t.inspect} - #{t.backtrace.first}"
299
+ end
300
+ else
301
+ log "! WARNING: Detected #{after.size-before.size} Thread(s) started in app boot"
302
+ end
303
+ end
284
304
  else
285
305
  log "* Phased restart available"
286
306
 
@@ -1,6 +1,6 @@
1
1
  module Puma
2
2
 
3
- # The CLI exports it's Configuration object here to allow
3
+ # The CLI exports its Configuration object here to allow
4
4
  # apps to pick it up. An app needs to use it conditionally though
5
5
  # since it is not set if the app is launched via another
6
6
  # mechanism than the CLI class.
@@ -15,15 +15,18 @@ module Puma
15
15
  DefaultTCPHost = "0.0.0.0"
16
16
  DefaultTCPPort = 9292
17
17
  DefaultWorkerTimeout = 60
18
+ DefaultWorkerShutdownTimeout = 30
18
19
 
19
20
  def initialize(options)
20
21
  @options = options
21
22
  @options[:mode] ||= :http
22
23
  @options[:binds] ||= []
23
24
  @options[:on_restart] ||= []
25
+ @options[:before_worker_shutdown] ||= []
24
26
  @options[:before_worker_boot] ||= []
25
27
  @options[:after_worker_boot] ||= []
26
28
  @options[:worker_timeout] ||= DefaultWorkerTimeout
29
+ @options[:worker_shutdown_timeout] ||= DefaultWorkerShutdownTimeout
27
30
  end
28
31
 
29
32
  attr_reader :options
@@ -82,7 +85,7 @@ module Puma
82
85
  @options[:rackup] || DefaultRackup
83
86
  end
84
87
 
85
- # Load the specified rackup file, pull an options from
88
+ # Load the specified rackup file, pull options from
86
89
  # the rackup file, and set @app.
87
90
  #
88
91
  def app
@@ -96,11 +99,15 @@ module Puma
96
99
  app, options = Rack::Builder.parse_file rackup
97
100
  @options.merge! options
98
101
 
102
+ config_ru_binds = []
103
+
99
104
  options.each do |key,val|
100
105
  if key.to_s[0,4] == "bind"
101
- @options[:binds] << val
106
+ config_ru_binds << val
102
107
  end
103
108
  end
109
+
110
+ @options[:binds] = config_ru_binds unless config_ru_binds.empty?
104
111
  end
105
112
 
106
113
  if @options[:mode] == :tcp
@@ -301,6 +308,17 @@ module Puma
301
308
  @options[:workers] = count.to_i
302
309
  end
303
310
 
311
+ # *Cluster mode only* Code to run immediately before a worker shuts
312
+ # down (after it has finished processing HTTP requests). These hooks
313
+ # can block if necessary to wait for background operations unknown
314
+ # to puma to finish before the process terminates.
315
+ #
316
+ # This can be called multiple times to add hooks.
317
+ #
318
+ def on_worker_shutdown(&block)
319
+ @options[:before_worker_shutdown] << block
320
+ end
321
+
304
322
  # *Cluster mode only* Code to run when a worker boots to setup
305
323
  # the process before booting the app.
306
324
  #
@@ -338,7 +356,7 @@ module Puma
338
356
  @options[:preload_app] = answer
339
357
  end
340
358
 
341
- # Use +obj+ or +block+ as the low lever error handler. This allows a config file to
359
+ # Use +obj+ or +block+ as the low level error handler. This allows a config file to
342
360
  # change the default error on the server.
343
361
  #
344
362
  def lowlevel_error_handler(obj=nil, &block)
@@ -347,7 +365,7 @@ module Puma
347
365
  @options[:lowlevel_error_handler] = obj
348
366
  end
349
367
 
350
- # This option is used to allow your app and it's gems to be
368
+ # This option is used to allow your app and its gems to be
351
369
  # properly reloaded when not using preload.
352
370
  #
353
371
  # When set, if puma detects that it's been invoked in the
@@ -372,6 +390,11 @@ module Puma
372
390
  def worker_timeout(timeout)
373
391
  @options[:worker_timeout] = timeout
374
392
  end
393
+
394
+ # *Cluster mode only* Set the timeout for worker shutdown
395
+ def worker_shutdown_timeout(timeout)
396
+ @options[:worker_shutdown_timeout] = timeout
397
+ end
375
398
  end
376
399
  end
377
400
  end
@@ -28,8 +28,8 @@ module Puma
28
28
  # too taxing on performance.
29
29
  module Const
30
30
 
31
- PUMA_VERSION = VERSION = "2.9.2".freeze
32
- CODE_NAME = "Team High Five".freeze
31
+ PUMA_VERSION = VERSION = "2.10.0".freeze
32
+ CODE_NAME = "Robots on Comets".freeze
33
33
 
34
34
  FAST_TRACK_KA_TIMEOUT = 0.2
35
35
 
@@ -89,6 +89,10 @@ module Puma
89
89
 
90
90
  break unless continue
91
91
 
92
+ Thread.current.keys.each do |key|
93
+ Thread.current[key] = nil unless key == :__recursive_key__
94
+ end
95
+
92
96
  block.call(work, *extra)
93
97
  end
94
98
 
@@ -176,7 +180,9 @@ module Puma
176
180
 
177
181
  # Use this instead of #each so that we don't stop in the middle
178
182
  # of each and see a mutated object mid #each
179
- @workers.first.join until @workers.empty?
183
+ if !@workers.empty?
184
+ @workers.first.join until @workers.empty?
185
+ end
180
186
 
181
187
  @spawned = 0
182
188
  @workers = []
@@ -153,4 +153,28 @@ class TestThreadPool < Test::Unit::TestCase
153
153
 
154
154
  assert_equal 1, pool.spawned
155
155
  end
156
+
157
+ def test_cleanliness
158
+ values = []
159
+ n = 100
160
+ mutex = Mutex.new
161
+
162
+ finished = false
163
+
164
+ pool = new_pool(1,1) {
165
+ mutex.synchronize { values.push Thread.current[:foo] }
166
+ Thread.current[:foo] = :hai
167
+ Thread.pass until finished
168
+ }
169
+
170
+ n.times { pool << 1 }
171
+
172
+ finished = true
173
+
174
+ pause
175
+
176
+ assert_equal n, values.length
177
+
178
+ assert_equal [], values.compact
179
+ end
156
180
  end
@@ -26,7 +26,7 @@ Puma apps are held in /etc/puma.conf by default. It's mainly a CSV file and ever
26
26
 
27
27
  You can add an instance by editing the file or running the following command:
28
28
 
29
- sudo /etc/init.d/puma add /path/to/app user /path/to/app/config/puma.rb /path/to/app/config/log/puma.log
29
+ sudo /etc/init.d/puma add /path/to/app user /path/to/app/config/puma.rb /path/to/app/log/puma.log
30
30
 
31
31
  The config and log paths are optional parameters and default to:
32
32
 
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.9.2
4
+ version: 2.10.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: 2014-10-30 00:00:00.000000000 Z
11
+ date: 2014-11-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -64,14 +64,14 @@ dependencies:
64
64
  requirements:
65
65
  - - "~>"
66
66
  - !ruby/object:Gem::Version
67
- version: '3.13'
67
+ version: '3.12'
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.12'
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