puma 0.9.2 → 0.9.3

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/README.md CHANGED
@@ -2,28 +2,24 @@
2
2
 
3
3
  ## Description
4
4
 
5
- Puma is a small library that provides a very fast and concurrent HTTP 1.1 server for Ruby web applications. It is designed for running rack apps only.
5
+ 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.
6
6
 
7
- What makes Puma so fast is the careful use of an Ragel extension to provide fast, accurate HTTP 1.1 protocol parsing. This makes the server scream without too many portability issues.
7
+ 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!
8
8
 
9
- ## License
9
+ 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.
10
10
 
11
- Puma is copyright 2011 Evan Phoenix and contributors. It is licensed under the BSD license. See the include LICENSE file for details.
11
+ 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).
12
12
 
13
13
  ## Quick Start
14
14
 
15
- The easiest way to get started with Puma is to install it via RubyGems and then run a Ruby on Rails application. You can do this easily:
15
+ The easiest way to get started with Puma is to install it via RubyGems. You can do this easily:
16
16
 
17
17
  $ gem install puma
18
18
 
19
- Now you should have the puma command available in your PATH, so just do the following:
19
+ Now you should have the puma command available in your PATH, so just do the following in the root folder of your Rack application:
20
20
 
21
21
  $ puma app.ru
22
22
 
23
- ## Install
24
-
25
- $ gem install puma
26
-
27
23
  ## Advanced Setup
28
24
 
29
25
  ### Sinatra
@@ -58,3 +54,29 @@ You can pass it as an option to `rackup`:
58
54
  Alternatively, you can modify your `config.ru` to choose Puma by default, by adding the following as the first line:
59
55
 
60
56
  #\ -s puma
57
+
58
+ ## Configuration
59
+
60
+ Puma provides numerous options for controlling the operation of the server. Consult `puma -h` (or `puma --help`) for a full list.
61
+
62
+ ### Thread Pool
63
+
64
+ Puma utilizes a dynamic thread pool which you can modify. You can set the minimum and maximum number of threads that are available in the pool with the `-t` (or `--threads`) flag:
65
+
66
+ $ puma -t 8:32
67
+
68
+ 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).
69
+
70
+ ### Binding TCP / Sockets
71
+
72
+ In contrast to many other server configs which require multiple flags, Puma simply uses one URI parameter with the `-b` (or `--bind`) flag:
73
+
74
+ $ puma -b tcp://127.0.0.1:9292
75
+
76
+ Want to use UNIX Sockets instead of TCP (which can provide a 5-10% performance boost)? No problem!
77
+
78
+ $ puma -b unix:///var/run/puma.sock
79
+
80
+ ## License
81
+
82
+ Puma is copyright 2011 Evan Phoenix and contributors. It is licensed under the BSD license. See the include LICENSE file for details.
data/Rakefile CHANGED
@@ -1,90 +1,98 @@
1
- require 'rubygems'
2
-
3
- require 'hoe'
1
+ require "hoe"
2
+ require "rake/extensiontask"
3
+ require "rake/javaextensiontask"
4
4
 
5
5
  IS_JRUBY = defined?(RUBY_ENGINE) ? RUBY_ENGINE == "jruby" : false
6
6
 
7
- HOE = Hoe.spec 'puma' do
7
+ HOE = Hoe.spec "puma" do
8
8
  self.rubyforge_name = 'puma'
9
- self.readme_file = "README.md"
9
+ self.readme_file = "README.md"
10
+
10
11
  developer 'Evan Phoenix', 'evan@phx.io'
11
12
 
12
- spec_extras[:extensions] = ["ext/puma_http11/extconf.rb"]
13
+ spec_extras[:extensions] = ["ext/puma_http11/extconf.rb"]
13
14
  spec_extras[:executables] = ['puma', 'pumactl']
14
15
 
15
- dependency 'rack', '~> 1.2'
16
+ require_ruby_version ">= 1.8.7"
16
17
 
17
- extra_dev_deps << ['rake-compiler', "~> 0.7.0"]
18
+ dependency "rack", "~> 1.2"
18
19
 
19
- clean_globs.push('test_*.log', 'log')
20
+ extra_dev_deps << ["rake-compiler", "~> 0.8.0"]
20
21
  end
21
22
 
22
- task :test => [:compile]
23
-
24
23
  # hoe/test and rake-compiler don't seem to play well together, so disable
25
24
  # hoe/test's .gemtest touch file thingy for now
26
25
  HOE.spec.files -= [".gemtest"]
27
26
 
27
+ # puma.gemspec
28
+
28
29
  file "#{HOE.spec.name}.gemspec" => ['Rakefile'] do |t|
29
30
  puts "Generating #{t.name}"
30
- File.open(t.name, 'w') { |f| f.puts HOE.spec.to_ruby }
31
+ File.open(t.name, 'wb') { |f| f.write HOE.spec.to_ruby }
31
32
  end
32
33
 
33
34
  desc "Generate or update the standalone gemspec file for the project"
34
35
  task :gemspec => ["#{HOE.spec.name}.gemspec"]
35
36
 
36
- # the following tasks ease the build of C file from Ragel one
37
+ # generate extension code using Ragel (C and Java)
38
+ desc "Generate extension code (C and Java) using Ragel"
39
+ task :ragel
37
40
 
38
41
  file 'ext/puma_http11/http11_parser.c' => ['ext/puma_http11/http11_parser.rl'] do |t|
39
42
  begin
40
- sh "ragel #{t.prerequisites.last} -C -G2 -o #{t.name}"
43
+ sh "ragel #{t.prerequisites.last} -C -G2 -I ext/puma_http11 -o #{t.name}"
41
44
  rescue
42
45
  fail "Could not build wrapper using Ragel (it failed or not installed?)"
43
46
  end
44
47
  end
48
+ task :ragel => ['ext/puma_http11/http11_parser.c']
45
49
 
46
50
  file 'ext/puma_http11/org/jruby/puma/Http11Parser.java' => ['ext/puma_http11/http11_parser.java.rl'] do |t|
47
51
  begin
48
- sh "ragel #{t.prerequisites.last} -J -G2 -o #{t.name}"
52
+ sh "ragel #{t.prerequisites.last} -J -G2 -I ext/puma_http11 -o #{t.name}"
49
53
  rescue
50
54
  fail "Could not build wrapper using Ragel (it failed or not installed?)"
51
55
  end
52
56
  end
57
+ task :ragel => ['ext/puma_http11/org/jruby/puma/Http11Parser.java']
58
+
59
+ # compile extensions using rake-compiler
60
+ # C (MRI, Rubinius)
61
+ Rake::ExtensionTask.new("puma_http11", HOE.spec) do |ext|
62
+ # place extension inside namespace
63
+ ext.lib_dir = "lib/puma"
64
+
65
+ ext.cross_compile = !!ENV['CROSS']
66
+ ext.cross_platform = ['i386-mswin32-60', 'i386-mingw32']
67
+ ext.cross_compiling do |spec|
68
+ # add fat-binary stub only when cross compiling
69
+ spec.files << "lib/puma/puma_http11.rb"
70
+ end
53
71
 
54
- if IS_JRUBY
55
- require 'rake/javaextensiontask'
56
-
57
- # build http11 java extension
58
- Rake::JavaExtensionTask.new('puma_http11', HOE.spec)
72
+ CLEAN.include "lib/puma/{1.8,1.9}"
73
+ CLEAN.include "lib/puma/puma_http11.rb"
74
+ end
59
75
 
60
- task :ragel => 'ext/puma_http11/org/jruby/puma/Http11Parser.java'
61
- else
62
- # use rake-compiler for building the extension
63
- require 'rake/extensiontask'
64
-
65
- # build http11 C extension
66
- Rake::ExtensionTask.new('puma_http11', HOE.spec) do |ext|
67
- # define target for extension (supporting fat binaries)
68
- if RUBY_PLATFORM =~ /mingw|mswin/ then
69
- RUBY_VERSION =~ /(\d+\.\d+)/
70
- ext.lib_dir = "lib/#{$1}"
71
- elsif ENV['CROSS']
72
- # define cross-compilation tasks when not on Windows.
73
- ext.cross_compile = true
74
- ext.cross_platform = ['i386-mswin32', 'i386-mingw32']
75
- end
76
-
77
- # cleanup versioned library directory
78
- CLEAN.include 'lib/{1.8,1.9}'
76
+ # Java (JRuby)
77
+ if defined? JRUBY_VERSION
78
+ Rake::JavaExtensionTask.new("puma_http11", HOE.spec) do |ext|
79
+ ext.lib_dir = "lib/puma"
79
80
  end
80
-
81
- task :ragel => 'ext/puma_http11/http11_parser.c'
82
81
  end
83
82
 
84
- task :ext_clean do
85
- sh "rm -rf lib/puma_http11.bundle"
86
- sh "rm -rf lib/puma_http11.jar"
87
- sh "rm -rf lib/puma_http11.so"
83
+ # the following is a fat-binary stub that will be used when
84
+ # require 'puma/puma_http11' and will use either 1.8 or 1.9 version depending
85
+ # on RUBY_VERSION
86
+ file "lib/puma/puma_http11.rb" do |t|
87
+ File.open(t.name, "w") do |f|
88
+ f.puts "RUBY_VERSION =~ /(\d+.\d+)/"
89
+ f.puts 'require "puma/#{$1}/puma_http11"'
90
+ end
88
91
  end
89
92
 
90
- task :clean => :ext_clean
93
+ # tests require extension be compiled, but depend on the platform
94
+ if IS_JRUBY
95
+ task :test => [:java]
96
+ else
97
+ task :test => [:compile]
98
+ end
@@ -2,4 +2,4 @@ require 'mkmf'
2
2
 
3
3
  dir_config("puma_http11")
4
4
 
5
- create_makefile("puma_http11")
5
+ create_makefile("puma/puma_http11")
@@ -268,7 +268,7 @@ void HttpParser_free(void *data) {
268
268
  TRACE();
269
269
 
270
270
  if(data) {
271
- free(data);
271
+ xfree(data);
272
272
  }
273
273
  }
274
274
 
@@ -1,4 +1,3 @@
1
-
2
1
  # Standard libraries
3
2
  require 'socket'
4
3
  require 'tempfile'
@@ -1,4 +1,3 @@
1
-
2
1
  module Puma
3
2
 
4
3
  # Every standard HTTP code mapped to the appropriate message. These are
@@ -44,6 +43,11 @@ module Puma
44
43
  505 => 'HTTP Version not supported'
45
44
  }
46
45
 
46
+ # For some HTTP status codes the client only expects headers.
47
+ STATUS_WITH_NO_ENTITY_BODY = {
48
+ 204 => true, 205 => true, 304 => true
49
+ }
50
+
47
51
  # Frequently used constants when constructing requests or responses. Many times
48
52
  # the constant just refers to a string with the same contents. Using these constants
49
53
  # gave about a 3% to 10% performance improvement over using the strings directly.
@@ -71,7 +75,7 @@ module Puma
71
75
 
72
76
  PATH_INFO = 'PATH_INFO'.freeze
73
77
 
74
- PUMA_VERSION = VERSION = "0.9.2".freeze
78
+ PUMA_VERSION = VERSION = "0.9.3".freeze
75
79
 
76
80
  PUMA_TMP_BASE = "puma".freeze
77
81
 
@@ -46,7 +46,7 @@ module Puma
46
46
 
47
47
  @parser.parse! @argv
48
48
 
49
- @state = YAML.load_file(@path)
49
+ @state = YAML.load File.read(@path)
50
50
  @config = @state['config']
51
51
 
52
52
  cmd = @argv.shift
@@ -1,4 +1,3 @@
1
- require 'rubygems'
2
1
  require 'rack'
3
2
  require 'stringio'
4
3
 
@@ -7,7 +6,7 @@ require 'puma/const'
7
6
  require 'puma/events'
8
7
  require 'puma/null_io'
9
8
 
10
- require 'puma_http11'
9
+ require 'puma/puma_http11'
11
10
 
12
11
  require 'socket'
13
12
 
@@ -194,6 +193,7 @@ module Puma
194
193
  #
195
194
  def process_client(client)
196
195
  parser = HttpParser.new
196
+ close_socket = true
197
197
 
198
198
  begin
199
199
  while true
@@ -214,7 +214,13 @@ module Puma
214
214
  if parser.finished?
215
215
  cl = env[CONTENT_LENGTH]
216
216
 
217
- return unless handle_request(env, client, parser.body, cl)
217
+ case handle_request(env, client, parser.body, cl)
218
+ when false
219
+ return
220
+ when :async
221
+ close_socket = false
222
+ return
223
+ end
218
224
 
219
225
  nparsed += parser.body.size if cl
220
226
 
@@ -258,7 +264,7 @@ module Puma
258
264
 
259
265
  ensure
260
266
  begin
261
- client.close
267
+ client.close if close_socket
262
268
  rescue IOError, SystemCallError
263
269
  # Already closed
264
270
  rescue StandardError => e
@@ -336,11 +342,20 @@ module Puma
336
342
  begin
337
343
  begin
338
344
  status, headers, res_body = @app.call(env)
345
+
346
+ if status == -1
347
+ unless headers.empty? and res_body == []
348
+ raise "async response must have empty headers and body"
349
+ end
350
+
351
+ return :async
352
+ end
339
353
  rescue => e
340
354
  status, headers, res_body = lowlevel_error(e)
341
355
  end
342
356
 
343
357
  content_length = nil
358
+ no_body = false
344
359
 
345
360
  if res_body.kind_of? Array and res_body.size == 1
346
361
  content_length = res_body[0].size
@@ -365,6 +380,8 @@ module Puma
365
380
  client.write " "
366
381
  client.write HTTP_STATUS_CODES[status]
367
382
  client.write "\r\n"
383
+
384
+ no_body = status < 200 || STATUS_WITH_NO_ENTITY_BODY[status]
368
385
  end
369
386
  else
370
387
  allow_chunked = false
@@ -381,6 +398,8 @@ module Puma
381
398
  client.write " "
382
399
  client.write HTTP_STATUS_CODES[status]
383
400
  client.write "\r\n"
401
+
402
+ no_body = status < 200 || STATUS_WITH_NO_ENTITY_BODY[status]
384
403
  end
385
404
  end
386
405
 
@@ -395,6 +414,8 @@ module Puma
395
414
  when TRANSFER_ENCODING
396
415
  allow_chunked = false
397
416
  content_length = nil
417
+ when CONTENT_TYPE
418
+ next if no_body
398
419
  end
399
420
 
400
421
  vs.split(NEWLINE).each do |v|
@@ -405,6 +426,11 @@ module Puma
405
426
  end
406
427
  end
407
428
 
429
+ if no_body
430
+ client.write line_ending
431
+ return keep_alive
432
+ end
433
+
408
434
  if include_keepalive_header
409
435
  client.write CONNECTION_KEEP_ALIVE
410
436
  elsif !keep_alive
@@ -2,12 +2,12 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "puma"
5
- s.version = "0.9.2"
5
+ s.version = "0.9.3"
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 = "2011-12-19"
10
- s.description = "Puma is a small library that provides a very fast and concurrent HTTP 1.1 server for Ruby web applications. It is designed for running rack apps only.\n\nWhat makes Puma so fast is the careful use of an Ragel extension to provide fast, accurate HTTP 1.1 protocol parsing. This makes the server scream without too many portability issues."
9
+ s.date = "2012-01-09"
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)."
11
11
  s.email = ["evan@phx.io"]
12
12
  s.executables = ["puma", "pumactl"]
13
13
  s.extensions = ["ext/puma_http11/extconf.rb"]
@@ -15,9 +15,10 @@ Gem::Specification.new do |s|
15
15
  s.files = ["COPYING", "Gemfile", "History.txt", "LICENSE", "Manifest.txt", "README.md", "Rakefile", "TODO", "bin/puma", "bin/pumactl", "examples/config.rb", "ext/puma_http11/PumaHttp11Service.java", "ext/puma_http11/ext_help.h", "ext/puma_http11/extconf.rb", "ext/puma_http11/http11_parser.c", "ext/puma_http11/http11_parser.h", "ext/puma_http11/http11_parser.java.rl", "ext/puma_http11/http11_parser.rl", "ext/puma_http11/http11_parser_common.rl", "ext/puma_http11/org/jruby/puma/Http11.java", "ext/puma_http11/org/jruby/puma/Http11Parser.java", "ext/puma_http11/puma_http11.c", "lib/puma.rb", "lib/puma/app/status.rb", "lib/puma/cli.rb", "lib/puma/configuration.rb", "lib/puma/const.rb", "lib/puma/control_cli.rb", "lib/puma/events.rb", "lib/puma/jruby_restart.rb", "lib/puma/null_io.rb", "lib/puma/rack_patch.rb", "lib/puma/server.rb", "lib/puma/thread_pool.rb", "lib/rack/handler/puma.rb", "puma.gemspec", "test/ab_rs.rb", "test/config/app.rb", "test/hello.ru", "test/lobster.ru", "test/mime.yaml", "test/slow.ru", "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_persistent.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", "test/testhelp.rb", "tools/trickletest.rb"]
16
16
  s.rdoc_options = ["--main", "README.md"]
17
17
  s.require_paths = ["lib"]
18
+ s.required_ruby_version = Gem::Requirement.new(">= 1.8.7")
18
19
  s.rubyforge_project = "puma"
19
- s.rubygems_version = "1.8.12"
20
- s.summary = "Puma is a small library that provides a very fast and concurrent HTTP 1.1 server for Ruby web applications"
20
+ s.rubygems_version = "1.8.15"
21
+ s.summary = "Puma is a simple, fast, and highly concurrent HTTP 1.1 server for Ruby web applications"
21
22
  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_persistent.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"]
22
23
 
23
24
  if s.respond_to? :specification_version then
@@ -25,19 +26,16 @@ Gem::Specification.new do |s|
25
26
 
26
27
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
27
28
  s.add_runtime_dependency(%q<rack>, ["~> 1.2"])
28
- s.add_development_dependency(%q<rake-compiler>, ["~> 0.7.0"])
29
+ s.add_development_dependency(%q<rake-compiler>, ["~> 0.8.0"])
29
30
  s.add_development_dependency(%q<hoe>, ["~> 2.12"])
30
- s.add_development_dependency(%q<rdoc>, ["~> 3.10"])
31
31
  else
32
32
  s.add_dependency(%q<rack>, ["~> 1.2"])
33
- s.add_dependency(%q<rake-compiler>, ["~> 0.7.0"])
33
+ s.add_dependency(%q<rake-compiler>, ["~> 0.8.0"])
34
34
  s.add_dependency(%q<hoe>, ["~> 2.12"])
35
- s.add_dependency(%q<rdoc>, ["~> 3.10"])
36
35
  end
37
36
  else
38
37
  s.add_dependency(%q<rack>, ["~> 1.2"])
39
- s.add_dependency(%q<rake-compiler>, ["~> 0.7.0"])
38
+ s.add_dependency(%q<rake-compiler>, ["~> 0.8.0"])
40
39
  s.add_dependency(%q<hoe>, ["~> 2.12"])
41
- s.add_dependency(%q<rdoc>, ["~> 3.10"])
42
40
  end
43
41
  end
@@ -1 +1 @@
1
- run lambda { |env| [200, {}, ["Hello World"]] }
1
+ run lambda { |env| [200, {"Content-Type" => "text/plain"}, ["Hello World"]] }
@@ -1,3 +1,4 @@
1
+ require "rbconfig"
1
2
  require 'test/unit'
2
3
  require 'puma/cli'
3
4
  require 'tempfile'
@@ -27,7 +28,7 @@ class TestCLI < Test::Unit::TestCase
27
28
  assert_equal File.read(@tmp_path).strip.to_i, Process.pid
28
29
  end
29
30
 
30
- unless defined? JRUBY_VERSION
31
+ unless defined?(JRUBY_VERSION) || RbConfig::CONFIG["host_os"] =~ /mingw|mswin/
31
32
  def test_control
32
33
  url = "unix://#{@tmp_path}"
33
34
 
@@ -85,7 +86,7 @@ class TestCLI < Test::Unit::TestCase
85
86
  cli.parse_options
86
87
  cli.write_state
87
88
 
88
- data = YAML.load_file(@tmp_path)
89
+ data = YAML.load File.read(@tmp_path)
89
90
 
90
91
  assert_equal Process.pid, data["pid"]
91
92
 
@@ -95,7 +96,7 @@ class TestCLI < Test::Unit::TestCase
95
96
 
96
97
  assert m, "'#{url}' is not a URL"
97
98
  end
98
- end
99
+ end # JRUBY or Windows
99
100
 
100
101
  def test_state
101
102
  url = "tcp://127.0.0.1:8232"
@@ -103,7 +104,7 @@ class TestCLI < Test::Unit::TestCase
103
104
  cli.parse_options
104
105
  cli.write_state
105
106
 
106
- data = YAML.load_file(@tmp_path)
107
+ data = YAML.load File.read(@tmp_path)
107
108
 
108
109
  assert_equal Process.pid, data["pid"]
109
110
  assert_equal url, data["config"].options[:control_url]
@@ -1,5 +1,5 @@
1
+ require "rbconfig"
1
2
  require 'test/unit'
2
- require 'rubygems'
3
3
  require 'socket'
4
4
 
5
5
  require 'puma/cli'
@@ -19,7 +19,7 @@ class TestIntegration < Test::Unit::TestCase
19
19
  end
20
20
 
21
21
  def test_stop_via_pumactl
22
- if defined? JRUBY_VERSION
22
+ if defined?(JRUBY_VERSION) || RbConfig::CONFIG["host_os"] =~ /mingw|mswin/
23
23
  assert true
24
24
  return
25
25
  end
@@ -10,6 +10,7 @@ class TestPersistent < Test::Unit::TestCase
10
10
  @keep_request = "GET / HTTP/1.0\r\nHost: test.com\r\nContent-Type: text/plain\r\nConnection: Keep-Alive\r\n\r\n"
11
11
 
12
12
  @valid_post = "POST / HTTP/1.1\r\nHost: test.com\r\nContent-Type: text/plain\r\nContent-Length: 5\r\n\r\nhello"
13
+ @valid_no_body = "GET / HTTP/1.1\r\nHost: test.com\r\nX-Status: 204\r\nContent-Type: text/plain\r\n\r\n"
13
14
 
14
15
  @headers = { "X-Header" => "Works" }
15
16
  @body = ["Hello"]
@@ -17,7 +18,8 @@ class TestPersistent < Test::Unit::TestCase
17
18
 
18
19
  @simple = lambda do |env|
19
20
  @inputs << env['rack.input']
20
- [200, @headers, @body]
21
+ status = Integer(env['HTTP_X_STATUS'] || 200)
22
+ [status, @headers, @body]
21
23
  end
22
24
 
23
25
  @server = Puma::Server.new @simple
@@ -76,6 +78,17 @@ class TestPersistent < Test::Unit::TestCase
76
78
  assert_equal "Hello", @client.read(5)
77
79
  end
78
80
 
81
+ def test_no_body_then_get
82
+ @client << @valid_no_body
83
+ assert_equal "HTTP/1.1 204 No Content\r\nX-Header: Works\r\n\r\n", lines(3)
84
+
85
+ @client << @valid_request
86
+ sz = @body[0].size.to_s
87
+
88
+ assert_equal "HTTP/1.1 200 OK\r\nX-Header: Works\r\nContent-Length: #{sz}\r\n\r\n", lines(4)
89
+ assert_equal "Hello", @client.read(5)
90
+ end
91
+
79
92
  def test_chunked
80
93
  @body << "Chunked"
81
94
 
@@ -1,10 +1,12 @@
1
+ require "rbconfig"
1
2
  require 'test/unit'
2
3
  require 'puma/server'
3
4
 
4
5
  require 'socket'
5
6
 
6
7
  # UNIX sockets are not recommended on JRuby
7
- unless defined?(JRUBY_VERSION)
8
+ # (or Windows)
9
+ unless defined?(JRUBY_VERSION) || RbConfig::CONFIG["host_os"] =~ /mingw|mswin/
8
10
  class TestPumaUnixSocket < Test::Unit::TestCase
9
11
 
10
12
  App = lambda { |env| [200, {}, ["Works"]] }
@@ -34,4 +36,4 @@ unless defined?(JRUBY_VERSION)
34
36
  sock.close
35
37
  end
36
38
  end
37
- end
39
+ end
@@ -2,8 +2,9 @@
2
2
  # Copyright (c) 2005 Zed A. Shaw
3
3
 
4
4
 
5
- %w(lib ext bin test).each do |dir|
6
- $LOAD_PATH.unshift File.expand_path("../../#{dir}", __FILE__)
5
+ %w(lib test).each do |d|
6
+ dir = File.expand_path("../../#{d}", __FILE__)
7
+ $LOAD_PATH.unshift dir unless $LOAD_PATH.include?(dir)
7
8
  end
8
9
 
9
10
  require 'rubygems'
@@ -18,7 +19,7 @@ require 'puma'
18
19
  def redirect_test_io
19
20
  yield
20
21
  end
21
-
22
+
22
23
  # Either takes a string to do a get request against, or a tuple of [URI, HTTP] where
23
24
  # HTTP is some kind of Net::HTTP request object (POST, HEAD, etc.)
24
25
  def hit(uris)
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: puma
3
3
  version: !ruby/object:Gem::Version
4
- hash: 63
4
+ hash: 61
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 9
9
- - 2
10
- version: 0.9.2
9
+ - 3
10
+ version: 0.9.3
11
11
  platform: ruby
12
12
  authors:
13
13
  - Evan Phoenix
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-12-19 00:00:00 Z
18
+ date: 2012-01-09 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: rack
@@ -40,12 +40,12 @@ dependencies:
40
40
  requirements:
41
41
  - - ~>
42
42
  - !ruby/object:Gem::Version
43
- hash: 3
43
+ hash: 63
44
44
  segments:
45
45
  - 0
46
- - 7
46
+ - 8
47
47
  - 0
48
- version: 0.7.0
48
+ version: 0.8.0
49
49
  type: :development
50
50
  version_requirements: *id002
51
51
  - !ruby/object:Gem::Dependency
@@ -63,25 +63,14 @@ dependencies:
63
63
  version: "2.12"
64
64
  type: :development
65
65
  version_requirements: *id003
66
- - !ruby/object:Gem::Dependency
67
- name: rdoc
68
- prerelease: false
69
- requirement: &id004 !ruby/object:Gem::Requirement
70
- none: false
71
- requirements:
72
- - - ~>
73
- - !ruby/object:Gem::Version
74
- hash: 19
75
- segments:
76
- - 3
77
- - 10
78
- version: "3.10"
79
- type: :development
80
- version_requirements: *id004
81
66
  description: |-
82
- Puma is a small library that provides a very fast and concurrent HTTP 1.1 server for Ruby web applications. It is designed for running rack apps only.
67
+ 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.
68
+
69
+ 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!
70
+
71
+ 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.
83
72
 
84
- What makes Puma so fast is the careful use of an Ragel extension to provide fast, accurate HTTP 1.1 protocol parsing. This makes the server scream without too many portability issues.
73
+ 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).
85
74
  email:
86
75
  - evan@phx.io
87
76
  executables:
@@ -163,10 +152,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
163
152
  requirements:
164
153
  - - ">="
165
154
  - !ruby/object:Gem::Version
166
- hash: 3
155
+ hash: 57
167
156
  segments:
168
- - 0
169
- version: "0"
157
+ - 1
158
+ - 8
159
+ - 7
160
+ version: 1.8.7
170
161
  required_rubygems_version: !ruby/object:Gem::Requirement
171
162
  none: false
172
163
  requirements:
@@ -179,10 +170,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
179
170
  requirements: []
180
171
 
181
172
  rubyforge_project: puma
182
- rubygems_version: 1.8.12
173
+ rubygems_version: 1.8.15
183
174
  signing_key:
184
175
  specification_version: 3
185
- summary: Puma is a small library that provides a very fast and concurrent HTTP 1.1 server for Ruby web applications
176
+ summary: Puma is a simple, fast, and highly concurrent HTTP 1.1 server for Ruby web applications
186
177
  test_files:
187
178
  - test/test_app_status.rb
188
179
  - test/test_cli.rb