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.

Files changed (64) hide show
  1. checksums.yaml +7 -0
  2. data/lib/webrick.rb +6 -6
  3. data/lib/webrick/accesslog.rb +9 -1
  4. data/lib/webrick/cgi.rb +58 -5
  5. data/lib/webrick/compat.rb +2 -1
  6. data/lib/webrick/config.rb +47 -10
  7. data/lib/webrick/cookie.rb +69 -7
  8. data/lib/webrick/htmlutils.rb +4 -2
  9. data/lib/webrick/httpauth.rb +6 -5
  10. data/lib/webrick/httpauth/authenticator.rb +13 -8
  11. data/lib/webrick/httpauth/basicauth.rb +16 -8
  12. data/lib/webrick/httpauth/digestauth.rb +35 -32
  13. data/lib/webrick/httpauth/htdigest.rb +12 -8
  14. data/lib/webrick/httpauth/htgroup.rb +10 -6
  15. data/lib/webrick/httpauth/htpasswd.rb +46 -9
  16. data/lib/webrick/httpauth/userdb.rb +1 -0
  17. data/lib/webrick/httpproxy.rb +93 -48
  18. data/lib/webrick/httprequest.rb +192 -27
  19. data/lib/webrick/httpresponse.rb +182 -62
  20. data/lib/webrick/https.rb +90 -2
  21. data/lib/webrick/httpserver.rb +45 -15
  22. data/lib/webrick/httpservlet.rb +6 -5
  23. data/lib/webrick/httpservlet/abstract.rb +5 -6
  24. data/lib/webrick/httpservlet/cgi_runner.rb +3 -2
  25. data/lib/webrick/httpservlet/cgihandler.rb +22 -10
  26. data/lib/webrick/httpservlet/erbhandler.rb +4 -3
  27. data/lib/webrick/httpservlet/filehandler.rb +136 -65
  28. data/lib/webrick/httpservlet/prochandler.rb +15 -1
  29. data/lib/webrick/httpstatus.rb +24 -14
  30. data/lib/webrick/httputils.rb +132 -13
  31. data/lib/webrick/httpversion.rb +28 -1
  32. data/lib/webrick/log.rb +25 -5
  33. data/lib/webrick/server.rb +234 -74
  34. data/lib/webrick/ssl.rb +100 -12
  35. data/lib/webrick/utils.rb +98 -69
  36. data/lib/webrick/version.rb +6 -1
  37. metadata +66 -72
  38. data/README.txt +0 -21
  39. data/sample/webrick/demo-app.rb +0 -66
  40. data/sample/webrick/demo-multipart.cgi +0 -12
  41. data/sample/webrick/demo-servlet.rb +0 -6
  42. data/sample/webrick/demo-urlencoded.cgi +0 -12
  43. data/sample/webrick/hello.cgi +0 -11
  44. data/sample/webrick/hello.rb +0 -8
  45. data/sample/webrick/httpd.rb +0 -23
  46. data/sample/webrick/httpproxy.rb +0 -25
  47. data/sample/webrick/httpsd.rb +0 -33
  48. data/test/openssl/utils.rb +0 -313
  49. data/test/ruby/envutil.rb +0 -208
  50. data/test/webrick/test_cgi.rb +0 -134
  51. data/test/webrick/test_cookie.rb +0 -131
  52. data/test/webrick/test_filehandler.rb +0 -285
  53. data/test/webrick/test_httpauth.rb +0 -167
  54. data/test/webrick/test_httpproxy.rb +0 -282
  55. data/test/webrick/test_httprequest.rb +0 -411
  56. data/test/webrick/test_httpresponse.rb +0 -49
  57. data/test/webrick/test_httpserver.rb +0 -305
  58. data/test/webrick/test_httputils.rb +0 -96
  59. data/test/webrick/test_httpversion.rb +0 -40
  60. data/test/webrick/test_server.rb +0 -67
  61. data/test/webrick/test_utils.rb +0 -64
  62. data/test/webrick/utils.rb +0 -58
  63. data/test/webrick/webrick.cgi +0 -36
  64. data/test/webrick/webrick_long_filename.cgi +0 -36
@@ -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.new(cn)
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::SHA1.new)
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
- def ssl_context
83
- @ssl_context ||= nil
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
- def listen(address, port)
88
- listeners = Utils::create_listeners(address, port, @logger)
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
- def setup_ssl_context(config)
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(1024, cn, comment)
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
@@ -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 'fcntl'
13
- begin
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
- flag = File::NONBLOCK
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 defined?(Fcntl::FD_CLOEXEC)
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 defined?(Etc)
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, logger=nil)
61
+ def create_listeners(address, port)
72
62
  unless port
73
63
  raise ArgumentError, "must specify port"
74
64
  end
75
- res = Socket::getaddrinfo(address, port,
76
- Socket::AF_UNSPEC, # address family
77
- Socket::SOCK_STREAM, # socket type
78
- 0, # protocol
79
- Socket::AI_PASSIVE) # flag
80
- last_error = nil
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
- TimeoutMutex.synchronize{
161
- instance.register(Thread.current, Time.now + seconds, exception)
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
- instance.cancel(Thread.current, id)
155
+ @timeout_info = Hash.new
170
156
  }
157
+ @queue = Thread::Queue.new
158
+ @watcher = nil
171
159
  end
172
160
 
173
- def initialize
174
- @timeout_info = Hash.new
175
- Thread.start{
161
+ # :nodoc:
162
+ private \
163
+ def watch
164
+ to_interrupt = []
176
165
  while true
177
- now = Time.now
178
- @timeout_info.each{|thread, ary|
179
- ary.dup.each{|info|
180
- time, exception = *info
181
- interrupt(thread, info.object_id, exception) if time < now
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
- sleep 0.5
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
- end
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
- TimeoutMutex.synchronize{
193
- if cancel(thread, id) && thread.alive?
194
- thread.raise(exception, "execution timeout")
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
- @timeout_info[thread] ||= Array.new
206
- @timeout_info[thread] << [time, exception]
207
- return @timeout_info[thread].last.object_id
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
- if ary = @timeout_info[thread]
214
- ary.delete_if{|info| info.object_id == id }
215
- if ary.empty?
216
- @timeout_info.delete(thread)
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 true
219
- end
220
- return false
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
 
@@ -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
- VERSION = "1.3.1"
13
+
14
+ ##
15
+ # The WEBrick version
16
+
17
+ VERSION = "1.4.3"
13
18
  end