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 +32 -10
- data/Rakefile +54 -46
- data/ext/puma_http11/extconf.rb +1 -1
- data/ext/puma_http11/puma_http11.c +1 -1
- data/lib/puma.rb +0 -1
- data/lib/puma/const.rb +6 -2
- data/lib/puma/control_cli.rb +1 -1
- data/lib/puma/server.rb +30 -4
- data/puma.gemspec +9 -11
- data/test/hello.ru +1 -1
- data/test/test_cli.rb +5 -4
- data/test/test_integration.rb +2 -2
- data/test/test_persistent.rb +14 -1
- data/test/test_unix_socket.rb +4 -2
- data/test/testhelp.rb +4 -3
- metadata +20 -29
data/README.md
CHANGED
@@ -2,28 +2,24 @@
|
|
2
2
|
|
3
3
|
## Description
|
4
4
|
|
5
|
-
Puma is a
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
2
|
-
|
3
|
-
require
|
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
|
7
|
+
HOE = Hoe.spec "puma" do
|
8
8
|
self.rubyforge_name = 'puma'
|
9
|
-
self.readme_file
|
9
|
+
self.readme_file = "README.md"
|
10
|
+
|
10
11
|
developer 'Evan Phoenix', 'evan@phx.io'
|
11
12
|
|
12
|
-
spec_extras[:extensions]
|
13
|
+
spec_extras[:extensions] = ["ext/puma_http11/extconf.rb"]
|
13
14
|
spec_extras[:executables] = ['puma', 'pumactl']
|
14
15
|
|
15
|
-
|
16
|
+
require_ruby_version ">= 1.8.7"
|
16
17
|
|
17
|
-
|
18
|
+
dependency "rack", "~> 1.2"
|
18
19
|
|
19
|
-
|
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, '
|
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
|
-
#
|
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
|
-
|
55
|
-
|
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
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
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
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
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
|
-
|
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
|
data/ext/puma_http11/extconf.rb
CHANGED
data/lib/puma.rb
CHANGED
data/lib/puma/const.rb
CHANGED
@@ -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.
|
78
|
+
PUMA_VERSION = VERSION = "0.9.3".freeze
|
75
79
|
|
76
80
|
PUMA_TMP_BASE = "puma".freeze
|
77
81
|
|
data/lib/puma/control_cli.rb
CHANGED
data/lib/puma/server.rb
CHANGED
@@ -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
|
-
|
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
|
data/puma.gemspec
CHANGED
@@ -2,12 +2,12 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = "puma"
|
5
|
-
s.version = "0.9.
|
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 = "
|
10
|
-
s.description = "Puma is a
|
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.
|
20
|
-
s.summary = "Puma is a
|
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.
|
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.
|
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.
|
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
|
data/test/hello.ru
CHANGED
@@ -1 +1 @@
|
|
1
|
-
run lambda { |env| [200, {}, ["Hello World"]] }
|
1
|
+
run lambda { |env| [200, {"Content-Type" => "text/plain"}, ["Hello World"]] }
|
data/test/test_cli.rb
CHANGED
@@ -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?
|
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.
|
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.
|
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]
|
data/test/test_integration.rb
CHANGED
@@ -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?
|
22
|
+
if defined?(JRUBY_VERSION) || RbConfig::CONFIG["host_os"] =~ /mingw|mswin/
|
23
23
|
assert true
|
24
24
|
return
|
25
25
|
end
|
data/test/test_persistent.rb
CHANGED
@@ -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
|
-
[
|
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
|
|
data/test/test_unix_socket.rb
CHANGED
@@ -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
|
-
|
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
|
data/test/testhelp.rb
CHANGED
@@ -2,8 +2,9 @@
|
|
2
2
|
# Copyright (c) 2005 Zed A. Shaw
|
3
3
|
|
4
4
|
|
5
|
-
%w(lib
|
6
|
-
|
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:
|
4
|
+
hash: 61
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 9
|
9
|
-
-
|
10
|
-
version: 0.9.
|
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:
|
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:
|
43
|
+
hash: 63
|
44
44
|
segments:
|
45
45
|
- 0
|
46
|
-
-
|
46
|
+
- 8
|
47
47
|
- 0
|
48
|
-
version: 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
|
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
|
-
|
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:
|
155
|
+
hash: 57
|
167
156
|
segments:
|
168
|
-
-
|
169
|
-
|
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.
|
173
|
+
rubygems_version: 1.8.15
|
183
174
|
signing_key:
|
184
175
|
specification_version: 3
|
185
|
-
summary: Puma is a
|
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
|