puma 2.11.3 → 2.12.0
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/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/tools/jungle/upstart/puma.conf +7 -1
- metadata +22 -18
- data/lib/puma/rack_patch.rb +0 -45
data/lib/puma/capistrano.rb
CHANGED
@@ -22,7 +22,7 @@ Capistrano::Configuration.instance.load do
|
|
22
22
|
namespace :puma do
|
23
23
|
desc 'Start puma'
|
24
24
|
task :start, :roles => lambda { puma_role }, :on_no_matching_servers => :continue do
|
25
|
-
run "cd #{current_path} && #{puma_cmd} #{start_options}", :pty => false
|
25
|
+
run "cd #{current_path} && #{puma_rails_additional_env} #{puma_cmd} #{start_options}", :pty => false
|
26
26
|
end
|
27
27
|
|
28
28
|
desc 'Stop puma'
|
@@ -33,7 +33,7 @@ Capistrano::Configuration.instance.load do
|
|
33
33
|
desc 'Restart puma'
|
34
34
|
task :restart, :roles => lambda { puma_role }, :on_no_matching_servers => :continue do
|
35
35
|
begin
|
36
|
-
run "cd #{current_path} && #{pumactl_cmd} -S #{state_path} restart"
|
36
|
+
run "cd #{current_path} && #{puma_rails_additional_env} #{pumactl_cmd} -S #{state_path} restart"
|
37
37
|
rescue Capistrano::CommandError => ex
|
38
38
|
puts "Failed to restart puma: #{ex}\nAssuming not started."
|
39
39
|
start
|
@@ -43,7 +43,7 @@ Capistrano::Configuration.instance.load do
|
|
43
43
|
desc 'Restart puma (phased restart)'
|
44
44
|
task :phased_restart, :roles => lambda { puma_role }, :on_no_matching_servers => :continue do
|
45
45
|
begin
|
46
|
-
run "cd #{current_path} && #{pumactl_cmd} -S #{state_path} phased-restart"
|
46
|
+
run "cd #{current_path} && #{puma_rails_additional_env} #{pumactl_cmd} -S #{state_path} phased-restart"
|
47
47
|
rescue Capistrano::CommandError => ex
|
48
48
|
puts "Failed to restart puma: #{ex}\nAssuming not started."
|
49
49
|
start
|
@@ -72,6 +72,11 @@ Capistrano::Configuration.instance.load do
|
|
72
72
|
fetch(:rack_env, fetch(:rails_env, 'production'))
|
73
73
|
end
|
74
74
|
|
75
|
+
#add additional env when start rails, such as : secret key, db username, db pwd or other what you want.
|
76
|
+
def puma_rails_additional_env
|
77
|
+
fetch(:puma_rails_additional_env, '')
|
78
|
+
end
|
79
|
+
|
75
80
|
def state_path
|
76
81
|
(config_file ? configuration.options[:state] : nil) || puma_state
|
77
82
|
end
|
data/lib/puma/cli.rb
CHANGED
@@ -11,8 +11,7 @@ require 'puma/util'
|
|
11
11
|
require 'puma/single'
|
12
12
|
require 'puma/cluster'
|
13
13
|
|
14
|
-
require '
|
15
|
-
require 'rack/utils'
|
14
|
+
require 'puma/commonlogger'
|
16
15
|
|
17
16
|
module Puma
|
18
17
|
class << self
|
@@ -408,7 +407,7 @@ module Puma
|
|
408
407
|
|
409
408
|
o.on "-V", "--version", "Print the version information" do
|
410
409
|
puts "puma version #{Puma::Const::VERSION}"
|
411
|
-
exit
|
410
|
+
exit 0
|
412
411
|
end
|
413
412
|
|
414
413
|
o.on "-w", "--workers COUNT",
|
@@ -424,7 +423,7 @@ module Puma
|
|
424
423
|
|
425
424
|
o.on_tail "-h", "--help", "Show help" do
|
426
425
|
log o
|
427
|
-
exit
|
426
|
+
exit 0
|
428
427
|
end
|
429
428
|
end
|
430
429
|
end
|
@@ -445,32 +444,28 @@ module Puma
|
|
445
444
|
|
446
445
|
@restart_dir ||= Dir.pwd
|
447
446
|
|
448
|
-
@original_argv =
|
447
|
+
@original_argv = @argv.dup
|
449
448
|
|
450
|
-
|
451
|
-
|
449
|
+
require 'rubygems'
|
450
|
+
|
451
|
+
# if $0 is a file in the current directory, then restart
|
452
|
+
# it the same, otherwise add -S on there because it was
|
453
|
+
# picked up in PATH.
|
454
|
+
#
|
455
|
+
if File.exist?($0)
|
456
|
+
arg0 = [Gem.ruby, $0]
|
452
457
|
else
|
453
|
-
|
454
|
-
|
455
|
-
# if $0 is a file in the current directory, then restart
|
456
|
-
# it the same, otherwise add -S on there because it was
|
457
|
-
# picked up in PATH.
|
458
|
-
#
|
459
|
-
if File.exist?($0)
|
460
|
-
arg0 = [Gem.ruby, $0]
|
461
|
-
else
|
462
|
-
arg0 = [Gem.ruby, "-S", $0]
|
463
|
-
end
|
458
|
+
arg0 = [Gem.ruby, "-S", $0]
|
459
|
+
end
|
464
460
|
|
465
|
-
|
466
|
-
|
467
|
-
|
461
|
+
# Detect and reinject -Ilib from the command line
|
462
|
+
lib = File.expand_path "lib"
|
463
|
+
arg0[1,0] = ["-I", lib] if $:[0] == lib
|
468
464
|
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
end
|
465
|
+
if defined? Puma::WILD_ARGS
|
466
|
+
@restart_argv = arg0 + Puma::WILD_ARGS + @original_argv
|
467
|
+
else
|
468
|
+
@restart_argv = arg0 + @original_argv
|
474
469
|
end
|
475
470
|
end
|
476
471
|
|
data/lib/puma/cluster.rb
CHANGED
@@ -0,0 +1,107 @@
|
|
1
|
+
module Puma
|
2
|
+
# Rack::CommonLogger forwards every request to the given +app+, and
|
3
|
+
# logs a line in the
|
4
|
+
# {Apache common log format}[http://httpd.apache.org/docs/1.3/logs.html#common]
|
5
|
+
# to the +logger+.
|
6
|
+
#
|
7
|
+
# If +logger+ is nil, CommonLogger will fall back +rack.errors+, which is
|
8
|
+
# an instance of Rack::NullLogger.
|
9
|
+
#
|
10
|
+
# +logger+ can be any class, including the standard library Logger, and is
|
11
|
+
# expected to have either +write+ or +<<+ method, which accepts the CommonLogger::FORMAT.
|
12
|
+
# According to the SPEC, the error stream must also respond to +puts+
|
13
|
+
# (which takes a single argument that responds to +to_s+), and +flush+
|
14
|
+
# (which is called without arguments in order to make the error appear for
|
15
|
+
# sure)
|
16
|
+
class CommonLogger
|
17
|
+
# Common Log Format: http://httpd.apache.org/docs/1.3/logs.html#common
|
18
|
+
#
|
19
|
+
# lilith.local - - [07/Aug/2006 23:58:02 -0400] "GET / HTTP/1.1" 500 -
|
20
|
+
#
|
21
|
+
# %{%s - %s [%s] "%s %s%s %s" %d %s\n} %
|
22
|
+
FORMAT = %{%s - %s [%s] "%s %s%s %s" %d %s %0.4f\n}
|
23
|
+
|
24
|
+
def initialize(app, logger=nil)
|
25
|
+
@app = app
|
26
|
+
@logger = logger
|
27
|
+
end
|
28
|
+
|
29
|
+
def call(env)
|
30
|
+
began_at = Time.now
|
31
|
+
status, header, body = @app.call(env)
|
32
|
+
header = Util::HeaderHash.new(header)
|
33
|
+
|
34
|
+
# If we've been hijacked, then output a special line
|
35
|
+
if env['rack.hijack_io']
|
36
|
+
log_hijacking(env, 'HIJACK', header, began_at)
|
37
|
+
else
|
38
|
+
ary = env['rack.after_reply']
|
39
|
+
ary << lambda { log(env, status, header, began_at) }
|
40
|
+
end
|
41
|
+
|
42
|
+
[status, header, body]
|
43
|
+
end
|
44
|
+
|
45
|
+
HIJACK_FORMAT = %{%s - %s [%s] "%s %s%s %s" HIJACKED -1 %0.4f\n}
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def log_hijacking(env, status, header, began_at)
|
50
|
+
now = Time.now
|
51
|
+
|
52
|
+
logger = @logger || env['rack.errors']
|
53
|
+
logger.write HIJACK_FORMAT % [
|
54
|
+
env['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-",
|
55
|
+
env["REMOTE_USER"] || "-",
|
56
|
+
now.strftime("%d/%b/%Y %H:%M:%S"),
|
57
|
+
env["REQUEST_METHOD"],
|
58
|
+
env["PATH_INFO"],
|
59
|
+
env["QUERY_STRING"].empty? ? "" : "?"+env["QUERY_STRING"],
|
60
|
+
env["HTTP_VERSION"],
|
61
|
+
now - began_at ]
|
62
|
+
end
|
63
|
+
|
64
|
+
PATH_INFO = 'PATH_INFO'.freeze
|
65
|
+
REQUEST_METHOD = 'REQUEST_METHOD'.freeze
|
66
|
+
SCRIPT_NAME = 'SCRIPT_NAME'.freeze
|
67
|
+
QUERY_STRING = 'QUERY_STRING'.freeze
|
68
|
+
CACHE_CONTROL = 'Cache-Control'.freeze
|
69
|
+
CONTENT_LENGTH = 'Content-Length'.freeze
|
70
|
+
CONTENT_TYPE = 'Content-Type'.freeze
|
71
|
+
|
72
|
+
GET = 'GET'.freeze
|
73
|
+
HEAD = 'HEAD'.freeze
|
74
|
+
|
75
|
+
|
76
|
+
def log(env, status, header, began_at)
|
77
|
+
now = Time.now
|
78
|
+
length = extract_content_length(header)
|
79
|
+
|
80
|
+
msg = FORMAT % [
|
81
|
+
env['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-",
|
82
|
+
env["REMOTE_USER"] || "-",
|
83
|
+
now.strftime("%d/%b/%Y:%H:%M:%S %z"),
|
84
|
+
env[REQUEST_METHOD],
|
85
|
+
env[PATH_INFO],
|
86
|
+
env[QUERY_STRING].empty? ? "" : "?"+env[QUERY_STRING],
|
87
|
+
env["HTTP_VERSION"],
|
88
|
+
status.to_s[0..3],
|
89
|
+
length,
|
90
|
+
now - began_at ]
|
91
|
+
|
92
|
+
logger = @logger || env['rack.errors']
|
93
|
+
# Standard library logger doesn't support write but it supports << which actually
|
94
|
+
# calls to write on the log device without formatting
|
95
|
+
if logger.respond_to?(:write)
|
96
|
+
logger.write(msg)
|
97
|
+
else
|
98
|
+
logger << msg
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def extract_content_length(headers)
|
103
|
+
value = headers[CONTENT_LENGTH] or return '-'
|
104
|
+
value.to_s == '0' ? '-' : value
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
data/lib/puma/configuration.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'puma/rack/builder'
|
2
|
+
|
1
3
|
module Puma
|
2
4
|
|
3
5
|
module ConfigDefault
|
@@ -77,7 +79,7 @@ module Puma
|
|
77
79
|
|
78
80
|
if !@options[:quiet] and @options[:environment] == "development"
|
79
81
|
logger = @options[:logger] || STDOUT
|
80
|
-
found =
|
82
|
+
found = CommonLogger.new(found, logger)
|
81
83
|
end
|
82
84
|
|
83
85
|
ConfigMiddleware.new(self, found)
|
@@ -99,11 +101,11 @@ module Puma
|
|
99
101
|
def load_rackup
|
100
102
|
raise "Missing rackup file '#{rackup}'" unless File.exist?(rackup)
|
101
103
|
|
102
|
-
rack_app, rack_options = Rack::Builder.parse_file(rackup)
|
104
|
+
rack_app, rack_options = Puma::Rack::Builder.parse_file(rackup)
|
103
105
|
@options.merge!(rack_options)
|
104
106
|
|
105
107
|
config_ru_binds = rack_options.each_with_object([]) do |(k, v), b|
|
106
|
-
b << v if k.to_s
|
108
|
+
b << v if k.to_s.start_with?("bind")
|
107
109
|
end
|
108
110
|
@options[:binds] = config_ru_binds unless config_ru_binds.empty?
|
109
111
|
|
data/lib/puma/const.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'rack'
|
2
|
-
|
3
1
|
module Puma
|
4
2
|
class UnsupportedOption < RuntimeError
|
5
3
|
end
|
@@ -8,12 +6,85 @@ module Puma
|
|
8
6
|
# Every standard HTTP code mapped to the appropriate message. These are
|
9
7
|
# used so frequently that they are placed directly in Puma for easy
|
10
8
|
# access rather than Puma::Const itself.
|
11
|
-
|
9
|
+
|
10
|
+
# Every standard HTTP code mapped to the appropriate message.
|
11
|
+
# Generated with:
|
12
|
+
# curl -s https://www.iana.org/assignments/http-status-codes/http-status-codes-1.csv | \
|
13
|
+
# ruby -ne 'm = /^(\d{3}),(?!Unassigned|\(Unused\))([^,]+)/.match($_) and \
|
14
|
+
# puts "#{m[1]} => \x27#{m[2].strip}\x27,"'
|
15
|
+
HTTP_STATUS_CODES = {
|
16
|
+
100 => 'Continue',
|
17
|
+
101 => 'Switching Protocols',
|
18
|
+
102 => 'Processing',
|
19
|
+
200 => 'OK',
|
20
|
+
201 => 'Created',
|
21
|
+
202 => 'Accepted',
|
22
|
+
203 => 'Non-Authoritative Information',
|
23
|
+
204 => 'No Content',
|
24
|
+
205 => 'Reset Content',
|
25
|
+
206 => 'Partial Content',
|
26
|
+
207 => 'Multi-Status',
|
27
|
+
208 => 'Already Reported',
|
28
|
+
226 => 'IM Used',
|
29
|
+
300 => 'Multiple Choices',
|
30
|
+
301 => 'Moved Permanently',
|
31
|
+
302 => 'Found',
|
32
|
+
303 => 'See Other',
|
33
|
+
304 => 'Not Modified',
|
34
|
+
305 => 'Use Proxy',
|
35
|
+
307 => 'Temporary Redirect',
|
36
|
+
308 => 'Permanent Redirect',
|
37
|
+
400 => 'Bad Request',
|
38
|
+
401 => 'Unauthorized',
|
39
|
+
402 => 'Payment Required',
|
40
|
+
403 => 'Forbidden',
|
41
|
+
404 => 'Not Found',
|
42
|
+
405 => 'Method Not Allowed',
|
43
|
+
406 => 'Not Acceptable',
|
44
|
+
407 => 'Proxy Authentication Required',
|
45
|
+
408 => 'Request Timeout',
|
46
|
+
409 => 'Conflict',
|
47
|
+
410 => 'Gone',
|
48
|
+
411 => 'Length Required',
|
49
|
+
412 => 'Precondition Failed',
|
50
|
+
413 => 'Payload Too Large',
|
51
|
+
414 => 'URI Too Long',
|
52
|
+
415 => 'Unsupported Media Type',
|
53
|
+
416 => 'Range Not Satisfiable',
|
54
|
+
417 => 'Expectation Failed',
|
55
|
+
422 => 'Unprocessable Entity',
|
56
|
+
423 => 'Locked',
|
57
|
+
424 => 'Failed Dependency',
|
58
|
+
426 => 'Upgrade Required',
|
59
|
+
428 => 'Precondition Required',
|
60
|
+
429 => 'Too Many Requests',
|
61
|
+
431 => 'Request Header Fields Too Large',
|
62
|
+
500 => 'Internal Server Error',
|
63
|
+
501 => 'Not Implemented',
|
64
|
+
502 => 'Bad Gateway',
|
65
|
+
503 => 'Service Unavailable',
|
66
|
+
504 => 'Gateway Timeout',
|
67
|
+
505 => 'HTTP Version Not Supported',
|
68
|
+
506 => 'Variant Also Negotiates',
|
69
|
+
507 => 'Insufficient Storage',
|
70
|
+
508 => 'Loop Detected',
|
71
|
+
510 => 'Not Extended',
|
72
|
+
511 => 'Network Authentication Required'
|
73
|
+
}
|
74
|
+
|
75
|
+
SYMBOL_TO_STATUS_CODE = Hash[*HTTP_STATUS_CODES.map { |code, message|
|
76
|
+
[message.downcase.gsub(/\s|-|'/, '_').to_sym, code]
|
77
|
+
}.flatten]
|
12
78
|
|
13
79
|
# For some HTTP status codes the client only expects headers.
|
14
|
-
|
15
|
-
|
16
|
-
}
|
80
|
+
#
|
81
|
+
|
82
|
+
no_body = {}
|
83
|
+
((100..199).to_a << 204 << 205 << 304).each do |code|
|
84
|
+
no_body[code] = true
|
85
|
+
end
|
86
|
+
|
87
|
+
STATUS_WITH_NO_ENTITY_BODY = no_body
|
17
88
|
|
18
89
|
# Frequently used constants when constructing requests or responses. Many times
|
19
90
|
# the constant just refers to a string with the same contents. Using these constants
|
@@ -28,8 +99,8 @@ module Puma
|
|
28
99
|
# too taxing on performance.
|
29
100
|
module Const
|
30
101
|
|
31
|
-
PUMA_VERSION = VERSION = "2.
|
32
|
-
CODE_NAME = "
|
102
|
+
PUMA_VERSION = VERSION = "2.12.0".freeze
|
103
|
+
CODE_NAME = "Plutonian Photo Shoot".freeze
|
33
104
|
|
34
105
|
FAST_TRACK_KA_TIMEOUT = 0.2
|
35
106
|
|
@@ -111,6 +182,7 @@ module Puma
|
|
111
182
|
PORT_80 = "80".freeze
|
112
183
|
PORT_443 = "443".freeze
|
113
184
|
LOCALHOST = "localhost".freeze
|
185
|
+
LOCALHOST_IP = "127.0.0.1".freeze
|
114
186
|
|
115
187
|
SERVER_PROTOCOL = "SERVER_PROTOCOL".freeze
|
116
188
|
HTTP_11 = "HTTP/1.1".freeze
|
@@ -129,6 +201,7 @@ module Puma
|
|
129
201
|
RACK_AFTER_REPLY = "rack.after_reply".freeze
|
130
202
|
PUMA_SOCKET = "puma.socket".freeze
|
131
203
|
PUMA_CONFIG = "puma.config".freeze
|
204
|
+
PUMA_PEERCERT = "puma.peercert".freeze
|
132
205
|
|
133
206
|
HTTP = "http".freeze
|
134
207
|
HTTPS = "https".freeze
|
data/lib/puma/control_cli.rb
CHANGED
@@ -66,7 +66,15 @@ module Puma
|
|
66
66
|
command = argv.shift
|
67
67
|
@options[:command] = command if command
|
68
68
|
|
69
|
-
|
69
|
+
unless @options[:config_file] == '-'
|
70
|
+
if @options[:config_file].nil? and File.exist?('config/puma.rb')
|
71
|
+
@options[:config_file] = 'config/puma.rb'
|
72
|
+
end
|
73
|
+
|
74
|
+
if @options[:config_file]
|
75
|
+
Puma::Configuration.new(@options).load
|
76
|
+
end
|
77
|
+
end
|
70
78
|
|
71
79
|
# check present of command
|
72
80
|
unless @options[:command]
|
data/lib/puma/events.rb
CHANGED
@@ -96,6 +96,15 @@ module Puma
|
|
96
96
|
@stderr.puts "#{Time.now}: ENV: #{env.inspect}\n---\n"
|
97
97
|
end
|
98
98
|
|
99
|
+
# An SSL error has occured.
|
100
|
+
# +server+ is the Server object, +peeraddr+ peer address, +peercert+
|
101
|
+
# any peer certificate (if present), and +error+ an exception object.
|
102
|
+
#
|
103
|
+
def ssl_error(server, peeraddr, peercert, error)
|
104
|
+
subject = peercert ? peercert.subject : nil
|
105
|
+
@stderr.puts "#{Time.now}: SSL error, peer: #{peeraddr}, peer cert: #{subject}, #{error.inspect}"
|
106
|
+
end
|
107
|
+
|
99
108
|
# An unknown error has occured.
|
100
109
|
# +server+ is the Server object, +env+ the request, +error+ an exception
|
101
110
|
# object, and +kind+ some additional info.
|
data/lib/puma/minissl.rb
CHANGED
@@ -4,6 +4,7 @@ module Puma
|
|
4
4
|
def initialize(socket, engine)
|
5
5
|
@socket = socket
|
6
6
|
@engine = engine
|
7
|
+
@peercert = nil
|
7
8
|
end
|
8
9
|
|
9
10
|
def to_io
|
@@ -86,6 +87,21 @@ module Puma
|
|
86
87
|
def peeraddr
|
87
88
|
@socket.peeraddr
|
88
89
|
end
|
90
|
+
|
91
|
+
def peercert
|
92
|
+
return @peercert if @peercert
|
93
|
+
|
94
|
+
raw = @engine.peercert
|
95
|
+
return nil unless raw
|
96
|
+
|
97
|
+
@peercert = OpenSSL::X509::Certificate.new raw
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
if defined?(JRUBY_VERSION)
|
102
|
+
class SSLError < StandardError
|
103
|
+
# Define this for jruby even though it isn't used.
|
104
|
+
end
|
89
105
|
end
|
90
106
|
|
91
107
|
class Context
|
@@ -104,6 +120,7 @@ module Puma
|
|
104
120
|
# non-jruby Context properties
|
105
121
|
attr_reader :key
|
106
122
|
attr_reader :cert
|
123
|
+
attr_reader :ca
|
107
124
|
|
108
125
|
def key=(key)
|
109
126
|
raise ArgumentError, "No such key file '#{key}'" unless File.exist? key
|
@@ -114,11 +131,17 @@ module Puma
|
|
114
131
|
raise ArgumentError, "No such cert file '#{cert}'" unless File.exist? cert
|
115
132
|
@cert = cert
|
116
133
|
end
|
134
|
+
|
135
|
+
def ca=(ca)
|
136
|
+
raise ArgumentError, "No such ca file '#{ca}'" unless File.exist? ca
|
137
|
+
@ca = ca
|
138
|
+
end
|
117
139
|
end
|
118
140
|
end
|
119
141
|
|
120
142
|
VERIFY_NONE = 0
|
121
143
|
VERIFY_PEER = 1
|
144
|
+
VERIFY_FAIL_IF_NO_PEER_CERT = 2
|
122
145
|
|
123
146
|
class Server
|
124
147
|
def initialize(socket, ctx)
|