webrick 1.3.1 → 1.4.3
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/lib/webrick.rb +6 -6
- 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.rb +6 -5
- 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/httpproxy.rb +93 -48
- data/lib/webrick/httprequest.rb +192 -27
- data/lib/webrick/httpresponse.rb +182 -62
- data/lib/webrick/https.rb +90 -2
- data/lib/webrick/httpserver.rb +45 -15
- data/lib/webrick/httpservlet.rb +6 -5
- 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/httpstatus.rb +24 -14
- data/lib/webrick/httputils.rb +132 -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
- metadata +66 -72
- 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/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
|
data/lib/webrick/utils.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: false
|
1
2
|
#
|
2
3
|
# utils.rb -- Miscellaneous utilities
|
3
4
|
#
|
@@ -9,45 +10,34 @@
|
|
9
10
|
# $IPR: utils.rb,v 1.10 2003/02/16 22:22:54 gotoyuzo Exp $
|
10
11
|
|
11
12
|
require 'socket'
|
12
|
-
require '
|
13
|
-
|
14
|
-
require 'etc'
|
15
|
-
rescue LoadError
|
16
|
-
nil
|
17
|
-
end
|
13
|
+
require 'io/nonblock'
|
14
|
+
require 'etc'
|
18
15
|
|
19
16
|
module WEBrick
|
20
17
|
module Utils
|
21
18
|
##
|
22
19
|
# Sets IO operations on +io+ to be non-blocking
|
23
20
|
def set_non_blocking(io)
|
24
|
-
|
25
|
-
if defined?(Fcntl::F_GETFL)
|
26
|
-
flag |= io.fcntl(Fcntl::F_GETFL)
|
27
|
-
end
|
28
|
-
io.fcntl(Fcntl::F_SETFL, flag)
|
21
|
+
io.nonblock = true if io.respond_to?(:nonblock=)
|
29
22
|
end
|
30
23
|
module_function :set_non_blocking
|
31
24
|
|
32
25
|
##
|
33
26
|
# Sets the close on exec flag for +io+
|
34
27
|
def set_close_on_exec(io)
|
35
|
-
if
|
36
|
-
io.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
37
|
-
end
|
28
|
+
io.close_on_exec = true if io.respond_to?(:close_on_exec=)
|
38
29
|
end
|
39
30
|
module_function :set_close_on_exec
|
40
31
|
|
41
32
|
##
|
42
33
|
# Changes the process's uid and gid to the ones of +user+
|
43
34
|
def su(user)
|
44
|
-
if
|
45
|
-
pw = Etc.getpwnam(user)
|
35
|
+
if pw = Etc.getpwnam(user)
|
46
36
|
Process::initgroups(user, pw.gid)
|
47
37
|
Process::Sys::setgid(pw.gid)
|
48
38
|
Process::Sys::setuid(pw.uid)
|
49
39
|
else
|
50
|
-
warn("WEBrick::Utils::su doesn't work on this platform")
|
40
|
+
warn("WEBrick::Utils::su doesn't work on this platform", uplevel: 1)
|
51
41
|
end
|
52
42
|
end
|
53
43
|
module_function :su
|
@@ -68,30 +58,17 @@ module WEBrick
|
|
68
58
|
# Creates TCP server sockets bound to +address+:+port+ and returns them.
|
69
59
|
#
|
70
60
|
# It will create IPV4 and IPV6 sockets on all interfaces.
|
71
|
-
def create_listeners(address, port
|
61
|
+
def create_listeners(address, port)
|
72
62
|
unless port
|
73
63
|
raise ArgumentError, "must specify port"
|
74
64
|
end
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
sockets = []
|
82
|
-
res.each{|ai|
|
83
|
-
begin
|
84
|
-
logger.debug("TCPServer.new(#{ai[3]}, #{port})") if logger
|
85
|
-
sock = TCPServer.new(ai[3], port)
|
86
|
-
port = sock.addr[1] if port == 0
|
87
|
-
Utils::set_close_on_exec(sock)
|
88
|
-
sockets << sock
|
89
|
-
rescue => ex
|
90
|
-
logger.warn("TCPServer Error: #{ex}") if logger
|
91
|
-
last_error = ex
|
92
|
-
end
|
65
|
+
sockets = Socket.tcp_server_sockets(address, port)
|
66
|
+
sockets = sockets.map {|s|
|
67
|
+
s.autoclose = false
|
68
|
+
ts = TCPServer.for_fd(s.fileno)
|
69
|
+
s.close
|
70
|
+
ts
|
93
71
|
}
|
94
|
-
raise last_error if sockets.empty?
|
95
72
|
return sockets
|
96
73
|
end
|
97
74
|
module_function :create_listeners
|
@@ -114,7 +91,6 @@ module WEBrick
|
|
114
91
|
|
115
92
|
###########
|
116
93
|
|
117
|
-
require "thread"
|
118
94
|
require "timeout"
|
119
95
|
require "singleton"
|
120
96
|
|
@@ -149,7 +125,7 @@ module WEBrick
|
|
149
125
|
|
150
126
|
##
|
151
127
|
# Mutex used to synchronize access across threads
|
152
|
-
TimeoutMutex = Mutex.new # :nodoc:
|
128
|
+
TimeoutMutex = Thread::Mutex.new # :nodoc:
|
153
129
|
|
154
130
|
##
|
155
131
|
# Registers a new timeout handler
|
@@ -157,43 +133,82 @@ module WEBrick
|
|
157
133
|
# +time+:: Timeout in seconds
|
158
134
|
# +exception+:: Exception to raise when timeout elapsed
|
159
135
|
def TimeoutHandler.register(seconds, exception)
|
160
|
-
|
161
|
-
|
162
|
-
}
|
136
|
+
at = Process.clock_gettime(Process::CLOCK_MONOTONIC) + seconds
|
137
|
+
instance.register(Thread.current, at, exception)
|
163
138
|
end
|
164
139
|
|
165
140
|
##
|
166
141
|
# Cancels the timeout handler +id+
|
167
142
|
def TimeoutHandler.cancel(id)
|
143
|
+
instance.cancel(Thread.current, id)
|
144
|
+
end
|
145
|
+
|
146
|
+
def self.terminate
|
147
|
+
instance.terminate
|
148
|
+
end
|
149
|
+
|
150
|
+
##
|
151
|
+
# Creates a new TimeoutHandler. You should use ::register and ::cancel
|
152
|
+
# instead of creating the timeout handler directly.
|
153
|
+
def initialize
|
168
154
|
TimeoutMutex.synchronize{
|
169
|
-
|
155
|
+
@timeout_info = Hash.new
|
170
156
|
}
|
157
|
+
@queue = Thread::Queue.new
|
158
|
+
@watcher = nil
|
171
159
|
end
|
172
160
|
|
173
|
-
|
174
|
-
|
175
|
-
|
161
|
+
# :nodoc:
|
162
|
+
private \
|
163
|
+
def watch
|
164
|
+
to_interrupt = []
|
176
165
|
while true
|
177
|
-
now =
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
166
|
+
now = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
167
|
+
wakeup = nil
|
168
|
+
to_interrupt.clear
|
169
|
+
TimeoutMutex.synchronize{
|
170
|
+
@timeout_info.each {|thread, ary|
|
171
|
+
next unless ary
|
172
|
+
ary.each{|info|
|
173
|
+
time, exception = *info
|
174
|
+
if time < now
|
175
|
+
to_interrupt.push [thread, info.object_id, exception]
|
176
|
+
elsif !wakeup || time < wakeup
|
177
|
+
wakeup = time
|
178
|
+
end
|
179
|
+
}
|
182
180
|
}
|
183
181
|
}
|
184
|
-
|
182
|
+
to_interrupt.each {|arg| interrupt(*arg)}
|
183
|
+
if !wakeup
|
184
|
+
@queue.pop
|
185
|
+
elsif (wakeup -= now) > 0
|
186
|
+
begin
|
187
|
+
(th = Thread.start {@queue.pop}).join(wakeup)
|
188
|
+
ensure
|
189
|
+
th&.kill&.join
|
190
|
+
end
|
191
|
+
end
|
192
|
+
@queue.clear
|
185
193
|
end
|
186
|
-
|
187
|
-
|
194
|
+
end
|
195
|
+
|
196
|
+
# :nodoc:
|
197
|
+
private \
|
198
|
+
def watcher
|
199
|
+
(w = @watcher)&.alive? and return w # usual case
|
200
|
+
TimeoutMutex.synchronize{
|
201
|
+
(w = @watcher)&.alive? and next w # pathological check
|
202
|
+
@watcher = Thread.start(&method(:watch))
|
203
|
+
}
|
204
|
+
end
|
188
205
|
|
189
206
|
##
|
190
207
|
# Interrupts the timeout handler +id+ and raises +exception+
|
191
208
|
def interrupt(thread, id, exception)
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
end
|
196
|
-
}
|
209
|
+
if cancel(thread, id) && thread.alive?
|
210
|
+
thread.raise(exception, "execution timeout")
|
211
|
+
end
|
197
212
|
end
|
198
213
|
|
199
214
|
##
|
@@ -202,22 +217,36 @@ module WEBrick
|
|
202
217
|
# +time+:: Timeout in seconds
|
203
218
|
# +exception+:: Exception to raise when timeout elapsed
|
204
219
|
def register(thread, time, exception)
|
205
|
-
|
206
|
-
|
207
|
-
|
220
|
+
info = nil
|
221
|
+
TimeoutMutex.synchronize{
|
222
|
+
(@timeout_info[thread] ||= []) << (info = [time, exception])
|
223
|
+
}
|
224
|
+
@queue.push nil
|
225
|
+
watcher
|
226
|
+
return info.object_id
|
208
227
|
end
|
209
228
|
|
210
229
|
##
|
211
230
|
# Cancels the timeout handler +id+
|
212
231
|
def cancel(thread, id)
|
213
|
-
|
214
|
-
ary
|
215
|
-
|
216
|
-
|
232
|
+
TimeoutMutex.synchronize{
|
233
|
+
if ary = @timeout_info[thread]
|
234
|
+
ary.delete_if{|info| info.object_id == id }
|
235
|
+
if ary.empty?
|
236
|
+
@timeout_info.delete(thread)
|
237
|
+
end
|
238
|
+
return true
|
217
239
|
end
|
218
|
-
return
|
219
|
-
|
220
|
-
|
240
|
+
return false
|
241
|
+
}
|
242
|
+
end
|
243
|
+
|
244
|
+
##
|
245
|
+
def terminate
|
246
|
+
TimeoutMutex.synchronize{
|
247
|
+
@timeout_info.clear
|
248
|
+
@watcher&.kill&.join
|
249
|
+
}
|
221
250
|
end
|
222
251
|
end
|
223
252
|
|
data/lib/webrick/version.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: false
|
1
2
|
#--
|
2
3
|
# version.rb -- version and release date
|
3
4
|
#
|
@@ -9,5 +10,9 @@
|
|
9
10
|
# $IPR: version.rb,v 1.74 2003/07/22 19:20:43 gotoyuzo Exp $
|
10
11
|
|
11
12
|
module WEBrick
|
12
|
-
|
13
|
+
|
14
|
+
##
|
15
|
+
# The WEBrick version
|
16
|
+
|
17
|
+
VERSION = "1.4.3"
|
13
18
|
end
|