puma 2.12.0-java → 2.12.1-java
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of puma might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/History.txt +16 -4
- data/README.md +1 -1
- data/ext/puma_http11/mini_ssl.c +2 -3
- data/lib/puma/const.rb +1 -1
- data/lib/puma/events.rb +3 -3
- data/lib/puma/puma_http11.jar +0 -0
- data/lib/puma/server.rb +1 -1
- metadata +5 -41
- data/test/test_app_status.rb +0 -92
- data/test/test_cli.rb +0 -173
- data/test/test_config.rb +0 -62
- data/test/test_http10.rb +0 -27
- data/test/test_http11.rb +0 -144
- data/test/test_integration.rb +0 -206
- data/test/test_iobuffer.rb +0 -38
- data/test/test_minissl.rb +0 -29
- data/test/test_null_io.rb +0 -31
- data/test/test_persistent.rb +0 -238
- data/test/test_puma_server.rb +0 -423
- data/test/test_puma_server_ssl.rb +0 -198
- data/test/test_rack_handler.rb +0 -10
- data/test/test_rack_server.rb +0 -140
- data/test/test_tcp_rack.rb +0 -42
- data/test/test_thread_pool.rb +0 -229
- data/test/test_unix_socket.rb +0 -39
- data/test/test_ws.rb +0 -89
data/test/test_config.rb
DELETED
@@ -1,62 +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_rackup
|
8
|
-
opts = {:rackup => "test/hello-bind.ru"}
|
9
|
-
conf = Puma::Configuration.new opts
|
10
|
-
conf.load
|
11
|
-
|
12
|
-
conf.app
|
13
|
-
|
14
|
-
assert_equal ["tcp://127.0.0.1:9292"], conf.options[:binds]
|
15
|
-
end
|
16
|
-
|
17
|
-
def test_app_from_app_DSL
|
18
|
-
opts = { :config_file => "test/config/app.rb" }
|
19
|
-
conf = Puma::Configuration.new opts
|
20
|
-
conf.load
|
21
|
-
|
22
|
-
app = conf.app
|
23
|
-
|
24
|
-
assert_equal [200, {}, ["embedded app"]], app.call({})
|
25
|
-
end
|
26
|
-
|
27
|
-
def test_double_bind_port
|
28
|
-
port = rand(30_000..40_000).to_s
|
29
|
-
with_env("PORT" => port) do
|
30
|
-
opts = { :binds => ["tcp://#{Configuration::DefaultTCPHost}:#{port}"], :config_file => "test/config/app.rb"}
|
31
|
-
conf = Puma::Configuration.new opts
|
32
|
-
conf.load
|
33
|
-
|
34
|
-
assert_equal ["tcp://0.0.0.0:#{port}"], conf.options[:binds]
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def test_lowleve_error_handler_DSL
|
39
|
-
opts = { :config_file => "test/config/app.rb" }
|
40
|
-
conf = Puma::Configuration.new opts
|
41
|
-
conf.load
|
42
|
-
|
43
|
-
app = conf.options[:lowlevel_error_handler]
|
44
|
-
|
45
|
-
assert_equal [200, {}, ["error page"]], app.call({})
|
46
|
-
end
|
47
|
-
|
48
|
-
private
|
49
|
-
|
50
|
-
def with_env(env = {})
|
51
|
-
original_env = {}
|
52
|
-
env.each do |k, v|
|
53
|
-
original_env[k] = ENV[k]
|
54
|
-
ENV[k] = v
|
55
|
-
end
|
56
|
-
yield
|
57
|
-
ensure
|
58
|
-
original_env.each do |k, v|
|
59
|
-
ENV[k] = v
|
60
|
-
end
|
61
|
-
end
|
62
|
-
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,144 +0,0 @@
|
|
1
|
-
# Copyright (c) 2011 Evan Phoenix
|
2
|
-
# Copyright (c) 2005 Zed A. Shaw
|
3
|
-
|
4
|
-
require '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(3000, 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
|
data/test/test_integration.rb
DELETED
@@ -1,206 +0,0 @@
|
|
1
|
-
require "rbconfig"
|
2
|
-
require 'test/unit'
|
3
|
-
require 'socket'
|
4
|
-
require 'timeout'
|
5
|
-
require 'net/http'
|
6
|
-
require 'tempfile'
|
7
|
-
|
8
|
-
require 'puma/cli'
|
9
|
-
require 'puma/control_cli'
|
10
|
-
|
11
|
-
# These don't run on travis because they're too fragile
|
12
|
-
|
13
|
-
class TestIntegration < Test::Unit::TestCase
|
14
|
-
def setup
|
15
|
-
@state_path = "test/test_puma.state"
|
16
|
-
@bind_path = "test/test_server.sock"
|
17
|
-
@control_path = "test/test_control.sock"
|
18
|
-
@tcp_port = 9998
|
19
|
-
|
20
|
-
@server = nil
|
21
|
-
@script = nil
|
22
|
-
|
23
|
-
@wait, @ready = IO.pipe
|
24
|
-
|
25
|
-
@events = Puma::Events.strings
|
26
|
-
@events.on_booted { @ready << "!" }
|
27
|
-
end
|
28
|
-
|
29
|
-
def teardown
|
30
|
-
File.unlink @state_path rescue nil
|
31
|
-
File.unlink @bind_path rescue nil
|
32
|
-
File.unlink @control_path rescue nil
|
33
|
-
|
34
|
-
@wait.close
|
35
|
-
@ready.close
|
36
|
-
|
37
|
-
if @server
|
38
|
-
Process.kill "INT", @server.pid
|
39
|
-
begin
|
40
|
-
Process.wait @server.pid
|
41
|
-
rescue Errno::ECHILD
|
42
|
-
end
|
43
|
-
|
44
|
-
@server.close
|
45
|
-
end
|
46
|
-
|
47
|
-
if @script
|
48
|
-
@script.close!
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def server(opts)
|
53
|
-
core = "#{Gem.ruby} -rubygems -Ilib bin/puma"
|
54
|
-
cmd = "#{core} --restart-cmd '#{core}' -b tcp://127.0.0.1:#{@tcp_port} #{opts}"
|
55
|
-
tf = Tempfile.new "puma-test"
|
56
|
-
tf.puts "exec #{cmd}"
|
57
|
-
tf.close
|
58
|
-
|
59
|
-
@script = tf
|
60
|
-
|
61
|
-
@server = IO.popen("sh #{tf.path}", "r")
|
62
|
-
|
63
|
-
true while @server.gets =~ /Ctrl-C/
|
64
|
-
|
65
|
-
sleep 1
|
66
|
-
|
67
|
-
@server
|
68
|
-
end
|
69
|
-
|
70
|
-
def signal(which)
|
71
|
-
Process.kill which, @server.pid
|
72
|
-
end
|
73
|
-
|
74
|
-
def wait_booted
|
75
|
-
@wait.sysread 1
|
76
|
-
end
|
77
|
-
|
78
|
-
def test_stop_via_pumactl
|
79
|
-
if defined?(JRUBY_VERSION) || RbConfig::CONFIG["host_os"] =~ /mingw|mswin/
|
80
|
-
assert true
|
81
|
-
return
|
82
|
-
end
|
83
|
-
|
84
|
-
cli = Puma::CLI.new %W!-q -S #{@state_path} -b unix://#{@bind_path} --control unix://#{@control_path} test/hello.ru!, @events
|
85
|
-
|
86
|
-
t = Thread.new do
|
87
|
-
cli.run
|
88
|
-
end
|
89
|
-
|
90
|
-
wait_booted
|
91
|
-
|
92
|
-
s = UNIXSocket.new @bind_path
|
93
|
-
s << "GET / HTTP/1.0\r\n\r\n"
|
94
|
-
assert_equal "Hello World", s.read.split("\r\n").last
|
95
|
-
|
96
|
-
sout = StringIO.new
|
97
|
-
|
98
|
-
ccli = Puma::ControlCLI.new %W!-S #{@state_path} stop!, sout
|
99
|
-
|
100
|
-
ccli.run
|
101
|
-
|
102
|
-
assert_kind_of Thread, t.join(1), "server didn't stop"
|
103
|
-
end
|
104
|
-
|
105
|
-
def notest_phased_restart_via_pumactl
|
106
|
-
if defined?(JRUBY_VERSION) || RbConfig::CONFIG["host_os"] =~ /mingw|mswin/
|
107
|
-
assert true
|
108
|
-
return
|
109
|
-
end
|
110
|
-
|
111
|
-
cli = Puma::CLI.new %W!-q -S #{@state_path} -b unix://#{@bind_path} --control unix://#{@control_path} -w 2 test/hello-stuck.ru!, @events
|
112
|
-
cli.options[:worker_shutdown_timeout] = 1
|
113
|
-
|
114
|
-
t = Thread.new do
|
115
|
-
cli.run
|
116
|
-
end
|
117
|
-
|
118
|
-
wait_booted
|
119
|
-
|
120
|
-
# Make both workers stuck
|
121
|
-
s1 = UNIXSocket.new @bind_path
|
122
|
-
s1 << "GET / HTTP/1.0\r\n\r\n"
|
123
|
-
s2 = UNIXSocket.new @bind_path
|
124
|
-
s2 << "GET / HTTP/1.0\r\n\r\n"
|
125
|
-
|
126
|
-
sout = StringIO.new
|
127
|
-
|
128
|
-
# Phased restart
|
129
|
-
ccli = Puma::ControlCLI.new %W!-S #{@state_path} phased-restart!, sout
|
130
|
-
ccli.run
|
131
|
-
sleep 20
|
132
|
-
@events.stdout.rewind
|
133
|
-
log = @events.stdout.readlines.join("")
|
134
|
-
assert_match(/TERM sent/, log)
|
135
|
-
assert_match(/KILL sent/, log)
|
136
|
-
assert_match(/Worker 0 \(pid: \d+\) booted, phase: 1/, log)
|
137
|
-
assert_match(/Worker 1 \(pid: \d+\) booted, phase: 1/, log)
|
138
|
-
|
139
|
-
# Stop
|
140
|
-
ccli = Puma::ControlCLI.new %W!-S #{@state_path} stop!, sout
|
141
|
-
ccli.run
|
142
|
-
|
143
|
-
assert_kind_of Thread, t.join(5), "server didn't stop"
|
144
|
-
end
|
145
|
-
|
146
|
-
def notest_restart_closes_keepalive_sockets
|
147
|
-
server("-q test/hello.ru")
|
148
|
-
|
149
|
-
s = TCPSocket.new "localhost", @tcp_port
|
150
|
-
s << "GET / HTTP/1.1\r\n\r\n"
|
151
|
-
true until s.gets == "\r\n"
|
152
|
-
|
153
|
-
s.readpartial(20)
|
154
|
-
signal :USR2
|
155
|
-
|
156
|
-
true while @server.gets =~ /Ctrl-C/
|
157
|
-
sleep 1
|
158
|
-
|
159
|
-
s.write "GET / HTTP/1.1\r\n\r\n"
|
160
|
-
|
161
|
-
assert_raises Errno::ECONNRESET do
|
162
|
-
Timeout.timeout(2) do
|
163
|
-
raise Errno::ECONNRESET unless s.read(2)
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
s = TCPSocket.new "localhost", @tcp_port
|
168
|
-
s << "GET / HTTP/1.0\r\n\r\n"
|
169
|
-
assert_equal "Hello World", s.read.split("\r\n").last
|
170
|
-
end
|
171
|
-
|
172
|
-
def notest_restart_closes_keepalive_sockets_workers
|
173
|
-
server("-q -w 2 test/hello.ru")
|
174
|
-
|
175
|
-
s = TCPSocket.new "localhost", @tcp_port
|
176
|
-
s << "GET / HTTP/1.1\r\n\r\n"
|
177
|
-
true until s.gets == "\r\n"
|
178
|
-
|
179
|
-
s.readpartial(20)
|
180
|
-
signal :USR2
|
181
|
-
|
182
|
-
true while @server.gets =~ /Ctrl-C/
|
183
|
-
sleep 1
|
184
|
-
|
185
|
-
s.write "GET / HTTP/1.1\r\n\r\n"
|
186
|
-
|
187
|
-
assert_raises Errno::ECONNRESET do
|
188
|
-
Timeout.timeout(2) do
|
189
|
-
raise Errno::ECONNRESET unless s.read(2)
|
190
|
-
end
|
191
|
-
end
|
192
|
-
|
193
|
-
s = TCPSocket.new "localhost", @tcp_port
|
194
|
-
s << "GET / HTTP/1.0\r\n\r\n"
|
195
|
-
assert_equal "Hello World", s.read.split("\r\n").last
|
196
|
-
end
|
197
|
-
|
198
|
-
def test_bad_query_string_outputs_400
|
199
|
-
server "-q test/hello.ru 2>&1"
|
200
|
-
|
201
|
-
s = TCPSocket.new "localhost", @tcp_port
|
202
|
-
s << "GET /?h=% HTTP/1.0\r\n\r\n"
|
203
|
-
data = s.read
|
204
|
-
assert_equal "HTTP/1.1 400 Bad Request\r\n\r\n", data
|
205
|
-
end
|
206
|
-
end unless ENV['TRAVIS']
|
data/test/test_iobuffer.rb
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
require 'puma/io_buffer'
|
2
|
-
require 'test/unit'
|
3
|
-
|
4
|
-
class TestIOBuffer < Test::Unit::TestCase
|
5
|
-
attr_accessor :iobuf
|
6
|
-
def setup
|
7
|
-
self.iobuf = Puma::IOBuffer.new
|
8
|
-
end
|
9
|
-
|
10
|
-
def test_initial_size
|
11
|
-
assert_equal 0, iobuf.used
|
12
|
-
assert iobuf.capacity > 0
|
13
|
-
end
|
14
|
-
|
15
|
-
def test_append_op
|
16
|
-
iobuf << "abc"
|
17
|
-
assert_equal "abc", iobuf.to_s
|
18
|
-
iobuf << "123"
|
19
|
-
assert_equal "abc123", iobuf.to_s
|
20
|
-
assert_equal 6, iobuf.used
|
21
|
-
end
|
22
|
-
|
23
|
-
def test_append
|
24
|
-
expected = "mary had a little lamb"
|
25
|
-
iobuf.append("mary", " ", "had ", "a little", " lamb")
|
26
|
-
assert_equal expected, iobuf.to_s
|
27
|
-
assert_equal expected.length, iobuf.used
|
28
|
-
end
|
29
|
-
|
30
|
-
def test_reset
|
31
|
-
iobuf << "content"
|
32
|
-
assert_equal "content", iobuf.to_s
|
33
|
-
iobuf.reset
|
34
|
-
assert_equal 0, iobuf.used
|
35
|
-
assert_equal "", iobuf.to_s
|
36
|
-
end
|
37
|
-
|
38
|
-
end
|