puma 2.11.3-java → 2.12.0-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/DEPLOYMENT.md +1 -2
- data/Gemfile +1 -1
- data/History.txt +49 -0
- data/Manifest.txt +5 -1
- data/README.md +14 -0
- data/Rakefile +1 -1
- data/ext/puma_http11/mini_ssl.c +132 -9
- data/lib/puma/binder.rb +31 -10
- data/lib/puma/capistrano.rb +8 -3
- data/lib/puma/cli.rb +21 -26
- data/lib/puma/cluster.rb +2 -0
- data/lib/puma/commonlogger.rb +107 -0
- data/lib/puma/configuration.rb +5 -3
- data/lib/puma/const.rb +81 -8
- data/lib/puma/control_cli.rb +9 -1
- data/lib/puma/events.rb +9 -0
- data/lib/puma/minissl.rb +23 -0
- data/lib/puma/puma_http11.jar +0 -0
- data/lib/puma/rack/backports/uri/common_18.rb +56 -0
- data/lib/puma/rack/backports/uri/common_192.rb +52 -0
- data/lib/puma/rack/backports/uri/common_193.rb +29 -0
- data/lib/puma/rack/builder.rb +298 -0
- data/lib/puma/reactor.rb +11 -0
- data/lib/puma/server.rb +44 -14
- data/lib/puma/thread_pool.rb +50 -1
- data/lib/puma/util.rb +123 -0
- data/puma.gemspec +0 -3
- data/test/test_config.rb +10 -0
- data/test/test_http11.rb +1 -1
- data/test/test_puma_server.rb +23 -0
- data/test/test_puma_server_ssl.rb +100 -2
- data/test/test_rack_server.rb +1 -2
- data/test/test_thread_pool.rb +47 -0
- data/tools/jungle/upstart/puma.conf +7 -1
- metadata +22 -18
- data/lib/puma/rack_patch.rb +0 -45
data/lib/puma/server.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'rack'
|
2
1
|
require 'stringio'
|
3
2
|
|
4
3
|
require 'puma/thread_pool'
|
@@ -13,8 +12,6 @@ require 'puma/delegation'
|
|
13
12
|
require 'puma/accept_nonblock'
|
14
13
|
require 'puma/util'
|
15
14
|
|
16
|
-
require 'puma/rack_patch'
|
17
|
-
|
18
15
|
require 'puma/puma_http11'
|
19
16
|
|
20
17
|
unless Puma.const_defined? "IOBuffer"
|
@@ -39,6 +36,7 @@ module Puma
|
|
39
36
|
attr_accessor :max_threads
|
40
37
|
attr_accessor :persistent_timeout
|
41
38
|
attr_accessor :auto_trim_time
|
39
|
+
attr_accessor :reaping_time
|
42
40
|
attr_accessor :first_data_timeout
|
43
41
|
|
44
42
|
# Create a server for the rack app +app+.
|
@@ -60,6 +58,7 @@ module Puma
|
|
60
58
|
@min_threads = 0
|
61
59
|
@max_threads = 16
|
62
60
|
@auto_trim_time = 1
|
61
|
+
@reaping_time = 1
|
63
62
|
|
64
63
|
@thread = nil
|
65
64
|
@thread_pool = nil
|
@@ -250,6 +249,14 @@ module Puma
|
|
250
249
|
client.finish
|
251
250
|
process_now = true
|
252
251
|
end
|
252
|
+
rescue MiniSSL::SSLError => e
|
253
|
+
ssl_socket = client.io
|
254
|
+
addr = ssl_socket.peeraddr.last
|
255
|
+
cert = ssl_socket.peercert
|
256
|
+
|
257
|
+
client.close
|
258
|
+
|
259
|
+
@events.ssl_error self, addr, cert, e
|
253
260
|
rescue HttpParserError => e
|
254
261
|
client.write_400
|
255
262
|
client.close
|
@@ -274,6 +281,10 @@ module Puma
|
|
274
281
|
@reactor.run_in_thread
|
275
282
|
end
|
276
283
|
|
284
|
+
if @reaping_time
|
285
|
+
@thread_pool.auto_reap!(@reaping_time)
|
286
|
+
end
|
287
|
+
|
277
288
|
if @auto_trim_time
|
278
289
|
@thread_pool.auto_trim!(@auto_trim_time)
|
279
290
|
end
|
@@ -395,6 +406,16 @@ module Puma
|
|
395
406
|
rescue ConnectionError
|
396
407
|
# Swallow them. The ensure tries to close +client+ down
|
397
408
|
|
409
|
+
# SSL handshake error
|
410
|
+
rescue MiniSSL::SSLError => e
|
411
|
+
ssl_socket = client.io
|
412
|
+
addr = ssl_socket.peeraddr.last
|
413
|
+
cert = ssl_socket.peercert
|
414
|
+
|
415
|
+
close_socket = true
|
416
|
+
|
417
|
+
@events.ssl_error self, addr, cert, e
|
418
|
+
|
398
419
|
# The client doesn't know HTTP well
|
399
420
|
rescue HttpParserError => e
|
400
421
|
client.write_400
|
@@ -457,16 +478,23 @@ module Puma
|
|
457
478
|
#
|
458
479
|
|
459
480
|
unless env.key?(REMOTE_ADDR)
|
460
|
-
|
481
|
+
begin
|
482
|
+
addr = client.peeraddr.last
|
483
|
+
rescue Errno::ENOTCONN
|
484
|
+
# Client disconnects can result in an inability to get the
|
485
|
+
# peeraddr from the socket; default to localhost.
|
486
|
+
addr = LOCALHOST_IP
|
487
|
+
end
|
461
488
|
|
462
489
|
# Set unix socket addrs to localhost
|
463
|
-
addr =
|
490
|
+
addr = LOCALHOST_IP if addr.empty?
|
464
491
|
|
465
492
|
env[REMOTE_ADDR] = addr
|
466
493
|
end
|
467
494
|
end
|
468
495
|
|
469
496
|
def default_server_port(env)
|
497
|
+
return PORT_443 if env[HTTPS_KEY] == 'on' || env[HTTPS_KEY] == 'https'
|
470
498
|
env['HTTP_X_FORWARDED_PROTO'] == 'https' ? PORT_443 : PORT_80
|
471
499
|
end
|
472
500
|
|
@@ -487,6 +515,10 @@ module Puma
|
|
487
515
|
|
488
516
|
env[PUMA_SOCKET] = client
|
489
517
|
|
518
|
+
if env[HTTPS_KEY] && client.peercert
|
519
|
+
env[PUMA_PEERCERT] = client.peercert
|
520
|
+
end
|
521
|
+
|
490
522
|
env[HIJACK_P] = true
|
491
523
|
env[HIJACK] = req
|
492
524
|
|
@@ -610,15 +642,13 @@ module Puma
|
|
610
642
|
fast_write client, lines.to_s
|
611
643
|
return keep_alive
|
612
644
|
end
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
chunked = true
|
621
|
-
end
|
645
|
+
|
646
|
+
if content_length
|
647
|
+
lines.append CONTENT_LENGTH_S, content_length.to_s, line_ending
|
648
|
+
chunked = false
|
649
|
+
elsif !response_hijack and allow_chunked
|
650
|
+
lines << TRANSFER_ENCODING_CHUNKED
|
651
|
+
chunked = true
|
622
652
|
end
|
623
653
|
|
624
654
|
lines << line_ending
|
data/lib/puma/thread_pool.rb
CHANGED
@@ -33,6 +33,7 @@ module Puma
|
|
33
33
|
@workers = []
|
34
34
|
|
35
35
|
@auto_trim = nil
|
36
|
+
@reaper = nil
|
36
37
|
|
37
38
|
@mutex.synchronize do
|
38
39
|
@min.times { spawn_thread }
|
@@ -101,7 +102,10 @@ module Puma
|
|
101
102
|
end
|
102
103
|
end
|
103
104
|
|
104
|
-
|
105
|
+
begin
|
106
|
+
block.call(work, *extra)
|
107
|
+
rescue Exception
|
108
|
+
end
|
105
109
|
end
|
106
110
|
|
107
111
|
mutex.synchronize do
|
@@ -155,6 +159,21 @@ module Puma
|
|
155
159
|
end
|
156
160
|
end
|
157
161
|
|
162
|
+
# If there are dead threads in the pool make them go away while decreasing
|
163
|
+
# spwaned counter so that new healty threads could be created again.
|
164
|
+
def reap
|
165
|
+
@mutex.synchronize do
|
166
|
+
dead_workers = @workers.reject(&:alive?)
|
167
|
+
|
168
|
+
dead_workers.each do |worker|
|
169
|
+
worker.kill
|
170
|
+
@spawned -= 1
|
171
|
+
end
|
172
|
+
|
173
|
+
@workers -= dead_workers
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
158
177
|
class AutoTrim
|
159
178
|
def initialize(pool, timeout)
|
160
179
|
@pool = pool
|
@@ -184,6 +203,35 @@ module Puma
|
|
184
203
|
@auto_trim.start!
|
185
204
|
end
|
186
205
|
|
206
|
+
class Reaper
|
207
|
+
def initialize(pool, timeout)
|
208
|
+
@pool = pool
|
209
|
+
@timeout = timeout
|
210
|
+
@running = false
|
211
|
+
end
|
212
|
+
|
213
|
+
def start!
|
214
|
+
@running = true
|
215
|
+
|
216
|
+
@thread = Thread.new do
|
217
|
+
while @running
|
218
|
+
@pool.reap
|
219
|
+
sleep @timeout
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
def stop
|
225
|
+
@running = false
|
226
|
+
@thread.wakeup
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
def auto_reap!(timeout=5)
|
231
|
+
@reaper = Reaper.new(self, timeout)
|
232
|
+
@reaper.start!
|
233
|
+
end
|
234
|
+
|
187
235
|
# Tell all threads in the pool to exit and wait for them to finish.
|
188
236
|
#
|
189
237
|
def shutdown
|
@@ -193,6 +241,7 @@ module Puma
|
|
193
241
|
@not_full.broadcast
|
194
242
|
|
195
243
|
@auto_trim.stop if @auto_trim
|
244
|
+
@reaper.stop if @reaper
|
196
245
|
end
|
197
246
|
|
198
247
|
# Use this instead of #each so that we don't stop in the middle
|
data/lib/puma/util.rb
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
major, minor, patch = RUBY_VERSION.split('.').map { |v| v.to_i }
|
2
|
+
|
3
|
+
if major == 1 && minor < 9
|
4
|
+
require 'puma/rack/backports/uri/common_18'
|
5
|
+
elsif major == 1 && minor == 9 && patch == 2 && RUBY_PATCHLEVEL <= 328 && RUBY_ENGINE != 'jruby'
|
6
|
+
require 'puma/rack/backports/uri/common_192'
|
7
|
+
elsif major == 1 && minor == 9 && patch == 3 && RUBY_PATCHLEVEL < 125
|
8
|
+
require 'puma/rack/backports/uri/common_193'
|
9
|
+
else
|
10
|
+
require 'uri/common'
|
11
|
+
end
|
12
|
+
|
1
13
|
module Puma
|
2
14
|
module Util
|
3
15
|
module_function
|
@@ -5,5 +17,116 @@ module Puma
|
|
5
17
|
def pipe
|
6
18
|
IO.pipe
|
7
19
|
end
|
20
|
+
|
21
|
+
# Unescapes a URI escaped string with +encoding+. +encoding+ will be the
|
22
|
+
# target encoding of the string returned, and it defaults to UTF-8
|
23
|
+
if defined?(::Encoding)
|
24
|
+
def unescape(s, encoding = Encoding::UTF_8)
|
25
|
+
URI.decode_www_form_component(s, encoding)
|
26
|
+
end
|
27
|
+
else
|
28
|
+
def unescape(s, encoding = nil)
|
29
|
+
URI.decode_www_form_component(s, encoding)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
module_function :unescape
|
33
|
+
|
34
|
+
DEFAULT_SEP = /[&;] */n
|
35
|
+
|
36
|
+
# Stolen from Mongrel, with some small modifications:
|
37
|
+
# Parses a query string by breaking it up at the '&'
|
38
|
+
# and ';' characters. You can also use this to parse
|
39
|
+
# cookies by changing the characters used in the second
|
40
|
+
# parameter (which defaults to '&;').
|
41
|
+
def parse_query(qs, d = nil, &unescaper)
|
42
|
+
unescaper ||= method(:unescape)
|
43
|
+
|
44
|
+
params = {}
|
45
|
+
|
46
|
+
(qs || '').split(d ? /[#{d}] */n : DEFAULT_SEP).each do |p|
|
47
|
+
next if p.empty?
|
48
|
+
k, v = p.split('=', 2).map(&unescaper)
|
49
|
+
|
50
|
+
if cur = params[k]
|
51
|
+
if cur.class == Array
|
52
|
+
params[k] << v
|
53
|
+
else
|
54
|
+
params[k] = [cur, v]
|
55
|
+
end
|
56
|
+
else
|
57
|
+
params[k] = v
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
return params
|
62
|
+
end
|
63
|
+
|
64
|
+
# A case-insensitive Hash that preserves the original case of a
|
65
|
+
# header when set.
|
66
|
+
class HeaderHash < Hash
|
67
|
+
def self.new(hash={})
|
68
|
+
HeaderHash === hash ? hash : super(hash)
|
69
|
+
end
|
70
|
+
|
71
|
+
def initialize(hash={})
|
72
|
+
super()
|
73
|
+
@names = {}
|
74
|
+
hash.each { |k, v| self[k] = v }
|
75
|
+
end
|
76
|
+
|
77
|
+
def each
|
78
|
+
super do |k, v|
|
79
|
+
yield(k, v.respond_to?(:to_ary) ? v.to_ary.join("\n") : v)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def to_hash
|
84
|
+
hash = {}
|
85
|
+
each { |k,v| hash[k] = v }
|
86
|
+
hash
|
87
|
+
end
|
88
|
+
|
89
|
+
def [](k)
|
90
|
+
super(k) || super(@names[k.downcase])
|
91
|
+
end
|
92
|
+
|
93
|
+
def []=(k, v)
|
94
|
+
canonical = k.downcase
|
95
|
+
delete k if @names[canonical] && @names[canonical] != k # .delete is expensive, don't invoke it unless necessary
|
96
|
+
@names[k] = @names[canonical] = k
|
97
|
+
super k, v
|
98
|
+
end
|
99
|
+
|
100
|
+
def delete(k)
|
101
|
+
canonical = k.downcase
|
102
|
+
result = super @names.delete(canonical)
|
103
|
+
@names.delete_if { |name,| name.downcase == canonical }
|
104
|
+
result
|
105
|
+
end
|
106
|
+
|
107
|
+
def include?(k)
|
108
|
+
@names.include?(k) || @names.include?(k.downcase)
|
109
|
+
end
|
110
|
+
|
111
|
+
alias_method :has_key?, :include?
|
112
|
+
alias_method :member?, :include?
|
113
|
+
alias_method :key?, :include?
|
114
|
+
|
115
|
+
def merge!(other)
|
116
|
+
other.each { |k, v| self[k] = v }
|
117
|
+
self
|
118
|
+
end
|
119
|
+
|
120
|
+
def merge(other)
|
121
|
+
hash = dup
|
122
|
+
hash.merge! other
|
123
|
+
end
|
124
|
+
|
125
|
+
def replace(other)
|
126
|
+
clear
|
127
|
+
other.each { |k, v| self[k] = v }
|
128
|
+
self
|
129
|
+
end
|
130
|
+
end
|
8
131
|
end
|
9
132
|
end
|
data/puma.gemspec
CHANGED
@@ -36,18 +36,15 @@ Gem::Specification.new do |s|
|
|
36
36
|
s.specification_version = 3
|
37
37
|
|
38
38
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
39
|
-
s.add_runtime_dependency(%q<rack>, ["< 2.0", ">= 1.1"])
|
40
39
|
s.add_development_dependency(%q<rdoc>, ["~> 4.0"])
|
41
40
|
s.add_development_dependency(%q<rake-compiler>, ["~> 0.8.0"])
|
42
41
|
s.add_development_dependency(%q<hoe>, ["~> 3.6"])
|
43
42
|
else
|
44
|
-
s.add_dependency(%q<rack>, ["< 2.0", ">= 1.1"])
|
45
43
|
s.add_dependency(%q<rdoc>, ["~> 4.0"])
|
46
44
|
s.add_dependency(%q<rake-compiler>, ["~> 0.8.0"])
|
47
45
|
s.add_dependency(%q<hoe>, ["~> 3.6"])
|
48
46
|
end
|
49
47
|
else
|
50
|
-
s.add_dependency(%q<rack>, ["< 2.0", ">= 1.1"])
|
51
48
|
s.add_dependency(%q<rdoc>, ["~> 4.0"])
|
52
49
|
s.add_dependency(%q<rake-compiler>, ["~> 0.8.0"])
|
53
50
|
s.add_dependency(%q<hoe>, ["~> 3.6"])
|
data/test/test_config.rb
CHANGED
@@ -4,6 +4,16 @@ require 'puma'
|
|
4
4
|
require 'puma/configuration'
|
5
5
|
|
6
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
|
+
|
7
17
|
def test_app_from_app_DSL
|
8
18
|
opts = { :config_file => "test/config/app.rb" }
|
9
19
|
conf = Puma::Configuration.new opts
|
data/test/test_http11.rb
CHANGED
@@ -94,7 +94,7 @@ class Http11ParserTest < Test::Unit::TestCase
|
|
94
94
|
parser.reset
|
95
95
|
|
96
96
|
# Raise exception if URI path length > 2048
|
97
|
-
path = "/" + rand_data(
|
97
|
+
path = "/" + rand_data(3000, 100)
|
98
98
|
http = "GET #{path} HTTP/1.1\r\n\r\n"
|
99
99
|
assert_raises Puma::HttpParserError do
|
100
100
|
parser.execute(req, http, 0)
|
data/test/test_puma_server.rb
CHANGED
@@ -369,7 +369,30 @@ class TestPumaServer < Test::Unit::TestCase
|
|
369
369
|
|
370
370
|
assert_equal "HTTP/1.0 200 OK\r\nContent-Type: plain/text\r\nContent-Length: 5\r\n\r\nhello", data
|
371
371
|
end
|
372
|
+
|
373
|
+
def test_http_10_partial_hijack_with_content_length
|
374
|
+
body_parts = ['abc', 'de']
|
375
|
+
|
376
|
+
@server.app = proc do |env|
|
377
|
+
hijack_lambda = proc do | io |
|
378
|
+
io.write(body_parts[0])
|
379
|
+
io.write(body_parts[1])
|
380
|
+
io.close
|
381
|
+
end
|
382
|
+
[200, {"Content-Length" => "5", 'rack.hijack' => hijack_lambda}, nil]
|
383
|
+
end
|
384
|
+
|
385
|
+
@server.add_tcp_listener @host, @port
|
386
|
+
@server.run
|
387
|
+
|
388
|
+
sock = TCPSocket.new @host, @port
|
389
|
+
sock << "GET / HTTP/1.0\r\nConnection: close\r\n\r\n"
|
372
390
|
|
391
|
+
data = sock.read
|
392
|
+
|
393
|
+
assert_equal "HTTP/1.0 200 OK\r\nContent-Length: 5\r\n\r\nabcde", data
|
394
|
+
end
|
395
|
+
|
373
396
|
def test_http_10_keep_alive_without_body
|
374
397
|
@server.app = proc { |env| [204, {}, []] }
|
375
398
|
|
@@ -8,6 +8,16 @@ require 'puma/server'
|
|
8
8
|
|
9
9
|
require 'net/https'
|
10
10
|
|
11
|
+
class SSLEventsHelper < ::Puma::Events
|
12
|
+
attr_accessor :addr, :cert, :error
|
13
|
+
|
14
|
+
def ssl_error(server, peeraddr, peercert, error)
|
15
|
+
self.addr = peeraddr
|
16
|
+
self.cert = peercert
|
17
|
+
self.error = error
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
11
21
|
class TestPumaServerSSL < Test::Unit::TestCase
|
12
22
|
|
13
23
|
def setup
|
@@ -28,7 +38,7 @@ class TestPumaServerSSL < Test::Unit::TestCase
|
|
28
38
|
|
29
39
|
@ctx.verify_mode = Puma::MiniSSL::VERIFY_NONE
|
30
40
|
|
31
|
-
@events =
|
41
|
+
@events = SSLEventsHelper.new STDOUT, STDERR
|
32
42
|
@server = Puma::Server.new @app, @events
|
33
43
|
@server.add_ssl_listener @host, @port, @ctx
|
34
44
|
@server.run
|
@@ -95,6 +105,94 @@ class TestPumaServerSSL < Test::Unit::TestCase
|
|
95
105
|
Net::HTTP::Get.new '/'
|
96
106
|
end
|
97
107
|
end
|
108
|
+
unless defined?(JRUBY_VERSION)
|
109
|
+
assert_match("wrong version number", @events.error.message) if @events.error
|
110
|
+
end
|
98
111
|
end
|
99
112
|
|
100
|
-
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# client-side TLS authentication tests
|
116
|
+
unless defined?(JRUBY_VERSION)
|
117
|
+
class TestPumaServerSSLClient < Test::Unit::TestCase
|
118
|
+
|
119
|
+
def assert_ssl_client_error_match(error, subject=nil, &blk)
|
120
|
+
@port = 3212
|
121
|
+
@host = "127.0.0.1"
|
122
|
+
|
123
|
+
@app = lambda { |env| [200, {}, [env['rack.url_scheme']]] }
|
124
|
+
|
125
|
+
@ctx = Puma::MiniSSL::Context.new
|
126
|
+
@ctx.key = File.expand_path "../../examples/puma/client-certs/server.key", __FILE__
|
127
|
+
@ctx.cert = File.expand_path "../../examples/puma/client-certs/server.crt", __FILE__
|
128
|
+
@ctx.ca = File.expand_path "../../examples/puma/client-certs/ca.crt", __FILE__
|
129
|
+
@ctx.verify_mode = Puma::MiniSSL::VERIFY_PEER | Puma::MiniSSL::VERIFY_FAIL_IF_NO_PEER_CERT
|
130
|
+
|
131
|
+
events = SSLEventsHelper.new STDOUT, STDERR
|
132
|
+
@server = Puma::Server.new @app, events
|
133
|
+
@server.add_ssl_listener @host, @port, @ctx
|
134
|
+
@server.run
|
135
|
+
|
136
|
+
@http = Net::HTTP.new @host, @port
|
137
|
+
@http.use_ssl = true
|
138
|
+
@http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
139
|
+
|
140
|
+
blk.call(@http)
|
141
|
+
|
142
|
+
client_error = false
|
143
|
+
begin
|
144
|
+
@http.start do
|
145
|
+
req = Net::HTTP::Get.new "/", {}
|
146
|
+
@http.request(req)
|
147
|
+
end
|
148
|
+
rescue OpenSSL::SSL::SSLError
|
149
|
+
client_error = true
|
150
|
+
end
|
151
|
+
|
152
|
+
sleep 0.1
|
153
|
+
assert_equal !!error, client_error
|
154
|
+
assert_match error, events.error.message if error
|
155
|
+
assert_equal @host, events.addr if error
|
156
|
+
assert_equal subject, events.cert.subject.to_s if subject
|
157
|
+
ensure
|
158
|
+
@server.stop(true)
|
159
|
+
end
|
160
|
+
|
161
|
+
def test_verify_fail_if_no_client_cert
|
162
|
+
assert_ssl_client_error_match 'peer did not return a certificate' do |http|
|
163
|
+
# nothing
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def test_verify_fail_if_client_unknown_ca
|
168
|
+
assert_ssl_client_error_match('self signed certificate in certificate chain', '/DC=net/DC=puma/CN=ca-unknown') do |http|
|
169
|
+
key = File.expand_path "../../examples/puma/client-certs/client_unknown.key", __FILE__
|
170
|
+
crt = File.expand_path "../../examples/puma/client-certs/client_unknown.crt", __FILE__
|
171
|
+
http.key = OpenSSL::PKey::RSA.new File.read(key)
|
172
|
+
http.cert = OpenSSL::X509::Certificate.new File.read(crt)
|
173
|
+
http.ca_file = File.expand_path "../../examples/puma/client-certs/unknown_ca.crt", __FILE__
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def test_verify_fail_if_client_expired_cert
|
178
|
+
assert_ssl_client_error_match('certificate has expired', '/DC=net/DC=puma/CN=client-expired') do |http|
|
179
|
+
key = File.expand_path "../../examples/puma/client-certs/client_expired.key", __FILE__
|
180
|
+
crt = File.expand_path "../../examples/puma/client-certs/client_expired.crt", __FILE__
|
181
|
+
http.key = OpenSSL::PKey::RSA.new File.read(key)
|
182
|
+
http.cert = OpenSSL::X509::Certificate.new File.read(crt)
|
183
|
+
http.ca_file = File.expand_path "../../examples/puma/client-certs/ca.crt", __FILE__
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def test_verify_client_cert
|
188
|
+
assert_ssl_client_error_match(nil) do |http|
|
189
|
+
key = File.expand_path "../../examples/puma/client-certs/client.key", __FILE__
|
190
|
+
crt = File.expand_path "../../examples/puma/client-certs/client.crt", __FILE__
|
191
|
+
http.key = OpenSSL::PKey::RSA.new File.read(key)
|
192
|
+
http.cert = OpenSSL::X509::Certificate.new File.read(crt)
|
193
|
+
http.ca_file = File.expand_path "../../examples/puma/client-certs/ca.crt", __FILE__
|
194
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|