puma 2.7.0 → 3.1.1

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.

Files changed (79) hide show
  1. checksums.yaml +5 -13
  2. data/DEPLOYMENT.md +91 -0
  3. data/Gemfile +3 -2
  4. data/History.txt +624 -1
  5. data/Manifest.txt +15 -3
  6. data/README.md +129 -14
  7. data/Rakefile +3 -3
  8. data/bin/puma-wild +31 -0
  9. data/bin/pumactl +1 -1
  10. data/docs/nginx.md +1 -1
  11. data/docs/signals.md +43 -0
  12. data/ext/puma_http11/extconf.rb +7 -2
  13. data/ext/puma_http11/http11_parser.java.rl +5 -5
  14. data/ext/puma_http11/io_buffer.c +1 -1
  15. data/ext/puma_http11/mini_ssl.c +233 -18
  16. data/ext/puma_http11/org/jruby/puma/Http11.java +12 -3
  17. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +39 -39
  18. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +245 -195
  19. data/ext/puma_http11/puma_http11.c +12 -4
  20. data/lib/puma.rb +1 -0
  21. data/lib/puma/app/status.rb +7 -0
  22. data/lib/puma/binder.rb +108 -39
  23. data/lib/puma/capistrano.rb +23 -6
  24. data/lib/puma/cli.rb +141 -446
  25. data/lib/puma/client.rb +48 -1
  26. data/lib/puma/cluster.rb +207 -58
  27. data/lib/puma/commonlogger.rb +107 -0
  28. data/lib/puma/configuration.rb +262 -235
  29. data/lib/puma/const.rb +97 -14
  30. data/lib/puma/control_cli.rb +85 -77
  31. data/lib/puma/convenient.rb +23 -0
  32. data/lib/puma/daemon_ext.rb +11 -4
  33. data/lib/puma/detect.rb +8 -1
  34. data/lib/puma/dsl.rb +456 -0
  35. data/lib/puma/events.rb +35 -18
  36. data/lib/puma/jruby_restart.rb +1 -1
  37. data/lib/puma/launcher.rb +399 -0
  38. data/lib/puma/minissl.rb +49 -20
  39. data/lib/puma/null_io.rb +15 -0
  40. data/lib/puma/plugin.rb +104 -0
  41. data/lib/puma/plugin/tmp_restart.rb +35 -0
  42. data/lib/puma/rack/backports/uri/common_18.rb +56 -0
  43. data/lib/puma/rack/backports/uri/common_192.rb +52 -0
  44. data/lib/puma/rack/backports/uri/common_193.rb +29 -0
  45. data/lib/puma/rack/builder.rb +295 -0
  46. data/lib/puma/rack/urlmap.rb +90 -0
  47. data/lib/puma/reactor.rb +14 -1
  48. data/lib/puma/runner.rb +35 -17
  49. data/lib/puma/server.rb +161 -58
  50. data/lib/puma/single.rb +15 -10
  51. data/lib/puma/state_file.rb +29 -0
  52. data/lib/puma/thread_pool.rb +88 -13
  53. data/lib/puma/util.rb +123 -0
  54. data/lib/rack/handler/puma.rb +35 -29
  55. data/puma.gemspec +2 -4
  56. data/tools/jungle/init.d/README.md +2 -2
  57. data/tools/jungle/init.d/puma +69 -7
  58. data/tools/jungle/upstart/puma.conf +8 -2
  59. metadata +51 -71
  60. data/COPYING +0 -55
  61. data/TODO +0 -5
  62. data/lib/puma/rack_patch.rb +0 -45
  63. data/test/test_app_status.rb +0 -92
  64. data/test/test_cli.rb +0 -173
  65. data/test/test_config.rb +0 -16
  66. data/test/test_http10.rb +0 -27
  67. data/test/test_http11.rb +0 -145
  68. data/test/test_integration.rb +0 -165
  69. data/test/test_iobuffer.rb +0 -38
  70. data/test/test_minissl.rb +0 -25
  71. data/test/test_null_io.rb +0 -31
  72. data/test/test_persistent.rb +0 -238
  73. data/test/test_puma_server.rb +0 -292
  74. data/test/test_rack_handler.rb +0 -10
  75. data/test/test_rack_server.rb +0 -141
  76. data/test/test_tcp_rack.rb +0 -42
  77. data/test/test_thread_pool.rb +0 -156
  78. data/test/test_unix_socket.rb +0 -39
  79. data/test/test_ws.rb +0 -89
data/COPYING DELETED
@@ -1,55 +0,0 @@
1
- Mongrel Web Server (Mongrel) is copyrighted free software by Zed A. Shaw
2
- <zedshaw at zedshaw dot com> You can redistribute it and/or modify it under
3
- either the terms of the GPL or the conditions below:
4
-
5
- 1. You may make and give away verbatim copies of the source form of the
6
- software without restriction, provided that you duplicate all of the
7
- original copyright notices and associated disclaimers.
8
-
9
- 2. You may modify your copy of the software in any way, provided that
10
- you do at least ONE of the following:
11
-
12
- a) place your modifications in the Public Domain or otherwise make them
13
- Freely Available, such as by posting said modifications to Usenet or an
14
- equivalent medium, or by allowing the author to include your
15
- modifications in the software.
16
-
17
- b) use the modified software only within your corporation or
18
- organization.
19
-
20
- c) rename any non-standard executables so the names do not conflict with
21
- standard executables, which must also be provided.
22
-
23
- d) make other distribution arrangements with the author.
24
-
25
- 3. You may distribute the software in object code or executable
26
- form, provided that you do at least ONE of the following:
27
-
28
- a) distribute the executables and library files of the software,
29
- together with instructions (in the manual page or equivalent) on where
30
- to get the original distribution.
31
-
32
- b) accompany the distribution with the machine-readable source of the
33
- software.
34
-
35
- c) give non-standard executables non-standard names, with
36
- instructions on where to get the original software distribution.
37
-
38
- d) make other distribution arrangements with the author.
39
-
40
- 4. You may modify and include the part of the software into any other
41
- software (possibly commercial). But some files in the distribution
42
- are not written by the author, so that they are not under this terms.
43
-
44
- 5. The scripts and library files supplied as input to or produced as
45
- output from the software do not automatically fall under the
46
- copyright of the software, but belong to whomever generated them,
47
- and may be sold commercially, and may be aggregated with this
48
- software.
49
-
50
- 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
51
- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
52
- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
53
- PURPOSE.
54
-
55
-
data/TODO DELETED
@@ -1,5 +0,0 @@
1
-
2
- v1.2. Rewrite and merge mongrel cluster and mongrel_rails into something small and maintainable. Remove gem_plugin entirely.
3
-
4
- v1.1.1. See if Java is setting the server version string in the request properly.
5
-
@@ -1,45 +0,0 @@
1
- require 'rack/commonlogger'
2
-
3
- module Rack
4
- # Patch CommonLogger to use after_reply.
5
- #
6
- # Simply request this file and CommonLogger will be a bit more
7
- # efficient.
8
- class CommonLogger
9
- remove_method :call
10
-
11
- def call(env)
12
- began_at = Time.now
13
- status, header, body = @app.call(env)
14
- header = Utils::HeaderHash.new(header)
15
-
16
- # If we've been hijacked, then output a special line
17
- if env['rack.hijack_io']
18
- log_hijacking(env, 'HIJACK', header, began_at)
19
- elsif ary = env['rack.after_reply']
20
- ary << lambda { log(env, status, header, began_at) }
21
- else
22
- body = BodyProxy.new(body) { log(env, status, header, began_at) }
23
- end
24
-
25
- [status, header, body]
26
- end
27
-
28
- HIJACK_FORMAT = %{%s - %s [%s] "%s %s%s %s" HIJACKED -1 %0.4f\n}
29
-
30
- def log_hijacking(env, status, header, began_at)
31
- now = Time.now
32
-
33
- logger = @logger || env['rack.errors']
34
- logger.write HIJACK_FORMAT % [
35
- env['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-",
36
- env["REMOTE_USER"] || "-",
37
- now.strftime("%d/%b/%Y %H:%M:%S"),
38
- env["REQUEST_METHOD"],
39
- env["PATH_INFO"],
40
- env["QUERY_STRING"].empty? ? "" : "?"+env["QUERY_STRING"],
41
- env["HTTP_VERSION"],
42
- now - began_at ]
43
- end
44
- end
45
- end
@@ -1,92 +0,0 @@
1
- require 'test/unit'
2
- require 'rack'
3
- require 'puma/app/status'
4
-
5
- class TestAppStatus < Test::Unit::TestCase
6
- class FakeServer
7
- def initialize
8
- @status = :running
9
- @backlog = 0
10
- @running = 0
11
- end
12
-
13
- attr_reader :status
14
- attr_accessor :backlog, :running
15
-
16
- def stop
17
- @status = :stop
18
- end
19
-
20
- def halt
21
- @status = :halt
22
- end
23
-
24
- def stats
25
- "{}"
26
- end
27
- end
28
-
29
- def setup
30
- @server = FakeServer.new
31
- @app = Puma::App::Status.new(@server)
32
- @app.auth_token = nil
33
- end
34
-
35
- def lint(uri)
36
- app = Rack::Lint.new @app
37
- mock_env = Rack::MockRequest.env_for uri
38
- app.call mock_env
39
- end
40
-
41
- def test_bad_token
42
- @app.auth_token = "abcdef"
43
-
44
- status, _, _ = lint('/whatever')
45
-
46
- assert_equal 403, status
47
- end
48
-
49
- def test_good_token
50
- @app.auth_token = "abcdef"
51
-
52
- status, _, _ = lint('/whatever?token=abcdef')
53
-
54
- assert_equal 404, status
55
- end
56
-
57
- def test_unsupported
58
- status, _, _ = lint('/not-real')
59
-
60
- assert_equal 404, status
61
- end
62
-
63
- def test_stop
64
- status, _ , app = lint('/stop')
65
-
66
- assert_equal :stop, @server.status
67
- assert_equal 200, status
68
- assert_equal ['{ "status": "ok" }'], app.enum_for.to_a
69
- end
70
-
71
- def test_halt
72
- status, _ , app = lint('/halt')
73
-
74
- assert_equal :halt, @server.status
75
- assert_equal 200, status
76
- assert_equal ['{ "status": "ok" }'], app.enum_for.to_a
77
- end
78
-
79
- def test_stats
80
- @server.backlog = 1
81
- @server.running = 9
82
- status, _ , app = lint('/stats')
83
-
84
- assert_equal 200, status
85
- assert_equal ['{}'], app.enum_for.to_a
86
- end
87
-
88
- def test_alternate_location
89
- status, _ , _ = lint('__alternatE_location_/stats')
90
- assert_equal 200, status
91
- end
92
- end
data/test/test_cli.rb DELETED
@@ -1,173 +0,0 @@
1
- require "rbconfig"
2
- require 'test/unit'
3
- require 'puma/cli'
4
- require 'tempfile'
5
-
6
- class TestCLI < Test::Unit::TestCase
7
- def setup
8
- @environment = 'production'
9
- @tmp_file = Tempfile.new("puma-test")
10
- @tmp_path = @tmp_file.path
11
- @tmp_file.close!
12
-
13
- @tmp_path2 = "#{@tmp_path}2"
14
-
15
- File.unlink @tmp_path if File.exist? @tmp_path
16
- File.unlink @tmp_path2 if File.exist? @tmp_path2
17
-
18
- @wait, @ready = IO.pipe
19
-
20
- @events = Events.strings
21
- @events.on_booted { @ready << "!" }
22
- end
23
-
24
- def wait_booted
25
- @wait.sysread 1
26
- end
27
-
28
- def teardown
29
- File.unlink @tmp_path if File.exist? @tmp_path
30
- File.unlink @tmp_path2 if File.exist? @tmp_path2
31
-
32
- @wait.close
33
- @ready.close
34
- end
35
-
36
- def test_pid_file
37
- cli = Puma::CLI.new ["--pidfile", @tmp_path]
38
- cli.parse_options
39
- cli.write_pid
40
-
41
- assert_equal File.read(@tmp_path).strip.to_i, Process.pid
42
- end
43
-
44
- def test_control_for_tcp
45
- url = "tcp://127.0.0.1:9877/"
46
- cli = Puma::CLI.new ["-b", "tcp://127.0.0.1:9876",
47
- "--control", url,
48
- "--control-token", "",
49
- "test/lobster.ru"], @events
50
-
51
- cli.parse_options
52
-
53
- thread_exception = nil
54
- t = Thread.new do
55
- begin
56
- cli.run
57
- rescue Exception => e
58
- thread_exception = e
59
- end
60
- end
61
-
62
- wait_booted
63
-
64
- s = TCPSocket.new "127.0.0.1", 9877
65
- s << "GET /stats HTTP/1.0\r\n\r\n"
66
- body = s.read
67
- assert_equal '{ "backlog": 0, "running": 0 }', body.split("\r\n").last
68
-
69
- cli.stop
70
- t.join
71
- assert_equal nil, thread_exception
72
- end
73
-
74
- unless defined?(JRUBY_VERSION) || RbConfig::CONFIG["host_os"] =~ /mingw|mswin/
75
- def test_control
76
- url = "unix://#{@tmp_path}"
77
-
78
- cli = Puma::CLI.new ["-b", "unix://#{@tmp_path2}",
79
- "--control", url,
80
- "--control-token", "",
81
- "test/lobster.ru"], @events
82
- cli.parse_options
83
-
84
- t = Thread.new { cli.run }
85
-
86
- wait_booted
87
-
88
- s = UNIXSocket.new @tmp_path
89
- s << "GET /stats HTTP/1.0\r\n\r\n"
90
- body = s.read
91
-
92
- assert_equal '{ "backlog": 0, "running": 0 }', body.split("\r\n").last
93
-
94
- cli.stop
95
- t.join
96
- end
97
-
98
- def test_control_stop
99
- url = "unix://#{@tmp_path}"
100
-
101
- cli = Puma::CLI.new ["-b", "unix://#{@tmp_path2}",
102
- "--control", url,
103
- "--control-token", "",
104
- "test/lobster.ru"], @events
105
- cli.parse_options
106
-
107
- t = Thread.new { cli.run }
108
-
109
- wait_booted
110
-
111
- s = UNIXSocket.new @tmp_path
112
- s << "GET /stop HTTP/1.0\r\n\r\n"
113
- body = s.read
114
-
115
- assert_equal '{ "status": "ok" }', body.split("\r\n").last
116
-
117
- t.join
118
- end
119
-
120
- def test_tmp_control
121
- url = "tcp://127.0.0.1:8232"
122
- cli = Puma::CLI.new ["--state", @tmp_path, "--control", "auto"]
123
- cli.parse_options
124
- cli.write_state
125
-
126
- data = YAML.load File.read(@tmp_path)
127
-
128
- assert_equal Process.pid, data["pid"]
129
-
130
- url = data["config"].options[:control_url]
131
-
132
- m = %r!unix://(.*)!.match(url)
133
-
134
- assert m, "'#{url}' is not a URL"
135
- end
136
- end # JRUBY or Windows
137
-
138
- def test_state
139
- url = "tcp://127.0.0.1:8232"
140
- cli = Puma::CLI.new ["--state", @tmp_path, "--control", url]
141
- cli.parse_options
142
- cli.write_state
143
-
144
- data = YAML.load File.read(@tmp_path)
145
-
146
- assert_equal Process.pid, data["pid"]
147
- assert_equal url, data["config"].options[:control_url]
148
- end
149
-
150
- def test_load_path
151
- cli = Puma::CLI.new ["--include", 'foo/bar']
152
- cli.parse_options
153
-
154
- assert_equal 'foo/bar', $LOAD_PATH[0]
155
- $LOAD_PATH.shift
156
-
157
- cli = Puma::CLI.new ["--include", 'foo/bar:baz/qux']
158
- cli.parse_options
159
-
160
- assert_equal 'foo/bar', $LOAD_PATH[0]
161
- $LOAD_PATH.shift
162
- assert_equal 'baz/qux', $LOAD_PATH[0]
163
- $LOAD_PATH.shift
164
- end
165
-
166
- def test_environment
167
- cli = Puma::CLI.new ["--environment", @environment]
168
- cli.parse_options
169
- cli.set_rack_environment
170
-
171
- assert_equal ENV['RACK_ENV'], @environment
172
- end
173
- end
data/test/test_config.rb DELETED
@@ -1,16 +0,0 @@
1
- require 'test/unit'
2
-
3
- require 'puma'
4
- require 'puma/configuration'
5
-
6
- class TestConfigFile < Test::Unit::TestCase
7
- def test_app_from_app_DSL
8
- opts = { :config_file => "test/config/app.rb" }
9
- conf = Puma::Configuration.new opts
10
- conf.load
11
-
12
- app = conf.app
13
-
14
- assert_equal [200, {}, ["embedded app"]], app.call({})
15
- end
16
- end
data/test/test_http10.rb DELETED
@@ -1,27 +0,0 @@
1
- require 'test/testhelp'
2
-
3
- class Http10ParserTest < Test::Unit::TestCase
4
- include Puma
5
-
6
- def test_parse_simple
7
- parser = HttpParser.new
8
- req = {}
9
- http = "GET / HTTP/1.0\r\n\r\n"
10
- nread = parser.execute(req, http, 0)
11
-
12
- assert nread == http.length, "Failed to parse the full HTTP request"
13
- assert parser.finished?, "Parser didn't finish"
14
- assert !parser.error?, "Parser had error"
15
- assert nread == parser.nread, "Number read returned from execute does not match"
16
-
17
- assert_equal '/', req['REQUEST_PATH']
18
- assert_equal 'HTTP/1.0', req['HTTP_VERSION']
19
- assert_equal '/', req['REQUEST_URI']
20
- assert_equal 'GET', req['REQUEST_METHOD']
21
- assert_nil req['FRAGMENT']
22
- assert_nil req['QUERY_STRING']
23
-
24
- parser.reset
25
- assert parser.nread == 0, "Number read after reset should be 0"
26
- end
27
- end
data/test/test_http11.rb DELETED
@@ -1,145 +0,0 @@
1
- # Copyright (c) 2011 Evan Phoenix
2
- # Copyright (c) 2005 Zed A. Shaw
3
-
4
- require 'test/testhelp'
5
-
6
- include Puma
7
-
8
- class Http11ParserTest < Test::Unit::TestCase
9
-
10
- def test_parse_simple
11
- parser = HttpParser.new
12
- req = {}
13
- http = "GET / HTTP/1.1\r\n\r\n"
14
- nread = parser.execute(req, http, 0)
15
-
16
- assert nread == http.length, "Failed to parse the full HTTP request"
17
- assert parser.finished?, "Parser didn't finish"
18
- assert !parser.error?, "Parser had error"
19
- assert nread == parser.nread, "Number read returned from execute does not match"
20
-
21
- assert_equal '/', req['REQUEST_PATH']
22
- assert_equal 'HTTP/1.1', req['HTTP_VERSION']
23
- assert_equal '/', req['REQUEST_URI']
24
- assert_equal 'GET', req['REQUEST_METHOD']
25
- assert_nil req['FRAGMENT']
26
- assert_nil req['QUERY_STRING']
27
-
28
- parser.reset
29
- assert parser.nread == 0, "Number read after reset should be 0"
30
- end
31
-
32
- def test_parse_dumbfuck_headers
33
- parser = HttpParser.new
34
- req = {}
35
- should_be_good = "GET / HTTP/1.1\r\naaaaaaaaaaaaa:++++++++++\r\n\r\n"
36
- nread = parser.execute(req, should_be_good, 0)
37
- assert_equal should_be_good.length, nread
38
- assert parser.finished?
39
- assert !parser.error?
40
- end
41
-
42
- def test_parse_error
43
- parser = HttpParser.new
44
- req = {}
45
- bad_http = "GET / SsUTF/1.1"
46
-
47
- error = false
48
- begin
49
- parser.execute(req, bad_http, 0)
50
- rescue
51
- error = true
52
- end
53
-
54
- assert error, "failed to throw exception"
55
- assert !parser.finished?, "Parser shouldn't be finished"
56
- assert parser.error?, "Parser SHOULD have error"
57
- end
58
-
59
- def test_fragment_in_uri
60
- parser = HttpParser.new
61
- req = {}
62
- get = "GET /forums/1/topics/2375?page=1#posts-17408 HTTP/1.1\r\n\r\n"
63
- assert_nothing_raised do
64
- parser.execute(req, get, 0)
65
- end
66
- assert parser.finished?
67
- assert_equal '/forums/1/topics/2375?page=1', req['REQUEST_URI']
68
- assert_equal 'posts-17408', req['FRAGMENT']
69
- end
70
-
71
- # lame random garbage maker
72
- def rand_data(min, max, readable=true)
73
- count = min + ((rand(max)+1) *10).to_i
74
- res = count.to_s + "/"
75
-
76
- if readable
77
- res << Digest::SHA1.hexdigest(rand(count * 100).to_s) * (count / 40)
78
- else
79
- res << Digest::SHA1.digest(rand(count * 100).to_s) * (count / 20)
80
- end
81
-
82
- return res
83
- end
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
104
-
105
- def test_horrible_queries
106
- parser = HttpParser.new
107
-
108
- # then that large header names are caught
109
- 10.times do |c|
110
- get = "GET /#{rand_data(10,120)} HTTP/1.1\r\nX-#{rand_data(1024, 1024+(c*1024))}: Test\r\n\r\n"
111
- assert_raises Puma::HttpParserError do
112
- parser.execute({}, get, 0)
113
- parser.reset
114
- end
115
- end
116
-
117
- # then that large mangled field values are caught
118
- 10.times do |c|
119
- get = "GET /#{rand_data(10,120)} HTTP/1.1\r\nX-Test: #{rand_data(1024, 1024+(c*1024), false)}\r\n\r\n"
120
- assert_raises Puma::HttpParserError do
121
- parser.execute({}, get, 0)
122
- parser.reset
123
- end
124
- end
125
-
126
- # then large headers are rejected too
127
- get = "GET /#{rand_data(10,120)} HTTP/1.1\r\n"
128
- get << "X-Test: test\r\n" * (80 * 1024)
129
- assert_raises Puma::HttpParserError do
130
- parser.execute({}, get, 0)
131
- parser.reset
132
- end
133
-
134
- # finally just that random garbage gets blocked all the time
135
- 10.times do |c|
136
- get = "GET #{rand_data(1024, 1024+(c*1024), false)} #{rand_data(1024, 1024+(c*1024), false)}\r\n\r\n"
137
- assert_raises Puma::HttpParserError do
138
- parser.execute({}, get, 0)
139
- parser.reset
140
- end
141
- end
142
-
143
- end
144
- end
145
-