puma 2.6.0-java → 2.7.0-java

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.

@@ -1,3 +1,20 @@
1
+ === 2.7.0 / 2013-12-03
2
+
3
+ * 1 minor feature:
4
+ * Adding TTIN and TTOU to increment/decrement workers
5
+
6
+ * N bug fixes:
7
+ * Always use our Process.daemon because it's not busted
8
+ * Add capistrano restart failback to start.
9
+ * Change position of `cd` so that rvm gemset is loaded
10
+ * Clarify some platform specifics
11
+ * Do not close the pipe sockets when retrying
12
+ * Fix String#byteslice for Ruby 1.9.1, 1.9.2
13
+ * Fix compatibility with 1.8.7.
14
+ * Handle IOError closed stream in IO.select
15
+ * Increase the max URI path length to 2048 chars from 1024 chars
16
+ * Upstart jungle use config/puma.rb instead
17
+
1
18
  === 2.6.0 / 2013-09-13
2
19
 
3
20
  * 2 minor features:
data/README.md CHANGED
@@ -22,7 +22,7 @@ The easiest way to get started with Puma is to install it via RubyGems. You can
22
22
 
23
23
  $ gem install puma
24
24
 
25
- Now you should have the puma command available in your PATH, so just do the following in the root folder of your Rack application:
25
+ Now you should have the `puma` command available in your PATH, so just do the following in the root folder of your Rack application:
26
26
 
27
27
  $ puma app.ru
28
28
 
@@ -82,7 +82,7 @@ Puma 2 offers clustered mode, allowing you to use forked processes to handle mul
82
82
  On a ruby implementation that offers native threads, you should tune this number to match the number of cores available.
83
83
  Note that threads are still used in clustered mode, and the `-t` thread flag setting is per worker, so `-w 2 -t 16:16` will be 32 threads.
84
84
 
85
- If you're running in Clustered Mode you can optionally choose to preload your application before starting up the workers. To do this simply specify the `--preload` flag in invocation:
85
+ If you're running in Clustered Mode you can optionally choose to preload your application before starting up the workers. This is necessary in order to take advantate of the [Copy on Write](http://en.wikipedia.org/wiki/Copy-on-write) feature introduced in [MRI Ruby 2.0](https://blog.heroku.com/archives/2013/3/6/matz_highlights_ruby_2_0_at_waza). To do this simply specify the `--preload` flag in invocation:
86
86
 
87
87
  # CLI invocation
88
88
  $ puma -t 8:32 -w 3 --preload
@@ -104,7 +104,7 @@ Additionally, you can specify a block in your configuration file that will be ru
104
104
  end
105
105
 
106
106
  This code can be used to setup the process before booting the application, allowing
107
- you to do some puma-specific things that you don't want to embed in your application.
107
+ you to do some Puma-specific things that you don't want to embed in your application.
108
108
  For instance, you could fire a log notification that a worker booted or send something to statsd.
109
109
  This can be called multiple times to add hooks.
110
110
 
@@ -137,15 +137,15 @@ Need a bit of security? Use SSL sockets!
137
137
 
138
138
  ### Control/Status Server
139
139
 
140
- 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:
140
+ 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:
141
141
 
142
142
  $ puma --control tcp://127.0.0.1:9293 --control-token foo
143
143
 
144
- This directs puma to start the control server on localhost port 9293. Additionally, all requests to the control server will need to include `token=foo` as a query parameter. This allows for simple authentication. Check out [status.rb](https://github.com/puma/puma/blob/master/lib/puma/app/status.rb) to see what the app has available.
144
+ This directs Puma to start the control server on localhost port 9293. Additionally, all requests to the control server will need to include `token=foo` as a query parameter. This allows for simple authentication. Check out [status.rb](https://github.com/puma/puma/blob/master/lib/puma/app/status.rb) to see what the app has available.
145
145
 
146
146
  ### Configuration file
147
147
 
148
- You can also provide a configuration file which puma will use with the `-C` (or `--config`) flag:
148
+ You can also provide a configuration file which Puma will use with the `-C` (or `--config`) flag:
149
149
 
150
150
  $ puma -C /path/to/config
151
151
 
@@ -153,30 +153,30 @@ Take the following [sample configuration](https://github.com/puma/puma/blob/mast
153
153
 
154
154
  ## Restart
155
155
 
156
- Puma includes the ability to restart itself allowing easy upgrades to new versions. When available (MRI, Rubinius, JRuby), puma performs a "hot restart". This is the same functionality available in *unicorn* and *nginx* which keep the server sockets open between restarts. This makes sure that no pending requests are dropped while the restart is taking place.
156
+ Puma includes the ability to restart itself allowing easy upgrades to new versions. When available (MRI, Rubinius, JRuby), Puma performs a "hot restart". This is the same functionality available in *unicorn* and *nginx* which keep the server sockets open between restarts. This makes sure that no pending requests are dropped while the restart is taking place.
157
157
 
158
158
  To perform a restart, there are 2 builtin mechanisms:
159
159
 
160
- * Send the puma process the `SIGUSR2` signal
160
+ * Send the `puma` process the `SIGUSR2` signal
161
161
  * Use the status server and issue `/restart`
162
162
 
163
- No code is shared between the current and restarted process, so it should be safe to issue a restart any place where you would manually stop puma and start it again.
163
+ No code is shared between the current and restarted process, so it should be safe to issue a restart any place where you would manually stop Puma and start it again.
164
164
 
165
- If the new process is unable to load, it will simply exit. You should therefore run puma under a supervisor when using it in production.
165
+ If the new process is unable to load, it will simply exit. You should therefore run Puma under a supervisor when using it in production.
166
166
 
167
167
  ### Cleanup Code
168
168
 
169
- 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.
169
+ 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.
170
170
 
171
171
  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.
172
172
 
173
173
  ### Platform Constraints
174
174
 
175
- Because of various platforms not being implement certain things, the following differences occur when puma is used on different platforms:
175
+ Because of various platforms not being implement certain things, the following differences occur when Puma is used on different platforms:
176
176
 
177
- * On JRuby and 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.
178
- * On Windows, daemon mode is not supported due to a lack of fork(2).
179
- * On JRuby and Windows, cluster mode is not supported due to a lack of fork(2).
177
+ * **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
178
+ * **JRuby**, **Windows**: cluster mode is not supported due to a lack of fork(2)
179
+ * **Windows**: daemon mode is not supported due to a lack of fork(2)
180
180
 
181
181
  ## pumactl
182
182
 
@@ -30,8 +30,8 @@ public class Http11 extends RubyObject {
30
30
  public final static String MAX_REQUEST_URI_LENGTH_ERR = "HTTP element REQUEST_URI is longer than the 12288 allowed length.";
31
31
  public final static int MAX_FRAGMENT_LENGTH = 1024;
32
32
  public final static String MAX_FRAGMENT_LENGTH_ERR = "HTTP element REQUEST_PATH is longer than the 1024 allowed length.";
33
- public final static int MAX_REQUEST_PATH_LENGTH = 1024;
34
- public final static String MAX_REQUEST_PATH_LENGTH_ERR = "HTTP element REQUEST_PATH is longer than the 1024 allowed length.";
33
+ public final static int MAX_REQUEST_PATH_LENGTH = 2048;
34
+ public final static String MAX_REQUEST_PATH_LENGTH_ERR = "HTTP element REQUEST_PATH is longer than the 2048 allowed length.";
35
35
  public final static int MAX_QUERY_STRING_LENGTH = 1024 * 10;
36
36
  public final static String MAX_QUERY_STRING_LENGTH_ERR = "HTTP element QUERY_STRING is longer than the 10240 allowed length.";
37
37
  public final static int MAX_HEADER_LENGTH = 1024 * (80 + 32);
@@ -52,7 +52,7 @@ DEF_MAX_LENGTH(FIELD_NAME, 256);
52
52
  DEF_MAX_LENGTH(FIELD_VALUE, 80 * 1024);
53
53
  DEF_MAX_LENGTH(REQUEST_URI, 1024 * 12);
54
54
  DEF_MAX_LENGTH(FRAGMENT, 1024); /* Don't know if this length is specified somewhere or not */
55
- DEF_MAX_LENGTH(REQUEST_PATH, 1024);
55
+ DEF_MAX_LENGTH(REQUEST_PATH, 2048);
56
56
  DEF_MAX_LENGTH(QUERY_STRING, (1024 * 10));
57
57
  DEF_MAX_LENGTH(HEADER, (1024 * (80 + 32)));
58
58
 
@@ -28,7 +28,12 @@ Capistrano::Configuration.instance.load do
28
28
 
29
29
  desc 'Restart puma'
30
30
  task :restart, :roles => lambda { puma_role }, :on_no_matching_servers => :continue do
31
- run "cd #{current_path} && #{pumactl_cmd} -S #{state_path} restart"
31
+ begin
32
+ run "cd #{current_path} && #{pumactl_cmd} -S #{state_path} restart"
33
+ rescue Capistrano::CommandError => ex
34
+ puts "Failed to restart puma: #{ex}\nAssuming not started."
35
+ start
36
+ end
32
37
  end
33
38
 
34
39
  desc 'Restart puma (phased restart)'
@@ -283,7 +283,7 @@ module Puma
283
283
  @config.load
284
284
 
285
285
  if clustered?
286
- unsupported "worker mode not supported on JRuby and Windows",
286
+ unsupported "worker mode not supported on JRuby or Windows",
287
287
  jruby? || windows?
288
288
  end
289
289
 
@@ -230,6 +230,17 @@ module Puma
230
230
  wakeup!
231
231
  end
232
232
 
233
+ Signal.trap "TTIN" do
234
+ @options[:workers] += 1
235
+ wakeup!
236
+ end
237
+
238
+ Signal.trap "TTOU" do
239
+ @options[:workers] -= 1 if @options[:workers] >= 2
240
+ @workers.last.term
241
+ wakeup!
242
+ end
243
+
233
244
  master_pid = Process.pid
234
245
 
235
246
  Signal.trap "SIGTERM" do
@@ -6,6 +6,13 @@ class String
6
6
  end
7
7
 
8
8
  unless method_defined? :byteslice
9
- alias_method :byteslice, :[]
9
+ if RUBY_VERSION < '1.9'
10
+ alias_method :byteslice, :[]
11
+ else
12
+ def byteslice(*arg)
13
+ enc = self.encoding
14
+ self.dup.force_encoding(Encoding::ASCII_8BIT).slice(*arg).force_encoding(enc)
15
+ end
16
+ end
10
17
  end
11
18
  end
@@ -28,8 +28,8 @@ module Puma
28
28
  # too taxing on performance.
29
29
  module Const
30
30
 
31
- PUMA_VERSION = VERSION = "2.6.0".freeze
32
- CODE_NAME = "Pantsuit Party"
31
+ PUMA_VERSION = VERSION = "2.7.0".freeze
32
+ CODE_NAME = "Earl of Sandwich Partition"
33
33
 
34
34
  FAST_TRACK_KA_TIMEOUT = 0.2
35
35
 
@@ -1,4 +1,8 @@
1
1
  module Process
2
+
3
+ # This overrides the default version because it is broken if it
4
+ # exists.
5
+
2
6
  def self.daemon(nochdir=false, noclose=false)
3
7
  exit if fork # Parent exits, child continues.
4
8
 
@@ -16,5 +20,5 @@ module Process
16
20
  end
17
21
 
18
22
  0
19
- end unless respond_to?(:daemon)
23
+ end
20
24
  end
@@ -27,15 +27,23 @@ module Puma
27
27
  end
28
28
  end
29
29
 
30
+ def engine_read_all
31
+ output = @engine.read
32
+ while output and additional_output = @engine.read
33
+ output << additional_output
34
+ end
35
+ output
36
+ end
37
+
30
38
  def read_nonblock(size)
31
39
  while true
32
- output = @engine.read
40
+ output = engine_read_all
33
41
  return output if output
34
42
 
35
43
  data = @socket.read_nonblock(size)
36
44
 
37
45
  @engine.inject(data)
38
- output = @engine.read
46
+ output = engine_read_all
39
47
 
40
48
  return output if output
41
49
 
Binary file
@@ -18,11 +18,24 @@ module Puma
18
18
  @sockets = [@ready]
19
19
  end
20
20
 
21
- def run
21
+ private
22
+
23
+ def run_internal
22
24
  sockets = @sockets
23
25
 
24
26
  while true
25
- ready = IO.select sockets, nil, nil, @sleep_for
27
+ begin
28
+ ready = IO.select sockets, nil, nil, @sleep_for
29
+ rescue IOError => e
30
+ if sockets.any? { |socket| socket.closed? }
31
+ STDERR.puts "Error in select: #{e.message} (#{e.class})"
32
+ STDERR.puts e.backtrace
33
+ sockets = sockets.reject { |socket| socket.closed? }
34
+ retry
35
+ else
36
+ raise
37
+ end
38
+ end
26
39
 
27
40
  if ready and reads = ready[0]
28
41
  reads.each do |c|
@@ -95,23 +108,30 @@ module Puma
95
108
  end
96
109
  end
97
110
  end
111
+ end
112
+
113
+ public
114
+
115
+ def run
116
+ run_internal
98
117
  ensure
99
118
  @trigger.close
100
119
  @ready.close
101
120
  end
102
121
 
103
122
  def run_in_thread
104
- @thread = Thread.new {
105
- while true
106
- begin
107
- run
108
- break
109
- rescue StandardError => e
110
- STDERR.puts "Error in reactor loop escaped: #{e.message} (#{e.class})"
111
- puts e.backtrace
112
- end
123
+ @thread = Thread.new do
124
+ begin
125
+ run_internal
126
+ rescue StandardError => e
127
+ STDERR.puts "Error in reactor loop escaped: #{e.message} (#{e.class})"
128
+ STDERR.puts e.backtrace
129
+ retry
130
+ ensure
131
+ @trigger.close
132
+ @ready.close
113
133
  end
114
- }
134
+ end
115
135
  end
116
136
 
117
137
  def calculate_sleep
@@ -17,7 +17,7 @@ require 'puma/rack_patch'
17
17
 
18
18
  require 'puma/puma_http11'
19
19
 
20
- unless Puma.const_defined? "IOBuffer"
20
+ unless Puma.const_defined?("IOBuffer", false)
21
21
  require 'puma/io_buffer'
22
22
  end
23
23
 
@@ -21,7 +21,7 @@ class Http11ParserTest < Test::Unit::TestCase
21
21
  assert_equal '/', req['REQUEST_PATH']
22
22
  assert_equal 'HTTP/1.1', req['HTTP_VERSION']
23
23
  assert_equal '/', req['REQUEST_URI']
24
- assert_equal 'GET', req['REQUEST_METHOD']
24
+ assert_equal 'GET', req['REQUEST_METHOD']
25
25
  assert_nil req['FRAGMENT']
26
26
  assert_nil req['QUERY_STRING']
27
27
 
@@ -81,7 +81,26 @@ class Http11ParserTest < Test::Unit::TestCase
81
81
 
82
82
  return res
83
83
  end
84
-
84
+
85
+ def test_max_uri_path_length
86
+ parser = HttpParser.new
87
+ req = {}
88
+
89
+ # Support URI path length to a max of 2048
90
+ path = "/" + rand_data(1000, 100)
91
+ http = "GET #{path} HTTP/1.1\r\n\r\n"
92
+ parser.execute(req, http, 0)
93
+ assert_equal path, req['REQUEST_PATH']
94
+ parser.reset
95
+
96
+ # Raise exception if URI path length > 2048
97
+ path = "/" + rand_data(2048, 100)
98
+ http = "GET #{path} HTTP/1.1\r\n\r\n"
99
+ assert_raises Puma::HttpParserError do
100
+ parser.execute(req, http, 0)
101
+ parser.reset
102
+ end
103
+ end
85
104
 
86
105
  def test_horrible_queries
87
106
  parser = HttpParser.new
@@ -38,8 +38,6 @@ exec /bin/bash <<'EOT'
38
38
  # set HOME to the setuid user's home, there doesn't seem to be a better, portable way
39
39
  export HOME="$(eval echo ~$(id -un))"
40
40
 
41
- cd $app
42
-
43
41
  if [ -d "$HOME/.rbenv/bin" ]; then
44
42
  export PATH="$HOME/.rbenv/bin:$PATH"
45
43
  elif [ -f /etc/profile.d/rvm.sh ]; then
@@ -57,8 +55,9 @@ exec /bin/bash <<'EOT'
57
55
  # chruby 2.0.0
58
56
  fi
59
57
 
58
+ cd $app
60
59
  logger -t puma "Starting server: $app"
61
60
 
62
- exec bundle exec puma -C config/puma/production.rb
61
+ exec bundle exec puma -C config/puma.rb
63
62
  EOT
64
- end script
63
+ end script
metadata CHANGED
@@ -2,14 +2,14 @@
2
2
  name: puma
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 2.6.0
5
+ version: 2.7.0
6
6
  platform: java
7
7
  authors:
8
8
  - Evan Phoenix
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-09-13 00:00:00.000000000 Z
12
+ date: 2013-12-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack