webrick 1.3.1 → 1.5.0
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.
- checksums.yaml +7 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +22 -0
- data/README.md +63 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/webrick/accesslog.rb +9 -1
- data/lib/webrick/cgi.rb +58 -5
- data/lib/webrick/compat.rb +2 -1
- data/lib/webrick/config.rb +47 -10
- data/lib/webrick/cookie.rb +69 -7
- data/lib/webrick/htmlutils.rb +4 -2
- data/lib/webrick/httpauth/authenticator.rb +13 -8
- data/lib/webrick/httpauth/basicauth.rb +16 -8
- data/lib/webrick/httpauth/digestauth.rb +35 -32
- data/lib/webrick/httpauth/htdigest.rb +12 -8
- data/lib/webrick/httpauth/htgroup.rb +10 -6
- data/lib/webrick/httpauth/htpasswd.rb +46 -9
- data/lib/webrick/httpauth/userdb.rb +1 -0
- data/lib/webrick/httpauth.rb +6 -5
- data/lib/webrick/httpproxy.rb +93 -48
- data/lib/webrick/httprequest.rb +192 -27
- data/lib/webrick/httpresponse.rb +221 -70
- data/lib/webrick/https.rb +90 -2
- data/lib/webrick/httpserver.rb +45 -15
- data/lib/webrick/httpservlet/abstract.rb +5 -6
- data/lib/webrick/httpservlet/cgi_runner.rb +3 -2
- data/lib/webrick/httpservlet/cgihandler.rb +22 -10
- data/lib/webrick/httpservlet/erbhandler.rb +4 -3
- data/lib/webrick/httpservlet/filehandler.rb +136 -65
- data/lib/webrick/httpservlet/prochandler.rb +15 -1
- data/lib/webrick/httpservlet.rb +6 -5
- data/lib/webrick/httpstatus.rb +24 -14
- data/lib/webrick/httputils.rb +133 -13
- data/lib/webrick/httpversion.rb +28 -1
- data/lib/webrick/log.rb +25 -5
- data/lib/webrick/server.rb +234 -74
- data/lib/webrick/ssl.rb +100 -12
- data/lib/webrick/utils.rb +98 -69
- data/lib/webrick/version.rb +6 -1
- data/lib/webrick.rb +7 -7
- data/webrick.gemspec +76 -0
- metadata +70 -69
- data/README.txt +0 -21
- data/sample/webrick/demo-app.rb +0 -66
- data/sample/webrick/demo-multipart.cgi +0 -12
- data/sample/webrick/demo-servlet.rb +0 -6
- data/sample/webrick/demo-urlencoded.cgi +0 -12
- data/sample/webrick/hello.cgi +0 -11
- data/sample/webrick/hello.rb +0 -8
- data/sample/webrick/httpd.rb +0 -23
- data/sample/webrick/httpproxy.rb +0 -25
- data/sample/webrick/httpsd.rb +0 -33
- data/test/openssl/utils.rb +0 -313
- data/test/ruby/envutil.rb +0 -208
- data/test/webrick/test_cgi.rb +0 -134
- data/test/webrick/test_cookie.rb +0 -131
- data/test/webrick/test_filehandler.rb +0 -285
- data/test/webrick/test_httpauth.rb +0 -167
- data/test/webrick/test_httpproxy.rb +0 -282
- data/test/webrick/test_httprequest.rb +0 -411
- data/test/webrick/test_httpresponse.rb +0 -49
- data/test/webrick/test_httpserver.rb +0 -305
- data/test/webrick/test_httputils.rb +0 -96
- data/test/webrick/test_httpversion.rb +0 -40
- data/test/webrick/test_server.rb +0 -67
- data/test/webrick/test_utils.rb +0 -64
- data/test/webrick/utils.rb +0 -58
- data/test/webrick/webrick.cgi +0 -36
- data/test/webrick/webrick_long_filename.cgi +0 -36
data/lib/webrick/server.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: false
|
1
2
|
#
|
2
3
|
# server.rb -- GenericServer Class
|
3
4
|
#
|
@@ -8,16 +9,25 @@
|
|
8
9
|
#
|
9
10
|
# $IPR: server.rb,v 1.62 2003/07/22 19:20:43 gotoyuzo Exp $
|
10
11
|
|
11
|
-
require 'thread'
|
12
12
|
require 'socket'
|
13
|
-
|
14
|
-
|
13
|
+
require_relative 'config'
|
14
|
+
require_relative 'log'
|
15
15
|
|
16
16
|
module WEBrick
|
17
17
|
|
18
|
+
##
|
19
|
+
# Server error exception
|
20
|
+
|
18
21
|
class ServerError < StandardError; end
|
19
22
|
|
23
|
+
##
|
24
|
+
# Base server class
|
25
|
+
|
20
26
|
class SimpleServer
|
27
|
+
|
28
|
+
##
|
29
|
+
# A SimpleServer only yields when you start it
|
30
|
+
|
21
31
|
def SimpleServer.start
|
22
32
|
yield
|
23
33
|
end
|
@@ -33,20 +43,47 @@ module WEBrick
|
|
33
43
|
# block, if given.
|
34
44
|
|
35
45
|
def Daemon.start
|
36
|
-
|
37
|
-
|
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")
|
46
|
+
Process.daemon
|
47
|
+
File.umask(0)
|
44
48
|
yield if block_given?
|
45
49
|
end
|
46
50
|
end
|
47
51
|
|
52
|
+
##
|
53
|
+
# Base TCP server class. You must subclass GenericServer and provide a #run
|
54
|
+
# method.
|
55
|
+
|
48
56
|
class GenericServer
|
49
|
-
|
57
|
+
|
58
|
+
##
|
59
|
+
# The server status. One of :Stop, :Running or :Shutdown
|
60
|
+
|
61
|
+
attr_reader :status
|
62
|
+
|
63
|
+
##
|
64
|
+
# The server configuration
|
65
|
+
|
66
|
+
attr_reader :config
|
67
|
+
|
68
|
+
##
|
69
|
+
# The server logger. This is independent from the HTTP access log.
|
70
|
+
|
71
|
+
attr_reader :logger
|
72
|
+
|
73
|
+
##
|
74
|
+
# Tokens control the number of outstanding clients. The
|
75
|
+
# <code>:MaxClients</code> configuration sets this.
|
76
|
+
|
77
|
+
attr_reader :tokens
|
78
|
+
|
79
|
+
##
|
80
|
+
# Sockets listening for connections.
|
81
|
+
|
82
|
+
attr_reader :listeners
|
83
|
+
|
84
|
+
##
|
85
|
+
# Creates a new generic server from +config+. The default configuration
|
86
|
+
# comes from +default+.
|
50
87
|
|
51
88
|
def initialize(config={}, default=Config::General)
|
52
89
|
@config = default.dup.update(config)
|
@@ -54,7 +91,7 @@ module WEBrick
|
|
54
91
|
@config[:Logger] ||= Log::new
|
55
92
|
@logger = @config[:Logger]
|
56
93
|
|
57
|
-
@tokens = SizedQueue.new(@config[:MaxClients])
|
94
|
+
@tokens = Thread::SizedQueue.new(@config[:MaxClients])
|
58
95
|
@config[:MaxClients].times{ @tokens.push(nil) }
|
59
96
|
|
60
97
|
webrickv = WEBrick::VERSION
|
@@ -63,9 +100,10 @@ module WEBrick
|
|
63
100
|
@logger.info("ruby #{rubyv}")
|
64
101
|
|
65
102
|
@listeners = []
|
103
|
+
@shutdown_pipe = nil
|
66
104
|
unless @config[:DoNotListen]
|
67
105
|
if @config[:Listen]
|
68
|
-
warn(":Listen option is deprecated; use GenericServer#listen")
|
106
|
+
warn(":Listen option is deprecated; use GenericServer#listen", uplevel: 1)
|
69
107
|
end
|
70
108
|
listen(@config[:BindAddress], @config[:Port])
|
71
109
|
if @config[:Port] == 0
|
@@ -74,108 +112,176 @@ module WEBrick
|
|
74
112
|
end
|
75
113
|
end
|
76
114
|
|
115
|
+
##
|
116
|
+
# Retrieves +key+ from the configuration
|
117
|
+
|
77
118
|
def [](key)
|
78
119
|
@config[key]
|
79
120
|
end
|
80
121
|
|
122
|
+
##
|
123
|
+
# Adds listeners from +address+ and +port+ to the server. See
|
124
|
+
# WEBrick::Utils::create_listeners for details.
|
125
|
+
|
81
126
|
def listen(address, port)
|
82
|
-
@listeners += Utils::create_listeners(address, port
|
127
|
+
@listeners += Utils::create_listeners(address, port)
|
83
128
|
end
|
84
129
|
|
130
|
+
##
|
131
|
+
# Starts the server and runs the +block+ for each connection. This method
|
132
|
+
# does not return until the server is stopped from a signal handler or
|
133
|
+
# another thread using #stop or #shutdown.
|
134
|
+
#
|
135
|
+
# If the block raises a subclass of StandardError the exception is logged
|
136
|
+
# and ignored. If an IOError or Errno::EBADF exception is raised the
|
137
|
+
# exception is ignored. If an Exception subclass is raised the exception
|
138
|
+
# is logged and re-raised which stops the server.
|
139
|
+
#
|
140
|
+
# To completely shut down a server call #shutdown from ensure:
|
141
|
+
#
|
142
|
+
# server = WEBrick::GenericServer.new
|
143
|
+
# # or WEBrick::HTTPServer.new
|
144
|
+
#
|
145
|
+
# begin
|
146
|
+
# server.start
|
147
|
+
# ensure
|
148
|
+
# server.shutdown
|
149
|
+
# end
|
150
|
+
|
85
151
|
def start(&block)
|
86
152
|
raise ServerError, "already started." if @status != :Stop
|
87
153
|
server_type = @config[:ServerType] || SimpleServer
|
88
154
|
|
155
|
+
setup_shutdown_pipe
|
156
|
+
|
89
157
|
server_type.start{
|
90
158
|
@logger.info \
|
91
159
|
"#{self.class}#start: pid=#{$$} port=#{@config[:Port]}"
|
160
|
+
@status = :Running
|
92
161
|
call_callback(:StartCallback)
|
93
162
|
|
163
|
+
shutdown_pipe = @shutdown_pipe
|
164
|
+
|
94
165
|
thgroup = ThreadGroup.new
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
svrs[
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
else
|
107
|
-
@tokens.push(nil)
|
166
|
+
begin
|
167
|
+
while @status == :Running
|
168
|
+
begin
|
169
|
+
sp = shutdown_pipe[0]
|
170
|
+
if svrs = IO.select([sp, *@listeners])
|
171
|
+
if svrs[0].include? sp
|
172
|
+
# swallow shutdown pipe
|
173
|
+
buf = String.new
|
174
|
+
nil while String ===
|
175
|
+
sp.read_nonblock([sp.nread, 8].max, buf, exception: false)
|
176
|
+
break
|
108
177
|
end
|
109
|
-
|
178
|
+
svrs[0].each{|svr|
|
179
|
+
@tokens.pop # blocks while no token is there.
|
180
|
+
if sock = accept_client(svr)
|
181
|
+
unless config[:DoNotReverseLookup].nil?
|
182
|
+
sock.do_not_reverse_lookup = !!config[:DoNotReverseLookup]
|
183
|
+
end
|
184
|
+
th = start_thread(sock, &block)
|
185
|
+
th[:WEBrickThread] = true
|
186
|
+
thgroup.add(th)
|
187
|
+
else
|
188
|
+
@tokens.push(nil)
|
189
|
+
end
|
190
|
+
}
|
191
|
+
end
|
192
|
+
rescue Errno::EBADF, Errno::ENOTSOCK, IOError => ex
|
193
|
+
# if the listening socket was closed in GenericServer#shutdown,
|
194
|
+
# IO::select raise it.
|
195
|
+
rescue StandardError => ex
|
196
|
+
msg = "#{ex.class}: #{ex.message}\n\t#{ex.backtrace[0]}"
|
197
|
+
@logger.error msg
|
198
|
+
rescue Exception => ex
|
199
|
+
@logger.fatal ex
|
200
|
+
raise
|
110
201
|
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
202
|
end
|
203
|
+
ensure
|
204
|
+
cleanup_shutdown_pipe(shutdown_pipe)
|
205
|
+
cleanup_listener
|
206
|
+
@status = :Shutdown
|
207
|
+
@logger.info "going to shutdown ..."
|
208
|
+
thgroup.list.each{|th| th.join if th[:WEBrickThread] }
|
209
|
+
call_callback(:StopCallback)
|
210
|
+
@logger.info "#{self.class}#start done."
|
211
|
+
@status = :Stop
|
118
212
|
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
213
|
}
|
126
214
|
end
|
127
215
|
|
216
|
+
##
|
217
|
+
# Stops the server from accepting new connections.
|
218
|
+
|
128
219
|
def stop
|
129
220
|
if @status == :Running
|
130
221
|
@status = :Shutdown
|
131
222
|
end
|
223
|
+
|
224
|
+
alarm_shutdown_pipe {|f| f.write_nonblock("\0")}
|
132
225
|
end
|
133
226
|
|
227
|
+
##
|
228
|
+
# Shuts down the server and all listening sockets. New listeners must be
|
229
|
+
# provided to restart the server.
|
230
|
+
|
134
231
|
def shutdown
|
135
232
|
stop
|
136
|
-
|
137
|
-
|
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
|
233
|
+
|
234
|
+
alarm_shutdown_pipe(&:close)
|
155
235
|
end
|
156
236
|
|
237
|
+
##
|
238
|
+
# You must subclass GenericServer and implement \#run which accepts a TCP
|
239
|
+
# client socket
|
240
|
+
|
157
241
|
def run(sock)
|
158
242
|
@logger.fatal "run() must be provided by user."
|
159
243
|
end
|
160
244
|
|
161
245
|
private
|
162
246
|
|
247
|
+
# :stopdoc:
|
248
|
+
|
249
|
+
##
|
250
|
+
# Accepts a TCP client socket from the TCP server socket +svr+ and returns
|
251
|
+
# the client socket.
|
252
|
+
|
163
253
|
def accept_client(svr)
|
164
|
-
sock =
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
254
|
+
case sock = svr.to_io.accept_nonblock(exception: false)
|
255
|
+
when :wait_readable
|
256
|
+
nil
|
257
|
+
else
|
258
|
+
if svr.respond_to?(:start_immediately)
|
259
|
+
sock = OpenSSL::SSL::SSLSocket.new(sock, ssl_context)
|
260
|
+
sock.sync_close = true
|
261
|
+
# we cannot do OpenSSL::SSL::SSLSocket#accept here because
|
262
|
+
# a slow client can prevent us from accepting connections
|
263
|
+
# from other clients
|
264
|
+
end
|
265
|
+
sock
|
175
266
|
end
|
176
|
-
|
267
|
+
rescue Errno::ECONNRESET, Errno::ECONNABORTED,
|
268
|
+
Errno::EPROTO, Errno::EINVAL
|
269
|
+
nil
|
270
|
+
rescue StandardError => ex
|
271
|
+
msg = "#{ex.class}: #{ex.message}\n\t#{ex.backtrace[0]}"
|
272
|
+
@logger.error msg
|
273
|
+
nil
|
177
274
|
end
|
178
275
|
|
276
|
+
##
|
277
|
+
# Starts a server thread for the client socket +sock+ that runs the given
|
278
|
+
# +block+.
|
279
|
+
#
|
280
|
+
# Sets the socket to the <code>:WEBrickSocket</code> thread local variable
|
281
|
+
# in the thread.
|
282
|
+
#
|
283
|
+
# If any errors occur in the block they are logged and handled.
|
284
|
+
|
179
285
|
def start_thread(sock, &block)
|
180
286
|
Thread.start{
|
181
287
|
begin
|
@@ -187,6 +293,16 @@ module WEBrick
|
|
187
293
|
@logger.debug "accept: <address unknown>"
|
188
294
|
raise
|
189
295
|
end
|
296
|
+
if sock.respond_to?(:sync_close=) && @config[:SSLStartImmediately]
|
297
|
+
WEBrick::Utils.timeout(@config[:RequestTimeout]) do
|
298
|
+
begin
|
299
|
+
sock.accept # OpenSSL::SSL::SSLSocket#accept
|
300
|
+
rescue Errno::ECONNRESET, Errno::ECONNABORTED,
|
301
|
+
Errno::EPROTO, Errno::EINVAL
|
302
|
+
Thread.exit
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|
190
306
|
call_callback(:AcceptCallback, sock)
|
191
307
|
block ? block.call(sock) : run(sock)
|
192
308
|
rescue Errno::ENOTCONN
|
@@ -209,10 +325,54 @@ module WEBrick
|
|
209
325
|
}
|
210
326
|
end
|
211
327
|
|
328
|
+
##
|
329
|
+
# Calls the callback +callback_name+ from the configuration with +args+
|
330
|
+
|
212
331
|
def call_callback(callback_name, *args)
|
213
|
-
|
214
|
-
|
332
|
+
@config[callback_name]&.call(*args)
|
333
|
+
end
|
334
|
+
|
335
|
+
def setup_shutdown_pipe
|
336
|
+
return @shutdown_pipe ||= IO.pipe
|
337
|
+
end
|
338
|
+
|
339
|
+
def cleanup_shutdown_pipe(shutdown_pipe)
|
340
|
+
@shutdown_pipe = nil
|
341
|
+
shutdown_pipe&.each(&:close)
|
342
|
+
end
|
343
|
+
|
344
|
+
def alarm_shutdown_pipe
|
345
|
+
_, pipe = @shutdown_pipe # another thread may modify @shutdown_pipe.
|
346
|
+
if pipe
|
347
|
+
if !pipe.closed?
|
348
|
+
begin
|
349
|
+
yield pipe
|
350
|
+
rescue IOError # closed by another thread.
|
351
|
+
end
|
352
|
+
end
|
215
353
|
end
|
216
354
|
end
|
355
|
+
|
356
|
+
def cleanup_listener
|
357
|
+
@listeners.each{|s|
|
358
|
+
if @logger.debug?
|
359
|
+
addr = s.addr
|
360
|
+
@logger.debug("close TCPSocket(#{addr[2]}, #{addr[1]})")
|
361
|
+
end
|
362
|
+
begin
|
363
|
+
s.shutdown
|
364
|
+
rescue Errno::ENOTCONN
|
365
|
+
# when `Errno::ENOTCONN: Socket is not connected' on some platforms,
|
366
|
+
# call #close instead of #shutdown.
|
367
|
+
# (ignore @config[:ShutdownSocketWithoutClose])
|
368
|
+
s.close
|
369
|
+
else
|
370
|
+
unless @config[:ShutdownSocketWithoutClose]
|
371
|
+
s.close
|
372
|
+
end
|
373
|
+
end
|
374
|
+
}
|
375
|
+
@listeners.clear
|
376
|
+
end
|
217
377
|
end # end of GenericServer
|
218
378
|
end
|
data/lib/webrick/ssl.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: false
|
1
2
|
#
|
2
3
|
# ssl.rb -- SSL/TLS enhancement for GenericServer
|
3
4
|
#
|
@@ -12,6 +13,57 @@ module WEBrick
|
|
12
13
|
module Config
|
13
14
|
svrsoft = General[:ServerSoftware]
|
14
15
|
osslv = ::OpenSSL::OPENSSL_VERSION.split[1]
|
16
|
+
|
17
|
+
##
|
18
|
+
# Default SSL server configuration.
|
19
|
+
#
|
20
|
+
# WEBrick can automatically create a self-signed certificate if
|
21
|
+
# <code>:SSLCertName</code> is set. For more information on the various
|
22
|
+
# SSL options see OpenSSL::SSL::SSLContext.
|
23
|
+
#
|
24
|
+
# :ServerSoftware ::
|
25
|
+
# The server software name used in the Server: header.
|
26
|
+
# :SSLEnable :: false,
|
27
|
+
# Enable SSL for this server. Defaults to false.
|
28
|
+
# :SSLCertificate ::
|
29
|
+
# The SSL certificate for the server.
|
30
|
+
# :SSLPrivateKey ::
|
31
|
+
# The SSL private key for the server certificate.
|
32
|
+
# :SSLClientCA :: nil,
|
33
|
+
# Array of certificates that will be sent to the client.
|
34
|
+
# :SSLExtraChainCert :: nil,
|
35
|
+
# Array of certificates that will be added to the certificate chain
|
36
|
+
# :SSLCACertificateFile :: nil,
|
37
|
+
# Path to a CA certificate file
|
38
|
+
# :SSLCACertificatePath :: nil,
|
39
|
+
# Path to a directory containing CA certificates
|
40
|
+
# :SSLCertificateStore :: nil,
|
41
|
+
# OpenSSL::X509::Store used for certificate validation of the client
|
42
|
+
# :SSLTmpDhCallback :: nil,
|
43
|
+
# Callback invoked when DH parameters are required.
|
44
|
+
# :SSLVerifyClient ::
|
45
|
+
# Sets whether the client is verified. This defaults to VERIFY_NONE
|
46
|
+
# which is typical for an HTTPS server.
|
47
|
+
# :SSLVerifyDepth ::
|
48
|
+
# Number of CA certificates to walk when verifying a certificate chain
|
49
|
+
# :SSLVerifyCallback ::
|
50
|
+
# Custom certificate verification callback
|
51
|
+
# :SSLServerNameCallback::
|
52
|
+
# Custom servername indication callback
|
53
|
+
# :SSLTimeout ::
|
54
|
+
# Maximum session lifetime
|
55
|
+
# :SSLOptions ::
|
56
|
+
# Various SSL options
|
57
|
+
# :SSLCiphers ::
|
58
|
+
# Ciphers to be used
|
59
|
+
# :SSLStartImmediately ::
|
60
|
+
# Immediately start SSL upon connection? Defaults to true
|
61
|
+
# :SSLCertName ::
|
62
|
+
# SSL certificate name. Must be set to enable automatic certificate
|
63
|
+
# creation.
|
64
|
+
# :SSLCertComment ::
|
65
|
+
# Comment used during automatic certificate creation.
|
66
|
+
|
15
67
|
SSL = {
|
16
68
|
:ServerSoftware => "#{svrsoft} OpenSSL/#{osslv}",
|
17
69
|
:SSLEnable => false,
|
@@ -22,11 +74,13 @@ module WEBrick
|
|
22
74
|
:SSLCACertificateFile => nil,
|
23
75
|
:SSLCACertificatePath => nil,
|
24
76
|
:SSLCertificateStore => nil,
|
77
|
+
:SSLTmpDhCallback => nil,
|
25
78
|
:SSLVerifyClient => ::OpenSSL::SSL::VERIFY_NONE,
|
26
79
|
:SSLVerifyDepth => nil,
|
27
80
|
:SSLVerifyCallback => nil, # custom verification
|
28
81
|
:SSLTimeout => nil,
|
29
82
|
:SSLOptions => nil,
|
83
|
+
:SSLCiphers => nil,
|
30
84
|
:SSLStartImmediately => true,
|
31
85
|
# Must specify if you use auto generated certificate.
|
32
86
|
:SSLCertName => nil,
|
@@ -36,6 +90,10 @@ module WEBrick
|
|
36
90
|
end
|
37
91
|
|
38
92
|
module Utils
|
93
|
+
##
|
94
|
+
# Creates a self-signed certificate with the given number of +bits+,
|
95
|
+
# the issuer +cn+ and a +comment+ to be stored in the certificate.
|
96
|
+
|
39
97
|
def create_self_signed_cert(bits, cn, comment)
|
40
98
|
rsa = OpenSSL::PKey::RSA.new(bits){|p, n|
|
41
99
|
case p
|
@@ -52,7 +110,8 @@ module WEBrick
|
|
52
110
|
cert = OpenSSL::X509::Certificate.new
|
53
111
|
cert.version = 2
|
54
112
|
cert.serial = 1
|
55
|
-
name = OpenSSL::X509::Name.
|
113
|
+
name = (cn.kind_of? String) ? OpenSSL::X509::Name.parse(cn)
|
114
|
+
: OpenSSL::X509::Name.new(cn)
|
56
115
|
cert.subject = name
|
57
116
|
cert.issuer = name
|
58
117
|
cert.not_before = Time.now
|
@@ -71,26 +130,40 @@ module WEBrick
|
|
71
130
|
aki = ef.create_extension("authorityKeyIdentifier",
|
72
131
|
"keyid:always,issuer:always")
|
73
132
|
cert.add_extension(aki)
|
74
|
-
cert.sign(rsa, OpenSSL::Digest::
|
133
|
+
cert.sign(rsa, OpenSSL::Digest::SHA256.new)
|
75
134
|
|
76
135
|
return [ cert, rsa ]
|
77
136
|
end
|
78
137
|
module_function :create_self_signed_cert
|
79
138
|
end
|
80
139
|
|
140
|
+
##
|
141
|
+
#--
|
142
|
+
# Updates WEBrick::GenericServer with SSL functionality
|
143
|
+
|
81
144
|
class GenericServer
|
82
|
-
|
83
|
-
|
145
|
+
|
146
|
+
##
|
147
|
+
# SSL context for the server when run in SSL mode
|
148
|
+
|
149
|
+
def ssl_context # :nodoc:
|
150
|
+
@ssl_context ||= begin
|
151
|
+
if @config[:SSLEnable]
|
152
|
+
ssl_context = setup_ssl_context(@config)
|
153
|
+
@logger.info("\n" + @config[:SSLCertificate].to_text)
|
154
|
+
ssl_context
|
155
|
+
end
|
156
|
+
end
|
84
157
|
end
|
85
158
|
|
86
159
|
undef listen
|
87
|
-
|
88
|
-
|
160
|
+
|
161
|
+
##
|
162
|
+
# Updates +listen+ to enable SSL when the SSL configuration is active.
|
163
|
+
|
164
|
+
def listen(address, port) # :nodoc:
|
165
|
+
listeners = Utils::create_listeners(address, port)
|
89
166
|
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
167
|
listeners.collect!{|svr|
|
95
168
|
ssvr = ::OpenSSL::SSL::SSLServer.new(svr, ssl_context)
|
96
169
|
ssvr.start_immediately = @config[:SSLStartImmediately]
|
@@ -98,13 +171,17 @@ module WEBrick
|
|
98
171
|
}
|
99
172
|
end
|
100
173
|
@listeners += listeners
|
174
|
+
setup_shutdown_pipe
|
101
175
|
end
|
102
176
|
|
103
|
-
|
177
|
+
##
|
178
|
+
# Sets up an SSL context for +config+
|
179
|
+
|
180
|
+
def setup_ssl_context(config) # :nodoc:
|
104
181
|
unless config[:SSLCertificate]
|
105
182
|
cn = config[:SSLCertName]
|
106
183
|
comment = config[:SSLCertComment]
|
107
|
-
cert, key = Utils::create_self_signed_cert(
|
184
|
+
cert, key = Utils::create_self_signed_cert(2048, cn, comment)
|
108
185
|
config[:SSLCertificate] = cert
|
109
186
|
config[:SSLPrivateKey] = key
|
110
187
|
end
|
@@ -116,12 +193,23 @@ module WEBrick
|
|
116
193
|
ctx.ca_file = config[:SSLCACertificateFile]
|
117
194
|
ctx.ca_path = config[:SSLCACertificatePath]
|
118
195
|
ctx.cert_store = config[:SSLCertificateStore]
|
196
|
+
ctx.tmp_dh_callback = config[:SSLTmpDhCallback]
|
119
197
|
ctx.verify_mode = config[:SSLVerifyClient]
|
120
198
|
ctx.verify_depth = config[:SSLVerifyDepth]
|
121
199
|
ctx.verify_callback = config[:SSLVerifyCallback]
|
200
|
+
ctx.servername_cb = config[:SSLServerNameCallback] || proc { |args| ssl_servername_callback(*args) }
|
122
201
|
ctx.timeout = config[:SSLTimeout]
|
123
202
|
ctx.options = config[:SSLOptions]
|
203
|
+
ctx.ciphers = config[:SSLCiphers]
|
124
204
|
ctx
|
125
205
|
end
|
206
|
+
|
207
|
+
##
|
208
|
+
# ServerNameIndication callback
|
209
|
+
|
210
|
+
def ssl_servername_callback(sslsocket, hostname = nil)
|
211
|
+
# default
|
212
|
+
end
|
213
|
+
|
126
214
|
end
|
127
215
|
end
|