webrick 1.3.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of webrick might be problematic. Click here for more details.
- data/README.txt +21 -0
- data/lib/webrick.rb +227 -0
- data/lib/webrick/accesslog.rb +151 -0
- data/lib/webrick/cgi.rb +260 -0
- data/lib/webrick/compat.rb +35 -0
- data/lib/webrick/config.rb +121 -0
- data/lib/webrick/cookie.rb +110 -0
- data/lib/webrick/htmlutils.rb +28 -0
- data/lib/webrick/httpauth.rb +95 -0
- data/lib/webrick/httpauth/authenticator.rb +112 -0
- data/lib/webrick/httpauth/basicauth.rb +108 -0
- data/lib/webrick/httpauth/digestauth.rb +392 -0
- data/lib/webrick/httpauth/htdigest.rb +128 -0
- data/lib/webrick/httpauth/htgroup.rb +93 -0
- data/lib/webrick/httpauth/htpasswd.rb +121 -0
- data/lib/webrick/httpauth/userdb.rb +52 -0
- data/lib/webrick/httpproxy.rb +305 -0
- data/lib/webrick/httprequest.rb +461 -0
- data/lib/webrick/httpresponse.rb +399 -0
- data/lib/webrick/https.rb +64 -0
- data/lib/webrick/httpserver.rb +264 -0
- data/lib/webrick/httpservlet.rb +22 -0
- data/lib/webrick/httpservlet/abstract.rb +153 -0
- data/lib/webrick/httpservlet/cgi_runner.rb +46 -0
- data/lib/webrick/httpservlet/cgihandler.rb +108 -0
- data/lib/webrick/httpservlet/erbhandler.rb +87 -0
- data/lib/webrick/httpservlet/filehandler.rb +470 -0
- data/lib/webrick/httpservlet/prochandler.rb +33 -0
- data/lib/webrick/httpstatus.rb +184 -0
- data/lib/webrick/httputils.rb +394 -0
- data/lib/webrick/httpversion.rb +49 -0
- data/lib/webrick/log.rb +136 -0
- data/lib/webrick/server.rb +218 -0
- data/lib/webrick/ssl.rb +127 -0
- data/lib/webrick/utils.rb +241 -0
- data/lib/webrick/version.rb +13 -0
- data/sample/webrick/demo-app.rb +66 -0
- data/sample/webrick/demo-multipart.cgi +12 -0
- data/sample/webrick/demo-servlet.rb +6 -0
- data/sample/webrick/demo-urlencoded.cgi +12 -0
- data/sample/webrick/hello.cgi +11 -0
- data/sample/webrick/hello.rb +8 -0
- data/sample/webrick/httpd.rb +23 -0
- data/sample/webrick/httpproxy.rb +25 -0
- data/sample/webrick/httpsd.rb +33 -0
- data/test/openssl/utils.rb +313 -0
- data/test/ruby/envutil.rb +208 -0
- data/test/webrick/test_cgi.rb +134 -0
- data/test/webrick/test_cookie.rb +131 -0
- data/test/webrick/test_filehandler.rb +285 -0
- data/test/webrick/test_httpauth.rb +167 -0
- data/test/webrick/test_httpproxy.rb +282 -0
- data/test/webrick/test_httprequest.rb +411 -0
- data/test/webrick/test_httpresponse.rb +49 -0
- data/test/webrick/test_httpserver.rb +305 -0
- data/test/webrick/test_httputils.rb +96 -0
- data/test/webrick/test_httpversion.rb +40 -0
- data/test/webrick/test_server.rb +67 -0
- data/test/webrick/test_utils.rb +64 -0
- data/test/webrick/utils.rb +58 -0
- data/test/webrick/webrick.cgi +36 -0
- data/test/webrick/webrick_long_filename.cgi +36 -0
- metadata +106 -0
@@ -0,0 +1,49 @@
|
|
1
|
+
#--
|
2
|
+
# HTTPVersion.rb -- presentation of HTTP version
|
3
|
+
#
|
4
|
+
# Author: IPR -- Internet Programming with Ruby -- writers
|
5
|
+
# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
|
6
|
+
# reserved.
|
7
|
+
#
|
8
|
+
# $IPR: httpversion.rb,v 1.5 2002/09/21 12:23:37 gotoyuzo Exp $
|
9
|
+
|
10
|
+
module WEBrick
|
11
|
+
class HTTPVersion
|
12
|
+
include Comparable
|
13
|
+
|
14
|
+
attr_accessor :major, :minor
|
15
|
+
|
16
|
+
def self.convert(version)
|
17
|
+
version.is_a?(self) ? version : new(version)
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize(version)
|
21
|
+
case version
|
22
|
+
when HTTPVersion
|
23
|
+
@major, @minor = version.major, version.minor
|
24
|
+
when String
|
25
|
+
if /^(\d+)\.(\d+)$/ =~ version
|
26
|
+
@major, @minor = $1.to_i, $2.to_i
|
27
|
+
end
|
28
|
+
end
|
29
|
+
if @major.nil? || @minor.nil?
|
30
|
+
raise ArgumentError,
|
31
|
+
format("cannot convert %s into %s", version.class, self.class)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def <=>(other)
|
36
|
+
unless other.is_a?(self.class)
|
37
|
+
other = self.class.new(other)
|
38
|
+
end
|
39
|
+
if (ret = @major <=> other.major) == 0
|
40
|
+
return @minor <=> other.minor
|
41
|
+
end
|
42
|
+
return ret
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_s
|
46
|
+
format("%d.%d", @major, @minor)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/webrick/log.rb
ADDED
@@ -0,0 +1,136 @@
|
|
1
|
+
#--
|
2
|
+
# log.rb -- Log Class
|
3
|
+
#
|
4
|
+
# Author: IPR -- Internet Programming with Ruby -- writers
|
5
|
+
# Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
|
6
|
+
# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
|
7
|
+
# reserved.
|
8
|
+
#
|
9
|
+
# $IPR: log.rb,v 1.26 2002/10/06 17:06:10 gotoyuzo Exp $
|
10
|
+
|
11
|
+
module WEBrick
|
12
|
+
|
13
|
+
##
|
14
|
+
# A generic logging class
|
15
|
+
|
16
|
+
class BasicLog
|
17
|
+
# log-level constants
|
18
|
+
FATAL, ERROR, WARN, INFO, DEBUG = 1, 2, 3, 4, 5
|
19
|
+
|
20
|
+
# log-level, messages above this level will be logged
|
21
|
+
attr_accessor :level
|
22
|
+
|
23
|
+
##
|
24
|
+
# Initializes a new logger for +log_file+ that outputs messages at +level+
|
25
|
+
# or higher. +log_file+ can be a filename, an IO-like object that
|
26
|
+
# responds to #<< or nil which outputs to $stderr.
|
27
|
+
#
|
28
|
+
# If no level is given INFO is chosen by default
|
29
|
+
|
30
|
+
def initialize(log_file=nil, level=nil)
|
31
|
+
@level = level || INFO
|
32
|
+
case log_file
|
33
|
+
when String
|
34
|
+
@log = open(log_file, "a+")
|
35
|
+
@log.sync = true
|
36
|
+
@opened = true
|
37
|
+
when NilClass
|
38
|
+
@log = $stderr
|
39
|
+
else
|
40
|
+
@log = log_file # requires "<<". (see BasicLog#log)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
##
|
45
|
+
# Closes the logger (also closes the log device associated to the logger)
|
46
|
+
def close
|
47
|
+
@log.close if @opened
|
48
|
+
@log = nil
|
49
|
+
end
|
50
|
+
|
51
|
+
##
|
52
|
+
# Logs +data+ at +level+ if the given level is above the current log
|
53
|
+
# level.
|
54
|
+
|
55
|
+
def log(level, data)
|
56
|
+
if @log && level <= @level
|
57
|
+
data += "\n" if /\n\Z/ !~ data
|
58
|
+
@log << data
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
##
|
63
|
+
# Synonym for log(INFO, obj.to_s)
|
64
|
+
def <<(obj)
|
65
|
+
log(INFO, obj.to_s)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Shortcut for logging a FATAL message
|
69
|
+
def fatal(msg) log(FATAL, "FATAL " << format(msg)); end
|
70
|
+
# Shortcut for logging an ERROR message
|
71
|
+
def error(msg) log(ERROR, "ERROR " << format(msg)); end
|
72
|
+
# Shortcut for logging a WARN message
|
73
|
+
def warn(msg) log(WARN, "WARN " << format(msg)); end
|
74
|
+
# Shortcut for logging an INFO message
|
75
|
+
def info(msg) log(INFO, "INFO " << format(msg)); end
|
76
|
+
# Shortcut for logging a DEBUG message
|
77
|
+
def debug(msg) log(DEBUG, "DEBUG " << format(msg)); end
|
78
|
+
|
79
|
+
# Will the logger output FATAL messages?
|
80
|
+
def fatal?; @level >= FATAL; end
|
81
|
+
# Will the logger output ERROR messages?
|
82
|
+
def error?; @level >= ERROR; end
|
83
|
+
# Will the logger output WARN messages?
|
84
|
+
def warn?; @level >= WARN; end
|
85
|
+
# Will the logger output INFO messages?
|
86
|
+
def info?; @level >= INFO; end
|
87
|
+
# Will the logger output DEBUG messages?
|
88
|
+
def debug?; @level >= DEBUG; end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
##
|
93
|
+
# Formats +arg+ for the logger
|
94
|
+
#
|
95
|
+
# * If +arg+ is an Exception, it will format the error message and
|
96
|
+
# the back trace.
|
97
|
+
# * If +arg+ responds to #to_str, it will return it.
|
98
|
+
# * Otherwise it will return +arg+.inspect.
|
99
|
+
def format(arg)
|
100
|
+
if arg.is_a?(Exception)
|
101
|
+
"#{arg.class}: #{arg.message}\n\t" <<
|
102
|
+
arg.backtrace.join("\n\t") << "\n"
|
103
|
+
elsif arg.respond_to?(:to_str)
|
104
|
+
arg.to_str
|
105
|
+
else
|
106
|
+
arg.inspect
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
##
|
112
|
+
# A logging class that prepends a timestamp to each message.
|
113
|
+
|
114
|
+
class Log < BasicLog
|
115
|
+
# Format of the timestamp which is applied to each logged line. The
|
116
|
+
# default is <tt>"[%Y-%m-%d %H:%M:%S]"</tt>
|
117
|
+
attr_accessor :time_format
|
118
|
+
|
119
|
+
##
|
120
|
+
# Same as BasicLog#initialize
|
121
|
+
#
|
122
|
+
# You can set the timestamp format through #time_format
|
123
|
+
def initialize(log_file=nil, level=nil)
|
124
|
+
super(log_file, level)
|
125
|
+
@time_format = "[%Y-%m-%d %H:%M:%S]"
|
126
|
+
end
|
127
|
+
|
128
|
+
##
|
129
|
+
# Same as BasicLog#log
|
130
|
+
def log(level, data)
|
131
|
+
tmp = Time.now.strftime(@time_format)
|
132
|
+
tmp << " " << data
|
133
|
+
super(level, tmp)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,218 @@
|
|
1
|
+
#
|
2
|
+
# server.rb -- GenericServer Class
|
3
|
+
#
|
4
|
+
# Author: IPR -- Internet Programming with Ruby -- writers
|
5
|
+
# Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
|
6
|
+
# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
|
7
|
+
# reserved.
|
8
|
+
#
|
9
|
+
# $IPR: server.rb,v 1.62 2003/07/22 19:20:43 gotoyuzo Exp $
|
10
|
+
|
11
|
+
require 'thread'
|
12
|
+
require 'socket'
|
13
|
+
require 'webrick/config'
|
14
|
+
require 'webrick/log'
|
15
|
+
|
16
|
+
module WEBrick
|
17
|
+
|
18
|
+
class ServerError < StandardError; end
|
19
|
+
|
20
|
+
class SimpleServer
|
21
|
+
def SimpleServer.start
|
22
|
+
yield
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
##
|
27
|
+
# A generic module for daemonizing a process
|
28
|
+
|
29
|
+
class Daemon
|
30
|
+
|
31
|
+
##
|
32
|
+
# Performs the standard operations for daemonizing a process. Runs a
|
33
|
+
# block, if given.
|
34
|
+
|
35
|
+
def Daemon.start
|
36
|
+
exit!(0) if fork
|
37
|
+
Process::setsid
|
38
|
+
exit!(0) if fork
|
39
|
+
Dir::chdir("/")
|
40
|
+
File::umask(0)
|
41
|
+
STDIN.reopen("/dev/null")
|
42
|
+
STDOUT.reopen("/dev/null", "w")
|
43
|
+
STDERR.reopen("/dev/null", "w")
|
44
|
+
yield if block_given?
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class GenericServer
|
49
|
+
attr_reader :status, :config, :logger, :tokens, :listeners
|
50
|
+
|
51
|
+
def initialize(config={}, default=Config::General)
|
52
|
+
@config = default.dup.update(config)
|
53
|
+
@status = :Stop
|
54
|
+
@config[:Logger] ||= Log::new
|
55
|
+
@logger = @config[:Logger]
|
56
|
+
|
57
|
+
@tokens = SizedQueue.new(@config[:MaxClients])
|
58
|
+
@config[:MaxClients].times{ @tokens.push(nil) }
|
59
|
+
|
60
|
+
webrickv = WEBrick::VERSION
|
61
|
+
rubyv = "#{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]"
|
62
|
+
@logger.info("WEBrick #{webrickv}")
|
63
|
+
@logger.info("ruby #{rubyv}")
|
64
|
+
|
65
|
+
@listeners = []
|
66
|
+
unless @config[:DoNotListen]
|
67
|
+
if @config[:Listen]
|
68
|
+
warn(":Listen option is deprecated; use GenericServer#listen")
|
69
|
+
end
|
70
|
+
listen(@config[:BindAddress], @config[:Port])
|
71
|
+
if @config[:Port] == 0
|
72
|
+
@config[:Port] = @listeners[0].addr[1]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def [](key)
|
78
|
+
@config[key]
|
79
|
+
end
|
80
|
+
|
81
|
+
def listen(address, port)
|
82
|
+
@listeners += Utils::create_listeners(address, port, @logger)
|
83
|
+
end
|
84
|
+
|
85
|
+
def start(&block)
|
86
|
+
raise ServerError, "already started." if @status != :Stop
|
87
|
+
server_type = @config[:ServerType] || SimpleServer
|
88
|
+
|
89
|
+
server_type.start{
|
90
|
+
@logger.info \
|
91
|
+
"#{self.class}#start: pid=#{$$} port=#{@config[:Port]}"
|
92
|
+
call_callback(:StartCallback)
|
93
|
+
|
94
|
+
thgroup = ThreadGroup.new
|
95
|
+
@status = :Running
|
96
|
+
while @status == :Running
|
97
|
+
begin
|
98
|
+
if svrs = IO.select(@listeners, nil, nil, 2.0)
|
99
|
+
svrs[0].each{|svr|
|
100
|
+
@tokens.pop # blocks while no token is there.
|
101
|
+
if sock = accept_client(svr)
|
102
|
+
sock.do_not_reverse_lookup = config[:DoNotReverseLookup]
|
103
|
+
th = start_thread(sock, &block)
|
104
|
+
th[:WEBrickThread] = true
|
105
|
+
thgroup.add(th)
|
106
|
+
else
|
107
|
+
@tokens.push(nil)
|
108
|
+
end
|
109
|
+
}
|
110
|
+
end
|
111
|
+
rescue Errno::EBADF, IOError => ex
|
112
|
+
# if the listening socket was closed in GenericServer#shutdown,
|
113
|
+
# IO::select raise it.
|
114
|
+
rescue Exception => ex
|
115
|
+
msg = "#{ex.class}: #{ex.message}\n\t#{ex.backtrace[0]}"
|
116
|
+
@logger.error msg
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
@logger.info "going to shutdown ..."
|
121
|
+
thgroup.list.each{|th| th.join if th[:WEBrickThread] }
|
122
|
+
call_callback(:StopCallback)
|
123
|
+
@logger.info "#{self.class}#start done."
|
124
|
+
@status = :Stop
|
125
|
+
}
|
126
|
+
end
|
127
|
+
|
128
|
+
def stop
|
129
|
+
if @status == :Running
|
130
|
+
@status = :Shutdown
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def shutdown
|
135
|
+
stop
|
136
|
+
@listeners.each{|s|
|
137
|
+
if @logger.debug?
|
138
|
+
addr = s.addr
|
139
|
+
@logger.debug("close TCPSocket(#{addr[2]}, #{addr[1]})")
|
140
|
+
end
|
141
|
+
begin
|
142
|
+
s.shutdown
|
143
|
+
rescue Errno::ENOTCONN
|
144
|
+
# when `Errno::ENOTCONN: Socket is not connected' on some platforms,
|
145
|
+
# call #close instead of #shutdown.
|
146
|
+
# (ignore @config[:ShutdownSocketWithoutClose])
|
147
|
+
s.close
|
148
|
+
else
|
149
|
+
unless @config[:ShutdownSocketWithoutClose]
|
150
|
+
s.close
|
151
|
+
end
|
152
|
+
end
|
153
|
+
}
|
154
|
+
@listeners.clear
|
155
|
+
end
|
156
|
+
|
157
|
+
def run(sock)
|
158
|
+
@logger.fatal "run() must be provided by user."
|
159
|
+
end
|
160
|
+
|
161
|
+
private
|
162
|
+
|
163
|
+
def accept_client(svr)
|
164
|
+
sock = nil
|
165
|
+
begin
|
166
|
+
sock = svr.accept
|
167
|
+
sock.sync = true
|
168
|
+
Utils::set_non_blocking(sock)
|
169
|
+
Utils::set_close_on_exec(sock)
|
170
|
+
rescue Errno::ECONNRESET, Errno::ECONNABORTED,
|
171
|
+
Errno::EPROTO, Errno::EINVAL => ex
|
172
|
+
rescue Exception => ex
|
173
|
+
msg = "#{ex.class}: #{ex.message}\n\t#{ex.backtrace[0]}"
|
174
|
+
@logger.error msg
|
175
|
+
end
|
176
|
+
return sock
|
177
|
+
end
|
178
|
+
|
179
|
+
def start_thread(sock, &block)
|
180
|
+
Thread.start{
|
181
|
+
begin
|
182
|
+
Thread.current[:WEBrickSocket] = sock
|
183
|
+
begin
|
184
|
+
addr = sock.peeraddr
|
185
|
+
@logger.debug "accept: #{addr[3]}:#{addr[1]}"
|
186
|
+
rescue SocketError
|
187
|
+
@logger.debug "accept: <address unknown>"
|
188
|
+
raise
|
189
|
+
end
|
190
|
+
call_callback(:AcceptCallback, sock)
|
191
|
+
block ? block.call(sock) : run(sock)
|
192
|
+
rescue Errno::ENOTCONN
|
193
|
+
@logger.debug "Errno::ENOTCONN raised"
|
194
|
+
rescue ServerError => ex
|
195
|
+
msg = "#{ex.class}: #{ex.message}\n\t#{ex.backtrace[0]}"
|
196
|
+
@logger.error msg
|
197
|
+
rescue Exception => ex
|
198
|
+
@logger.error ex
|
199
|
+
ensure
|
200
|
+
@tokens.push(nil)
|
201
|
+
Thread.current[:WEBrickSocket] = nil
|
202
|
+
if addr
|
203
|
+
@logger.debug "close: #{addr[3]}:#{addr[1]}"
|
204
|
+
else
|
205
|
+
@logger.debug "close: <address unknown>"
|
206
|
+
end
|
207
|
+
sock.close
|
208
|
+
end
|
209
|
+
}
|
210
|
+
end
|
211
|
+
|
212
|
+
def call_callback(callback_name, *args)
|
213
|
+
if cb = @config[callback_name]
|
214
|
+
cb.call(*args)
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end # end of GenericServer
|
218
|
+
end
|
data/lib/webrick/ssl.rb
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
#
|
2
|
+
# ssl.rb -- SSL/TLS enhancement for GenericServer
|
3
|
+
#
|
4
|
+
# Copyright (c) 2003 GOTOU Yuuzou All rights reserved.
|
5
|
+
#
|
6
|
+
# $Id$
|
7
|
+
|
8
|
+
require 'webrick'
|
9
|
+
require 'openssl'
|
10
|
+
|
11
|
+
module WEBrick
|
12
|
+
module Config
|
13
|
+
svrsoft = General[:ServerSoftware]
|
14
|
+
osslv = ::OpenSSL::OPENSSL_VERSION.split[1]
|
15
|
+
SSL = {
|
16
|
+
:ServerSoftware => "#{svrsoft} OpenSSL/#{osslv}",
|
17
|
+
:SSLEnable => false,
|
18
|
+
:SSLCertificate => nil,
|
19
|
+
:SSLPrivateKey => nil,
|
20
|
+
:SSLClientCA => nil,
|
21
|
+
:SSLExtraChainCert => nil,
|
22
|
+
:SSLCACertificateFile => nil,
|
23
|
+
:SSLCACertificatePath => nil,
|
24
|
+
:SSLCertificateStore => nil,
|
25
|
+
:SSLVerifyClient => ::OpenSSL::SSL::VERIFY_NONE,
|
26
|
+
:SSLVerifyDepth => nil,
|
27
|
+
:SSLVerifyCallback => nil, # custom verification
|
28
|
+
:SSLTimeout => nil,
|
29
|
+
:SSLOptions => nil,
|
30
|
+
:SSLStartImmediately => true,
|
31
|
+
# Must specify if you use auto generated certificate.
|
32
|
+
:SSLCertName => nil,
|
33
|
+
:SSLCertComment => "Generated by Ruby/OpenSSL"
|
34
|
+
}
|
35
|
+
General.update(SSL)
|
36
|
+
end
|
37
|
+
|
38
|
+
module Utils
|
39
|
+
def create_self_signed_cert(bits, cn, comment)
|
40
|
+
rsa = OpenSSL::PKey::RSA.new(bits){|p, n|
|
41
|
+
case p
|
42
|
+
when 0; $stderr.putc "." # BN_generate_prime
|
43
|
+
when 1; $stderr.putc "+" # BN_generate_prime
|
44
|
+
when 2; $stderr.putc "*" # searching good prime,
|
45
|
+
# n = #of try,
|
46
|
+
# but also data from BN_generate_prime
|
47
|
+
when 3; $stderr.putc "\n" # found good prime, n==0 - p, n==1 - q,
|
48
|
+
# but also data from BN_generate_prime
|
49
|
+
else; $stderr.putc "*" # BN_generate_prime
|
50
|
+
end
|
51
|
+
}
|
52
|
+
cert = OpenSSL::X509::Certificate.new
|
53
|
+
cert.version = 2
|
54
|
+
cert.serial = 1
|
55
|
+
name = OpenSSL::X509::Name.new(cn)
|
56
|
+
cert.subject = name
|
57
|
+
cert.issuer = name
|
58
|
+
cert.not_before = Time.now
|
59
|
+
cert.not_after = Time.now + (365*24*60*60)
|
60
|
+
cert.public_key = rsa.public_key
|
61
|
+
|
62
|
+
ef = OpenSSL::X509::ExtensionFactory.new(nil,cert)
|
63
|
+
ef.issuer_certificate = cert
|
64
|
+
cert.extensions = [
|
65
|
+
ef.create_extension("basicConstraints","CA:FALSE"),
|
66
|
+
ef.create_extension("keyUsage", "keyEncipherment"),
|
67
|
+
ef.create_extension("subjectKeyIdentifier", "hash"),
|
68
|
+
ef.create_extension("extendedKeyUsage", "serverAuth"),
|
69
|
+
ef.create_extension("nsComment", comment),
|
70
|
+
]
|
71
|
+
aki = ef.create_extension("authorityKeyIdentifier",
|
72
|
+
"keyid:always,issuer:always")
|
73
|
+
cert.add_extension(aki)
|
74
|
+
cert.sign(rsa, OpenSSL::Digest::SHA1.new)
|
75
|
+
|
76
|
+
return [ cert, rsa ]
|
77
|
+
end
|
78
|
+
module_function :create_self_signed_cert
|
79
|
+
end
|
80
|
+
|
81
|
+
class GenericServer
|
82
|
+
def ssl_context
|
83
|
+
@ssl_context ||= nil
|
84
|
+
end
|
85
|
+
|
86
|
+
undef listen
|
87
|
+
def listen(address, port)
|
88
|
+
listeners = Utils::create_listeners(address, port, @logger)
|
89
|
+
if @config[:SSLEnable]
|
90
|
+
unless ssl_context
|
91
|
+
@ssl_context = setup_ssl_context(@config)
|
92
|
+
@logger.info("\n" + @config[:SSLCertificate].to_text)
|
93
|
+
end
|
94
|
+
listeners.collect!{|svr|
|
95
|
+
ssvr = ::OpenSSL::SSL::SSLServer.new(svr, ssl_context)
|
96
|
+
ssvr.start_immediately = @config[:SSLStartImmediately]
|
97
|
+
ssvr
|
98
|
+
}
|
99
|
+
end
|
100
|
+
@listeners += listeners
|
101
|
+
end
|
102
|
+
|
103
|
+
def setup_ssl_context(config)
|
104
|
+
unless config[:SSLCertificate]
|
105
|
+
cn = config[:SSLCertName]
|
106
|
+
comment = config[:SSLCertComment]
|
107
|
+
cert, key = Utils::create_self_signed_cert(1024, cn, comment)
|
108
|
+
config[:SSLCertificate] = cert
|
109
|
+
config[:SSLPrivateKey] = key
|
110
|
+
end
|
111
|
+
ctx = OpenSSL::SSL::SSLContext.new
|
112
|
+
ctx.key = config[:SSLPrivateKey]
|
113
|
+
ctx.cert = config[:SSLCertificate]
|
114
|
+
ctx.client_ca = config[:SSLClientCA]
|
115
|
+
ctx.extra_chain_cert = config[:SSLExtraChainCert]
|
116
|
+
ctx.ca_file = config[:SSLCACertificateFile]
|
117
|
+
ctx.ca_path = config[:SSLCACertificatePath]
|
118
|
+
ctx.cert_store = config[:SSLCertificateStore]
|
119
|
+
ctx.verify_mode = config[:SSLVerifyClient]
|
120
|
+
ctx.verify_depth = config[:SSLVerifyDepth]
|
121
|
+
ctx.verify_callback = config[:SSLVerifyCallback]
|
122
|
+
ctx.timeout = config[:SSLTimeout]
|
123
|
+
ctx.options = config[:SSLOptions]
|
124
|
+
ctx
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|