puma 2.0.1 → 2.1.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/Gemfile CHANGED
@@ -5,4 +5,6 @@ gem "rdoc"
5
5
  gem "rake-compiler"
6
6
  gem "rack"
7
7
 
8
+ gem 'minitest', '~> 4.0'
9
+
8
10
  gem "jruby-openssl", :platform => "jruby"
@@ -1,3 +1,32 @@
1
+ === 2.1.0 / 2013-06-18
2
+
3
+ * 3 minor features:
4
+ * Allow listening socket to be configured via Capistrano variable
5
+ * Output results from 'stat's command when using pumactl
6
+ * Support systemd socket activation
7
+
8
+ * 15 bug fixes:
9
+ * Deal with pipes closing while stopping. Fixes #270
10
+ * Error out early if there is no app configured
11
+ * Handle ConnectionError rather than the lowlevel exceptions
12
+ * tune with `-C` config file and `on_worker_boot`
13
+ * use `-w`
14
+ * Fixed some typos in upstart scripts
15
+ * Make sure to use bytesize instead of size (MiniSSL write)
16
+ * Fix an error in puma-manager.conf
17
+ * fix: stop leaking sockets on restart (affects ruby 1.9.3 or before)
18
+ * Ignore errors on the cross-thread pipe. Fixes #246
19
+ * Ignore errors while uncorking the socket (it might already be closed)
20
+ * Ignore the body on a HEAD request. Fixes #278
21
+ * Handle all engine data when possible. Fixes #251.
22
+ * Handle all read exceptions properly. Fixes #252
23
+ * Handle errors from the server better
24
+
25
+ * 3 doc changes:
26
+ * Add note about on_worker_boot hook
27
+ * Add some documentation for Clustered mode
28
+ * Added quotes to /etc/puma.conf
29
+
1
30
  === 2.0.1 / 2013-04-30
2
31
 
3
32
  * 1 bug fix:
data/README.md CHANGED
@@ -4,6 +4,10 @@
4
4
 
5
5
  ## Description
6
6
 
7
+ 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.
8
+
9
+ ## Built For Speed & Concurrency
10
+
7
11
  Puma is a simple, fast, and highly concurrent HTTP 1.1 server for Ruby web applications. It can be used with any application that supports Rack, and is considered the replacement for Webrick and Mongrel. It was designed to be the go-to server for [Rubinius](http://rubini.us), but also works well with JRuby and MRI. Puma is intended for use in both development and production environments.
8
12
 
9
13
  Under the hood, Puma processes requests using a C-optimized Ragel extension (inherited from Mongrel) that provides fast, accurate HTTP 1.1 protocol parsing in a portable way. Puma then serves the request in a thread from an internal thread pool (which you can control). This allows Puma to provide real concurrency for your web application!
@@ -69,6 +73,31 @@ Puma utilizes a dynamic thread pool which you can modify. You can set the minimu
69
73
 
70
74
  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).
71
75
 
76
+ ### Clustered mode
77
+
78
+ Puma 2 offers clustered mode, allowing you to use forked processes to handle multiple incoming requests concurrently, in addition to threads already provided. You can tune the number of workers with the `-w` (or `--workers`) flag:
79
+
80
+ $ puma -t 8:32 -w 3
81
+
82
+ On a ruby implementation that offers native threads, you should tune this number to match the number of cores available.
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
+
85
+ Additionally, you can specify a block in your configuration that will be run on boot of each worker:
86
+
87
+ # config/puma.rb
88
+ on_worker_boot do
89
+ # configuration here
90
+ end
91
+
92
+ This code can be used to setup the process before booting the application, allowing
93
+ you to do some puma-specific things that you don't want to embed in your application.
94
+ For instance, you could fire a log notification that a worker booted or send something to statsd.
95
+ This can be called multiple times to add hooks.
96
+
97
+ Be sure to specify the location of your configuration file:
98
+
99
+ $ puma -t 8:32 -w 3 -C config/puma.rb
100
+
72
101
  ### Binding TCP / Sockets
73
102
 
74
103
  In contrast to many other server configs which require multiple flags, Puma simply uses one URI parameter with the `-b` (or `--bind`) flag:
@@ -165,4 +194,4 @@ $ bundle exec cap puma:stop
165
194
 
166
195
  ## License
167
196
 
168
- Puma is copyright 2011 Evan Phoenix and contributors. It is licensed under the BSD license. See the include LICENSE file for details.
197
+ Puma is copyright 2013 Evan Phoenix and contributors. It is licensed under the BSD license. See the include LICENSE file for details.
@@ -53,6 +53,24 @@ module Puma
53
53
  @inherited_fds[url] = fd.to_i
54
54
  remove << k
55
55
  end
56
+ if k =~ /LISTEN_FDS/ && ENV['LISTEN_PID'].to_i == $$
57
+ v.to_i.times do |num|
58
+ fd = num + 3
59
+ sock = TCPServer.for_fd(fd)
60
+ begin
61
+ url = "unix://" + Socket.unpack_sockaddr_un(sock.getsockname)
62
+ rescue ArgumentError
63
+ port, addr = Socket.unpack_sockaddr_in(sock.getsockname)
64
+ if addr =~ /\:/
65
+ addr = "[#{addr}]"
66
+ end
67
+ url = "tcp://#{addr}:#{port}"
68
+ end
69
+ @inherited_fds[url] = sock
70
+ end
71
+ ENV.delete k
72
+ ENV.delete 'LISTEN_PID'
73
+ end
56
74
  end
57
75
 
58
76
  remove.each do |k|
@@ -141,7 +159,12 @@ module Puma
141
159
  logger.log "* Closing unused inherited connection: #{str}"
142
160
 
143
161
  begin
144
- IO.for_fd(fd).close
162
+ if fd.kind_of? TCPServer
163
+ fd.close
164
+ else
165
+ IO.for_fd(fd).close
166
+ end
167
+
145
168
  rescue SystemCallError
146
169
  end
147
170
 
@@ -244,7 +267,11 @@ module Puma
244
267
  def inherit_unix_listener(path, fd)
245
268
  @unix_paths << path
246
269
 
247
- s = UNIXServer.for_fd fd
270
+ if fd.kind_of? TCPServer
271
+ s = fd
272
+ else
273
+ s = UNIXServer.for_fd fd
274
+ end
248
275
  @ios << s
249
276
 
250
277
  s
@@ -11,13 +11,14 @@ Capistrano::Configuration.instance.load do
11
11
  _cset(:puma_cmd) { "#{fetch(:bundle_cmd, 'bundle')} exec puma" }
12
12
  _cset(:pumactl_cmd) { "#{fetch(:bundle_cmd, 'bundle')} exec pumactl" }
13
13
  _cset(:puma_state) { "#{shared_path}/sockets/puma.state" }
14
+ _cset(:puma_socket) { "unix://#{shared_path}/sockets/puma.sock" }
14
15
  _cset(:puma_role) { :app }
15
16
 
16
17
  namespace :puma do
17
18
  desc 'Start puma'
18
19
  task :start, :roles => lambda { fetch(:puma_role) }, :on_no_matching_servers => :continue do
19
20
  puma_env = fetch(:rack_env, fetch(:rails_env, 'production'))
20
- run "cd #{current_path} && #{fetch(:puma_cmd)} -q -d -e #{puma_env} -b 'unix://#{shared_path}/sockets/puma.sock' -S #{fetch(:puma_state)} --control 'unix://#{shared_path}/sockets/pumactl.sock'", :pty => false
21
+ run "cd #{current_path} && #{fetch(:puma_cmd)} -q -d -e #{puma_env} -b '#{fetch(:puma_socket)}' -S #{fetch(:puma_state)} --control 'unix://#{shared_path}/sockets/pumactl.sock'", :pty => false
21
22
  end
22
23
 
23
24
  desc 'Stop puma'
@@ -117,7 +117,7 @@ module Puma
117
117
  require 'puma/jruby_restart'
118
118
  JRubyRestart.chdir_exec(@restart_dir, @restart_argv)
119
119
  else
120
- redirects = {}
120
+ redirects = {:close_others => true}
121
121
  @binder.listeners.each_with_index do |(l,io),i|
122
122
  ENV["PUMA_INHERIT_#{i}"] = "#{io.to_i}:#{l}"
123
123
  redirects[io.to_i] = io.to_i
@@ -419,6 +419,11 @@ module Puma
419
419
 
420
420
  @binder.parse @options[:binds], self
421
421
 
422
+ unless @config.app_configured?
423
+ error "No application configured, nothing to run"
424
+ exit 1
425
+ end
426
+
422
427
  if @options[:daemon]
423
428
  Process.daemon(true, @io_redirected)
424
429
  end
@@ -547,7 +552,12 @@ module Puma
547
552
  server.stop
548
553
  end
549
554
 
550
- @worker_write << "b#{Process.pid}\n"
555
+ begin
556
+ @worker_write << "b#{Process.pid}\n"
557
+ rescue SystemCallError, IOError
558
+ STDERR.puts "Master seems to have exitted, exitting."
559
+ return
560
+ end
551
561
 
552
562
  server.run.join
553
563
 
@@ -643,6 +653,13 @@ module Puma
643
653
  end
644
654
  end
645
655
 
656
+ def wakeup!
657
+ begin
658
+ @wakeup.write "!" unless @wakeup.closed?
659
+ rescue SystemCallError, IOError
660
+ end
661
+ end
662
+
646
663
  def run_cluster
647
664
  log "Puma #{Puma::Const::PUMA_VERSION} starting in cluster mode..."
648
665
  log "* Process workers: #{@options[:workers]}"
@@ -651,10 +668,15 @@ module Puma
651
668
 
652
669
  @binder.parse @options[:binds], self
653
670
 
654
- read, write = Puma::Util.pipe
671
+ unless @config.app_configured?
672
+ error "No application configured, nothing to run"
673
+ exit 1
674
+ end
675
+
676
+ read, @wakeup = Puma::Util.pipe
655
677
 
656
678
  Signal.trap "SIGCHLD" do
657
- write.write "!"
679
+ wakeup!
658
680
  end
659
681
 
660
682
  stop = false
@@ -663,7 +685,7 @@ module Puma
663
685
  Signal.trap "SIGUSR2" do
664
686
  @restart = true
665
687
  stop = true
666
- write.write "!"
688
+ wakeup!
667
689
  end
668
690
  rescue Exception
669
691
  end
@@ -672,7 +694,7 @@ module Puma
672
694
 
673
695
  begin
674
696
  Signal.trap "SIGTERM" do
675
- # The worker installs there own SIGTERM when booted.
697
+ # The worker installs their own SIGTERM when booted.
676
698
  # Until then, this is run by the worker and the worker
677
699
  # should just exit if they get it.
678
700
  if Process.pid != master_pid
@@ -680,7 +702,7 @@ module Puma
680
702
  exit! 0
681
703
  else
682
704
  stop = true
683
- write.write "!"
705
+ wakeup!
684
706
  end
685
707
  end
686
708
  rescue Exception
@@ -691,7 +713,7 @@ module Puma
691
713
  begin
692
714
  Signal.trap "SIGUSR1" do
693
715
  phased_restart = true
694
- write.write "!"
716
+ wakeup!
695
717
  end
696
718
  rescue Exception
697
719
  end
@@ -715,12 +737,12 @@ module Puma
715
737
 
716
738
  write_state
717
739
 
718
- @master_read, @worker_write = read, write
740
+ @master_read, @worker_write = read, @wakeup
719
741
  spawn_workers
720
742
 
721
743
  Signal.trap "SIGINT" do
722
744
  stop = true
723
- write.write "!"
745
+ wakeup!
724
746
  end
725
747
 
726
748
  begin
@@ -761,7 +783,7 @@ module Puma
761
783
  @check_pipe.close
762
784
  @suicide_pipe.close
763
785
  read.close
764
- write.close
786
+ @wakeup.close
765
787
  end
766
788
 
767
789
  if @restart
@@ -16,6 +16,9 @@ if Puma::IS_JRUBY
16
16
  end
17
17
 
18
18
  module Puma
19
+
20
+ class ConnectionError < RuntimeError; end
21
+
19
22
  class Client
20
23
  include Puma::Const
21
24
 
@@ -139,6 +142,8 @@ module Puma
139
142
  data = @io.read_nonblock(CHUNK_SIZE)
140
143
  rescue Errno::EAGAIN
141
144
  return false
145
+ rescue SystemCallError, IOError
146
+ raise ConnectionError, "Connection error detected during read"
142
147
  end
143
148
 
144
149
  if @buffer
@@ -223,6 +228,8 @@ module Puma
223
228
  chunk = @io.read_nonblock(want)
224
229
  rescue Errno::EAGAIN
225
230
  return false
231
+ rescue SystemCallError, IOError
232
+ raise ConnectionError, "Connection error detected during read"
226
233
  end
227
234
 
228
235
  # No chunk means a closed socket
@@ -67,6 +67,16 @@ module Puma
67
67
  end
68
68
  end
69
69
 
70
+ # Indicate if there is a properly configured app
71
+ #
72
+ def app_configured?
73
+ @options[:app] || File.exists?(rackup)
74
+ end
75
+
76
+ def rackup
77
+ @options[:rackup] || DefaultRackup
78
+ end
79
+
70
80
  # Load the specified rackup file, pull an options from
71
81
  # the rackup file, and set @app.
72
82
  #
@@ -74,13 +84,11 @@ module Puma
74
84
  app = @options[:app]
75
85
 
76
86
  unless app
77
- path = @options[:rackup] || DefaultRackup
78
-
79
- unless File.exists?(path)
80
- raise "Missing rackup file '#{path}'"
87
+ unless File.exists?(rackup)
88
+ raise "Missing rackup file '#{rackup}'"
81
89
  end
82
90
 
83
- app, options = Rack::Builder.parse_file path
91
+ app, options = Rack::Builder.parse_file rackup
84
92
  @options.merge! options
85
93
 
86
94
  options.each do |key,val|
@@ -28,7 +28,7 @@ module Puma
28
28
  # too taxing on performance.
29
29
  module Const
30
30
 
31
- PUMA_VERSION = VERSION = "2.0.1".freeze
31
+ PUMA_VERSION = VERSION = "2.1.0".freeze
32
32
 
33
33
  FAST_TRACK_KA_TIMEOUT = 0.2
34
34
 
@@ -138,7 +138,15 @@ module Puma
138
138
 
139
139
  @server << "GET #{url} HTTP/1.0\r\n\r\n"
140
140
 
141
- response = @server.read.split("\r\n")
141
+ unless data = @server.read
142
+ raise "Server closed connection before responding"
143
+ end
144
+
145
+ response = data.split("\r\n")
146
+
147
+ if response.empty?
148
+ raise "Server sent empty response"
149
+ end
142
150
 
143
151
  (@http,@code,@message) = response.first.split(" ")
144
152
 
@@ -149,6 +157,7 @@ module Puma
149
157
  end
150
158
 
151
159
  message "Command #{@options[:command]} sent success"
160
+ message response.last if @options[:command] == "stats"
152
161
  end
153
162
 
154
163
  @server.close
@@ -46,19 +46,20 @@ module Puma
46
46
  end
47
47
 
48
48
  def write(data)
49
- need = data.size
49
+ need = data.bytesize
50
50
 
51
51
  while true
52
52
  wrote = @engine.write data
53
53
  enc = @engine.extract
54
54
 
55
- if enc
56
- @socket.syswrite enc
55
+ while enc
56
+ @socket.write enc
57
+ enc = @engine.extract
57
58
  end
58
59
 
59
60
  need -= wrote
60
61
 
61
- return data.size if need == 0
62
+ return data.bytesize if need == 0
62
63
 
63
64
  data = data[need..-1]
64
65
  end
@@ -94,7 +94,10 @@ module Puma
94
94
  end
95
95
 
96
96
  def uncork_socket(socket)
97
- socket.setsockopt(6, 3, 0) if socket.kind_of? TCPSocket
97
+ begin
98
+ socket.setsockopt(6, 3, 0) if socket.kind_of? TCPSocket
99
+ rescue IOError
100
+ end
98
101
  end
99
102
  else
100
103
  def cork_socket(socket)
@@ -135,7 +138,7 @@ module Puma
135
138
  client.close
136
139
 
137
140
  @events.parse_error self, client.env, e
138
- rescue IOError
141
+ rescue ConnectionError
139
142
  client.close
140
143
  else
141
144
  if process_now
@@ -259,7 +262,7 @@ module Puma
259
262
  end
260
263
 
261
264
  # The client disconnected while we were reading data
262
- rescue IOError, SystemCallError => e
265
+ rescue ConnectionError
263
266
  # Swallow them. The ensure tries to close +client+ down
264
267
 
265
268
  # The client doesn't know HTTP well
@@ -351,6 +354,8 @@ module Puma
351
354
 
352
355
  body = req.body
353
356
 
357
+ head = env[REQUEST_METHOD] == HEAD
358
+
354
359
  env[RACK_INPUT] = body
355
360
  env[RACK_URL_SCHEME] = env[HTTPS_KEY] ? HTTPS : HTTP
356
361
 
@@ -381,7 +386,7 @@ module Puma
381
386
  end
382
387
 
383
388
  content_length = nil
384
- no_body = false
389
+ no_body = head
385
390
 
386
391
  if res_body.kind_of? Array and res_body.size == 1
387
392
  content_length = res_body[0].bytesize
@@ -407,7 +412,7 @@ module Puma
407
412
  lines.append "HTTP/1.1 ", status.to_s, " ",
408
413
  HTTP_STATUS_CODES[status], line_ending
409
414
 
410
- no_body = status < 200 || STATUS_WITH_NO_ENTITY_BODY[status]
415
+ no_body ||= status < 200 || STATUS_WITH_NO_ENTITY_BODY[status]
411
416
  end
412
417
  else
413
418
  allow_chunked = false
@@ -422,7 +427,7 @@ module Puma
422
427
  lines.append "HTTP/1.0 ", status.to_s, " ",
423
428
  HTTP_STATUS_CODES[status], line_ending
424
429
 
425
- no_body = status < 200 || STATUS_WITH_NO_ENTITY_BODY[status]
430
+ no_body ||= status < 200 || STATUS_WITH_NO_ENTITY_BODY[status]
426
431
  end
427
432
  end
428
433
 
@@ -579,19 +584,31 @@ module Puma
579
584
  # off the request queue before finally exiting.
580
585
  #
581
586
  def stop(sync=false)
582
- @notify << STOP_COMMAND
587
+ begin
588
+ @notify << STOP_COMMAND
589
+ rescue IOError
590
+ # The server, in another thread, is shutting down
591
+ end
583
592
 
584
593
  @thread.join if @thread && sync
585
594
  end
586
595
 
587
596
  def halt(sync=false)
588
- @notify << HALT_COMMAND
597
+ begin
598
+ @notify << HALT_COMMAND
599
+ rescue IOError
600
+ # The server, in another thread, is shutting down
601
+ end
589
602
 
590
603
  @thread.join if @thread && sync
591
604
  end
592
605
 
593
606
  def begin_restart
594
- @notify << RESTART_COMMAND
607
+ begin
608
+ @notify << RESTART_COMMAND
609
+ rescue IOError
610
+ # The server, in another thread, is shutting down
611
+ end
595
612
  end
596
613
 
597
614
  def fast_write(io, str)
@@ -2,12 +2,12 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "puma"
5
- s.version = "2.0.1"
5
+ s.version = "2.1.0"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Evan Phoenix"]
9
- s.date = "2013-04-30"
10
- s.description = "Puma is a simple, fast, and highly concurrent HTTP 1.1 server for Ruby web applications. It can be used with any application that supports Rack, and is considered the replacement for Webrick and Mongrel. It was designed to be the go-to server for [Rubinius](http://rubini.us), but also works well with JRuby and MRI. Puma is intended for use in both development and production environments.\n\nUnder the hood, Puma processes requests using a C-optimized Ragel extension (inherited from Mongrel) that provides fast, accurate HTTP 1.1 protocol parsing in a portable way. Puma then serves the request in a thread from an internal thread pool (which you can control). This allows Puma to provide real concurrency for your web application!\n\nWith Rubinius 2.0, Puma will utilize all cores on your CPU with real threads, meaning you won't have to spawn multiple processes to increase throughput. You can expect to see a similar benefit from JRuby.\n\nOn MRI, there is a Global Interpreter Lock (GIL) that ensures only one thread can be run at a time. But if you're doing a lot of blocking IO (such as HTTP calls to external APIs like Twitter), Puma still improves MRI's throughput by allowing blocking IO to be run concurrently (EventMachine-based servers such as Thin turn off this ability, requiring you to use special libraries). Your mileage may vary. In order to get the best throughput, it is highly recommended that you use a Ruby implementation with real threads like [Rubinius](http://rubini.us) or [JRuby](http://jruby.org)."
9
+ s.date = "2013-06-18"
10
+ 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."
11
11
  s.email = ["evan@phx.io"]
12
12
  s.executables = ["puma", "pumactl"]
13
13
  s.extensions = ["ext/puma_http11/extconf.rb"]
@@ -19,7 +19,7 @@ Gem::Specification.new do |s|
19
19
  s.required_ruby_version = Gem::Requirement.new(">= 1.8.7")
20
20
  s.rubyforge_project = "puma"
21
21
  s.rubygems_version = "1.8.25"
22
- s.summary = "Puma is a simple, fast, and highly concurrent HTTP 1.1 server for Ruby web applications"
22
+ s.summary = "Puma is a simple, fast, threaded, and highly concurrent HTTP 1.1 server for Ruby/Rack applications"
23
23
  s.test_files = ["test/test_app_status.rb", "test/test_cli.rb", "test/test_config.rb", "test/test_http10.rb", "test/test_http11.rb", "test/test_integration.rb", "test/test_iobuffer.rb", "test/test_minissl.rb", "test/test_null_io.rb", "test/test_persistent.rb", "test/test_puma_server.rb", "test/test_rack_handler.rb", "test/test_rack_server.rb", "test/test_thread_pool.rb", "test/test_unix_socket.rb", "test/test_ws.rb"]
24
24
 
25
25
  if s.respond_to? :specification_version then
@@ -82,7 +82,7 @@ class TestAppStatus < Test::Unit::TestCase
82
82
  end
83
83
 
84
84
  def test_alternate_location
85
- status, _ , app = lint('__alternatE_location_/stats')
85
+ status, _ , _ = lint('__alternatE_location_/stats')
86
86
  assert_equal 200, status
87
87
  end
88
88
  end
@@ -162,4 +162,46 @@ class TestPumaServer < Test::Unit::TestCase
162
162
 
163
163
  assert_equal "80", res.body
164
164
  end
165
+
166
+ def test_HEAD_has_no_body
167
+ @server.app = proc { |env| [200, {"Foo" => "Bar"}, ["hello"]] }
168
+
169
+ @server.add_tcp_listener @host, @port
170
+ @server.run
171
+
172
+ sock = TCPSocket.new @host, @port
173
+ sock << "HEAD / HTTP/1.0\r\n\r\n"
174
+
175
+ data = sock.read
176
+
177
+ assert_equal "HTTP/1.0 200 OK\r\nFoo: Bar\r\n\r\n", data
178
+ end
179
+
180
+ def test_GET_with_empty_body_has_sane_chunking
181
+ @server.app = proc { |env| [200, {}, [""]] }
182
+
183
+ @server.add_tcp_listener @host, @port
184
+ @server.run
185
+
186
+ sock = TCPSocket.new @host, @port
187
+ sock << "HEAD / HTTP/1.0\r\n\r\n"
188
+
189
+ data = sock.read
190
+
191
+ assert_equal "HTTP/1.0 200 OK\r\n\r\n", data
192
+ end
193
+
194
+ def test_GET_with_no_body_has_sane_chunking
195
+ @server.app = proc { |env| [200, {}, [""]] }
196
+
197
+ @server.add_tcp_listener @host, @port
198
+ @server.run
199
+
200
+ sock = TCPSocket.new @host, @port
201
+ sock << "HEAD / HTTP/1.0\r\n\r\n"
202
+
203
+ data = sock.read
204
+
205
+ assert_equal "HTTP/1.0 200 OK\r\n\r\n", data
206
+ end
165
207
  end
@@ -6,9 +6,9 @@
6
6
  #
7
7
  # See puma.conf for how to manage a single Puma instance.
8
8
  #
9
- # Use "stop workers" to stop all Puma instances.
10
- # Use "start workers" to start all instances.
11
- # Use "restart workers" to restart all instances.
9
+ # Use "stop puma-manager" to stop all Puma instances.
10
+ # Use "start puma-manager" to start all instances.
11
+ # Use "restart puma-manager" to restart all instances.
12
12
  # Crazy, right?
13
13
  #
14
14
 
@@ -20,12 +20,12 @@ stop on runlevel [06]
20
20
 
21
21
  # Set this to the number of Puma processes you want
22
22
  # to run on this machine
23
- env PUMA_CONF=/etc/puma.conf
23
+ env PUMA_CONF="/etc/puma.conf"
24
24
 
25
25
  pre-start script
26
26
  for i in `cat $PUMA_CONF`; do
27
27
  app=`echo $i | cut -d , -f 1`
28
- logger -t "puma-manager" "Starting $app"
28
+ logger -t "puma-manager" "Starting $app"
29
29
  start puma app=$app
30
30
  done
31
31
  end script
@@ -6,7 +6,7 @@
6
6
  #
7
7
  # See workers.conf for how to manage all Puma instances at once.
8
8
  #
9
- # Save this config as /etc/init/puma.conf then mange puma with:
9
+ # Save this config as /etc/init/puma.conf then manage puma with:
10
10
  # sudo start puma index=0
11
11
  # sudo stop puma index=0
12
12
  # sudo status puma index=0
@@ -34,7 +34,7 @@ script
34
34
  # respawn as bash so we can source in rbenv/rvm
35
35
  exec /bin/bash <<EOT
36
36
  export HOME=/home/apps
37
-
37
+
38
38
  # Pick your poison :) Or none if you're using a system wide installed Ruby.
39
39
  # rbenv
40
40
  # source /home/apps/.bash_profile
metadata CHANGED
@@ -1,201 +1,218 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: puma
3
- version: !ruby/object:Gem::Version
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.1.0
4
5
  prerelease:
5
- version: 2.0.1
6
6
  platform: ruby
7
- authors:
8
- - Evan Phoenix
7
+ authors:
8
+ - Evan Phoenix
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
-
13
- date: 2013-04-30 00:00:00 Z
14
- dependencies:
15
- - !ruby/object:Gem::Dependency
16
- name: rack
17
- version_requirements: &id001 !ruby/object:Gem::Requirement
18
- none: false
19
- requirements:
20
- - - ">="
21
- - !ruby/object:Gem::Version
22
- version: "1.1"
23
- - - <
24
- - !ruby/object:Gem::Version
25
- version: "2.0"
26
- requirement: *id001
27
- prerelease: false
28
- type: :runtime
29
- - !ruby/object:Gem::Dependency
30
- name: rdoc
31
- version_requirements: &id002 !ruby/object:Gem::Requirement
32
- none: false
33
- requirements:
34
- - - ~>
35
- - !ruby/object:Gem::Version
36
- version: "3.10"
37
- requirement: *id002
38
- prerelease: false
39
- type: :development
40
- - !ruby/object:Gem::Dependency
41
- name: rake-compiler
42
- version_requirements: &id003 !ruby/object:Gem::Requirement
43
- none: false
44
- requirements:
45
- - - ~>
46
- - !ruby/object:Gem::Version
47
- version: 0.8.0
48
- requirement: *id003
49
- prerelease: false
50
- type: :development
51
- - !ruby/object:Gem::Dependency
52
- name: hoe
53
- version_requirements: &id004 !ruby/object:Gem::Requirement
54
- none: false
55
- requirements:
56
- - - ~>
57
- - !ruby/object:Gem::Version
58
- version: "3.5"
59
- requirement: *id004
60
- prerelease: false
61
- type: :development
62
- description: |-
63
- Puma is a simple, fast, and highly concurrent HTTP 1.1 server for Ruby web applications. It can be used with any application that supports Rack, and is considered the replacement for Webrick and Mongrel. It was designed to be the go-to server for [Rubinius](http://rubini.us), but also works well with JRuby and MRI. Puma is intended for use in both development and production environments.
64
-
65
- Under the hood, Puma processes requests using a C-optimized Ragel extension (inherited from Mongrel) that provides fast, accurate HTTP 1.1 protocol parsing in a portable way. Puma then serves the request in a thread from an internal thread pool (which you can control). This allows Puma to provide real concurrency for your web application!
66
-
67
- With Rubinius 2.0, Puma will utilize all cores on your CPU with real threads, meaning you won't have to spawn multiple processes to increase throughput. You can expect to see a similar benefit from JRuby.
68
-
69
- On MRI, there is a Global Interpreter Lock (GIL) that ensures only one thread can be run at a time. But if you're doing a lot of blocking IO (such as HTTP calls to external APIs like Twitter), Puma still improves MRI's throughput by allowing blocking IO to be run concurrently (EventMachine-based servers such as Thin turn off this ability, requiring you to use special libraries). Your mileage may vary. In order to get the best throughput, it is highly recommended that you use a Ruby implementation with real threads like [Rubinius](http://rubini.us) or [JRuby](http://jruby.org).
70
- email:
71
- - evan@phx.io
72
- executables:
73
- - puma
74
- - pumactl
75
- extensions:
76
- - ext/puma_http11/extconf.rb
77
- extra_rdoc_files:
78
- - History.txt
79
- - Manifest.txt
80
- files:
81
- - COPYING
82
- - Gemfile
83
- - History.txt
84
- - LICENSE
85
- - Manifest.txt
86
- - README.md
87
- - Rakefile
88
- - TODO
89
- - bin/puma
90
- - bin/pumactl
91
- - docs/config.md
92
- - docs/nginx.md
93
- - ext/puma_http11/PumaHttp11Service.java
94
- - ext/puma_http11/ext_help.h
95
- - ext/puma_http11/extconf.rb
96
- - ext/puma_http11/http11_parser.c
97
- - ext/puma_http11/http11_parser.h
98
- - ext/puma_http11/http11_parser.java.rl
99
- - ext/puma_http11/http11_parser.rl
100
- - ext/puma_http11/http11_parser_common.rl
101
- - ext/puma_http11/io_buffer.c
102
- - ext/puma_http11/mini_ssl.c
103
- - ext/puma_http11/org/jruby/puma/Http11.java
104
- - ext/puma_http11/org/jruby/puma/Http11Parser.java
105
- - ext/puma_http11/org/jruby/puma/MiniSSL.java
106
- - ext/puma_http11/puma_http11.c
107
- - lib/puma.rb
108
- - lib/puma/accept_nonblock.rb
109
- - lib/puma/app/status.rb
110
- - lib/puma/binder.rb
111
- - lib/puma/capistrano.rb
112
- - lib/puma/cli.rb
113
- - lib/puma/client.rb
114
- - lib/puma/compat.rb
115
- - lib/puma/configuration.rb
116
- - lib/puma/const.rb
117
- - lib/puma/control_cli.rb
118
- - lib/puma/daemon_ext.rb
119
- - lib/puma/delegation.rb
120
- - lib/puma/detect.rb
121
- - lib/puma/events.rb
122
- - lib/puma/io_buffer.rb
123
- - lib/puma/java_io_buffer.rb
124
- - lib/puma/jruby_restart.rb
125
- - lib/puma/minissl.rb
126
- - lib/puma/null_io.rb
127
- - lib/puma/rack_default.rb
128
- - lib/puma/rack_patch.rb
129
- - lib/puma/reactor.rb
130
- - lib/puma/server.rb
131
- - lib/puma/thread_pool.rb
132
- - lib/puma/util.rb
133
- - lib/rack/handler/puma.rb
134
- - puma.gemspec
135
- - tools/jungle/init.d/README.md
136
- - tools/jungle/init.d/puma
137
- - tools/jungle/init.d/run-puma
138
- - tools/jungle/upstart/README.md
139
- - tools/jungle/upstart/puma-manager.conf
140
- - tools/jungle/upstart/puma.conf
141
- - test/test_app_status.rb
142
- - test/test_cli.rb
143
- - test/test_config.rb
144
- - test/test_http10.rb
145
- - test/test_http11.rb
146
- - test/test_integration.rb
147
- - test/test_iobuffer.rb
148
- - test/test_minissl.rb
149
- - test/test_null_io.rb
150
- - test/test_persistent.rb
151
- - test/test_puma_server.rb
152
- - test/test_rack_handler.rb
153
- - test/test_rack_server.rb
154
- - test/test_thread_pool.rb
155
- - test/test_unix_socket.rb
156
- - test/test_ws.rb
12
+ date: 2013-06-18 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rack
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '1.1'
22
+ - - <
23
+ - !ruby/object:Gem::Version
24
+ version: '2.0'
25
+ type: :runtime
26
+ prerelease: false
27
+ version_requirements: !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '1.1'
33
+ - - <
34
+ - !ruby/object:Gem::Version
35
+ version: '2.0'
36
+ - !ruby/object:Gem::Dependency
37
+ name: rdoc
38
+ requirement: !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: '3.10'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: !ruby/object:Gem::Requirement
47
+ none: false
48
+ requirements:
49
+ - - ~>
50
+ - !ruby/object:Gem::Version
51
+ version: '3.10'
52
+ - !ruby/object:Gem::Dependency
53
+ name: rake-compiler
54
+ requirement: !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ~>
58
+ - !ruby/object:Gem::Version
59
+ version: 0.8.0
60
+ type: :development
61
+ prerelease: false
62
+ version_requirements: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ~>
66
+ - !ruby/object:Gem::Version
67
+ version: 0.8.0
68
+ - !ruby/object:Gem::Dependency
69
+ name: hoe
70
+ requirement: !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: '3.5'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ none: false
80
+ requirements:
81
+ - - ~>
82
+ - !ruby/object:Gem::Version
83
+ version: '3.5'
84
+ description: Puma is a simple, fast, threaded, and highly concurrent HTTP 1.1 server
85
+ for Ruby/Rack applications. Puma is intended for use in both development and production
86
+ environments. In order to get the best throughput, it is highly recommended that
87
+ you use a Ruby implementation with real threads like Rubinius or JRuby.
88
+ email:
89
+ - evan@phx.io
90
+ executables:
91
+ - puma
92
+ - pumactl
93
+ extensions:
94
+ - ext/puma_http11/extconf.rb
95
+ extra_rdoc_files:
96
+ - History.txt
97
+ - Manifest.txt
98
+ files:
99
+ - COPYING
100
+ - Gemfile
101
+ - History.txt
102
+ - LICENSE
103
+ - Manifest.txt
104
+ - README.md
105
+ - Rakefile
106
+ - TODO
107
+ - bin/puma
108
+ - bin/pumactl
109
+ - docs/config.md
110
+ - docs/nginx.md
111
+ - ext/puma_http11/PumaHttp11Service.java
112
+ - ext/puma_http11/ext_help.h
113
+ - ext/puma_http11/extconf.rb
114
+ - ext/puma_http11/http11_parser.c
115
+ - ext/puma_http11/http11_parser.h
116
+ - ext/puma_http11/http11_parser.java.rl
117
+ - ext/puma_http11/http11_parser.rl
118
+ - ext/puma_http11/http11_parser_common.rl
119
+ - ext/puma_http11/io_buffer.c
120
+ - ext/puma_http11/mini_ssl.c
121
+ - ext/puma_http11/org/jruby/puma/Http11.java
122
+ - ext/puma_http11/org/jruby/puma/Http11Parser.java
123
+ - ext/puma_http11/org/jruby/puma/MiniSSL.java
124
+ - ext/puma_http11/puma_http11.c
125
+ - lib/puma.rb
126
+ - lib/puma/accept_nonblock.rb
127
+ - lib/puma/app/status.rb
128
+ - lib/puma/binder.rb
129
+ - lib/puma/capistrano.rb
130
+ - lib/puma/cli.rb
131
+ - lib/puma/client.rb
132
+ - lib/puma/compat.rb
133
+ - lib/puma/configuration.rb
134
+ - lib/puma/const.rb
135
+ - lib/puma/control_cli.rb
136
+ - lib/puma/daemon_ext.rb
137
+ - lib/puma/delegation.rb
138
+ - lib/puma/detect.rb
139
+ - lib/puma/events.rb
140
+ - lib/puma/io_buffer.rb
141
+ - lib/puma/java_io_buffer.rb
142
+ - lib/puma/jruby_restart.rb
143
+ - lib/puma/minissl.rb
144
+ - lib/puma/null_io.rb
145
+ - lib/puma/rack_default.rb
146
+ - lib/puma/rack_patch.rb
147
+ - lib/puma/reactor.rb
148
+ - lib/puma/server.rb
149
+ - lib/puma/thread_pool.rb
150
+ - lib/puma/util.rb
151
+ - lib/rack/handler/puma.rb
152
+ - puma.gemspec
153
+ - tools/jungle/init.d/README.md
154
+ - tools/jungle/init.d/puma
155
+ - tools/jungle/init.d/run-puma
156
+ - tools/jungle/upstart/README.md
157
+ - tools/jungle/upstart/puma-manager.conf
158
+ - tools/jungle/upstart/puma.conf
159
+ - test/test_app_status.rb
160
+ - test/test_cli.rb
161
+ - test/test_config.rb
162
+ - test/test_http10.rb
163
+ - test/test_http11.rb
164
+ - test/test_integration.rb
165
+ - test/test_iobuffer.rb
166
+ - test/test_minissl.rb
167
+ - test/test_null_io.rb
168
+ - test/test_persistent.rb
169
+ - test/test_puma_server.rb
170
+ - test/test_rack_handler.rb
171
+ - test/test_rack_server.rb
172
+ - test/test_thread_pool.rb
173
+ - test/test_unix_socket.rb
174
+ - test/test_ws.rb
157
175
  homepage: http://puma.io
158
176
  licenses: []
159
-
160
177
  post_install_message:
161
- rdoc_options:
162
- - --main
163
- - README.md
164
- require_paths:
165
- - lib
166
- required_ruby_version: !ruby/object:Gem::Requirement
178
+ rdoc_options:
179
+ - --main
180
+ - README.md
181
+ require_paths:
182
+ - lib
183
+ required_ruby_version: !ruby/object:Gem::Requirement
167
184
  none: false
168
- requirements:
169
- - - ">="
170
- - !ruby/object:Gem::Version
171
- version: 1.8.7
172
- required_rubygems_version: !ruby/object:Gem::Requirement
185
+ requirements:
186
+ - - ! '>='
187
+ - !ruby/object:Gem::Version
188
+ version: 1.8.7
189
+ required_rubygems_version: !ruby/object:Gem::Requirement
173
190
  none: false
174
- requirements:
175
- - - ">="
176
- - !ruby/object:Gem::Version
177
- version: "0"
191
+ requirements:
192
+ - - ! '>='
193
+ - !ruby/object:Gem::Version
194
+ version: '0'
178
195
  requirements: []
179
-
180
196
  rubyforge_project: puma
181
- rubygems_version: 1.8.24
197
+ rubygems_version: 1.8.25
182
198
  signing_key:
183
199
  specification_version: 3
184
- summary: Puma is a simple, fast, and highly concurrent HTTP 1.1 server for Ruby web applications
185
- test_files:
186
- - test/test_app_status.rb
187
- - test/test_cli.rb
188
- - test/test_config.rb
189
- - test/test_http10.rb
190
- - test/test_http11.rb
191
- - test/test_integration.rb
192
- - test/test_iobuffer.rb
193
- - test/test_minissl.rb
194
- - test/test_null_io.rb
195
- - test/test_persistent.rb
196
- - test/test_puma_server.rb
197
- - test/test_rack_handler.rb
198
- - test/test_rack_server.rb
199
- - test/test_thread_pool.rb
200
- - test/test_unix_socket.rb
201
- - test/test_ws.rb
200
+ summary: Puma is a simple, fast, threaded, and highly concurrent HTTP 1.1 server for
201
+ Ruby/Rack applications
202
+ test_files:
203
+ - test/test_app_status.rb
204
+ - test/test_cli.rb
205
+ - test/test_config.rb
206
+ - test/test_http10.rb
207
+ - test/test_http11.rb
208
+ - test/test_integration.rb
209
+ - test/test_iobuffer.rb
210
+ - test/test_minissl.rb
211
+ - test/test_null_io.rb
212
+ - test/test_persistent.rb
213
+ - test/test_puma_server.rb
214
+ - test/test_rack_handler.rb
215
+ - test/test_rack_server.rb
216
+ - test/test_thread_pool.rb
217
+ - test/test_unix_socket.rb
218
+ - test/test_ws.rb