puma 2.11.1 → 2.11.2

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.

@@ -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
@@ -1,26 +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
-
17
- def test_lowleve_error_handler_DSL
18
- opts = { :config_file => "test/config/app.rb" }
19
- conf = Puma::Configuration.new opts
20
- conf.load
21
-
22
- app = conf.options[:lowlevel_error_handler]
23
-
24
- assert_equal [200, {}, ["error page"]], app.call({})
25
- end
26
- end
@@ -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
@@ -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(2049, 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
@@ -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']