module WEBrick::Utils

Constants

RAND_CHARS

Characters used to generate random strings

Public Class Methods

create_listeners(address, port) click to toggle source

Creates TCP server sockets bound to address:port and returns them.

It will create IPV4 and IPV6 sockets on all interfaces.

# File lib/webrick/utils.rb, line 61
def create_listeners(address, port)
  unless port
    raise ArgumentError, "must specify port"
  end
  sockets = Socket.tcp_server_sockets(address, port)
  sockets = sockets.map {|s|
    s.autoclose = false
    ts = TCPServer.for_fd(s.fileno)
    s.close
    ts
  }
  return sockets
end
create_self_signed_cert(bits, cn, comment) click to toggle source

Creates a self-signed certificate with the given number of bits, the issuer cn and a comment to be stored in the certificate.

# File lib/webrick/ssl.rb, line 97
def create_self_signed_cert(bits, cn, comment)
  rsa = OpenSSL::PKey::RSA.new(bits){|p, n|
    case p
    when 0; $stderr.putc "."  # BN_generate_prime
    when 1; $stderr.putc "+"  # BN_generate_prime
    when 2; $stderr.putc "*"  # searching good prime,
                              # n = #of try,
                              # but also data from BN_generate_prime
    when 3; $stderr.putc "\n" # found good prime, n==0 - p, n==1 - q,
                              # but also data from BN_generate_prime
    else;   $stderr.putc "*"  # BN_generate_prime
    end
  }
  cert = OpenSSL::X509::Certificate.new
  cert.version = 2
  cert.serial = 1
  name = (cn.kind_of? String) ? OpenSSL::X509::Name.parse(cn)
                              : OpenSSL::X509::Name.new(cn)
  cert.subject = name
  cert.issuer = name
  cert.not_before = Time.now
  cert.not_after = Time.now + (365*24*60*60)
  cert.public_key = rsa.public_key

  ef = OpenSSL::X509::ExtensionFactory.new(nil,cert)
  ef.issuer_certificate = cert
  cert.extensions = [
    ef.create_extension("basicConstraints","CA:FALSE"),
    ef.create_extension("keyUsage", "keyEncipherment"),
    ef.create_extension("subjectKeyIdentifier", "hash"),
    ef.create_extension("extendedKeyUsage", "serverAuth"),
    ef.create_extension("nsComment", comment),
  ]
  aki = ef.create_extension("authorityKeyIdentifier",
                            "keyid:always,issuer:always")
  cert.add_extension(aki)
  cert.sign(rsa, OpenSSL::Digest::SHA256.new)

  return [ cert, rsa ]
end
getservername() click to toggle source

The server hostname

# File lib/webrick/utils.rb, line 47
def getservername
  host = Socket::gethostname
  begin
    Socket::gethostbyname(host)[0]
  rescue
    host
  end
end
random_string(len) click to toggle source

Generates a random string of length len

# File lib/webrick/utils.rb, line 84
def random_string(len)
  rand_max = RAND_CHARS.bytesize
  ret = ""
  len.times{ ret << RAND_CHARS[rand(rand_max)] }
  ret
end
set_close_on_exec(io) click to toggle source

Sets the close on exec flag for io

# File lib/webrick/utils.rb, line 27
def set_close_on_exec(io)
  io.close_on_exec = true if io.respond_to?(:close_on_exec=)
end
set_non_blocking(io) click to toggle source

Sets IO operations on io to be non-blocking

# File lib/webrick/utils.rb, line 20
def set_non_blocking(io)
  io.nonblock = true if io.respond_to?(:nonblock=)
end
su(user) click to toggle source

Changes the process's uid and gid to the ones of user

# File lib/webrick/utils.rb, line 34
def su(user)
  if pw = Etc.getpwnam(user)
    Process::initgroups(user, pw.gid)
    Process::Sys::setgid(pw.gid)
    Process::Sys::setuid(pw.uid)
  else
    warn("WEBrick::Utils::su doesn't work on this platform", uplevel: 1)
  end
end
timeout(seconds, exception=Timeout::Error) { || ... } click to toggle source

Executes the passed block and raises exception if execution takes more than seconds.

If seconds is zero or nil, simply executes the block

# File lib/webrick/utils.rb, line 258
def timeout(seconds, exception=Timeout::Error)
  return yield if seconds.nil? or seconds.zero?
  # raise ThreadError, "timeout within critical session" if Thread.critical
  id = TimeoutHandler.register(seconds, exception)
  begin
    yield(seconds)
  ensure
    TimeoutHandler.cancel(id)
  end
end

Private Instance Methods

create_listeners(address, port) click to toggle source

Creates TCP server sockets bound to address:port and returns them.

It will create IPV4 and IPV6 sockets on all interfaces.

# File lib/webrick/utils.rb, line 61
def create_listeners(address, port)
  unless port
    raise ArgumentError, "must specify port"
  end
  sockets = Socket.tcp_server_sockets(address, port)
  sockets = sockets.map {|s|
    s.autoclose = false
    ts = TCPServer.for_fd(s.fileno)
    s.close
    ts
  }
  return sockets
end
create_self_signed_cert(bits, cn, comment) click to toggle source

Creates a self-signed certificate with the given number of bits, the issuer cn and a comment to be stored in the certificate.

# File lib/webrick/ssl.rb, line 97
def create_self_signed_cert(bits, cn, comment)
  rsa = OpenSSL::PKey::RSA.new(bits){|p, n|
    case p
    when 0; $stderr.putc "."  # BN_generate_prime
    when 1; $stderr.putc "+"  # BN_generate_prime
    when 2; $stderr.putc "*"  # searching good prime,
                              # n = #of try,
                              # but also data from BN_generate_prime
    when 3; $stderr.putc "\n" # found good prime, n==0 - p, n==1 - q,
                              # but also data from BN_generate_prime
    else;   $stderr.putc "*"  # BN_generate_prime
    end
  }
  cert = OpenSSL::X509::Certificate.new
  cert.version = 2
  cert.serial = 1
  name = (cn.kind_of? String) ? OpenSSL::X509::Name.parse(cn)
                              : OpenSSL::X509::Name.new(cn)
  cert.subject = name
  cert.issuer = name
  cert.not_before = Time.now
  cert.not_after = Time.now + (365*24*60*60)
  cert.public_key = rsa.public_key

  ef = OpenSSL::X509::ExtensionFactory.new(nil,cert)
  ef.issuer_certificate = cert
  cert.extensions = [
    ef.create_extension("basicConstraints","CA:FALSE"),
    ef.create_extension("keyUsage", "keyEncipherment"),
    ef.create_extension("subjectKeyIdentifier", "hash"),
    ef.create_extension("extendedKeyUsage", "serverAuth"),
    ef.create_extension("nsComment", comment),
  ]
  aki = ef.create_extension("authorityKeyIdentifier",
                            "keyid:always,issuer:always")
  cert.add_extension(aki)
  cert.sign(rsa, OpenSSL::Digest::SHA256.new)

  return [ cert, rsa ]
end
getservername() click to toggle source

The server hostname

# File lib/webrick/utils.rb, line 47
def getservername
  host = Socket::gethostname
  begin
    Socket::gethostbyname(host)[0]
  rescue
    host
  end
end
random_string(len) click to toggle source

Generates a random string of length len

# File lib/webrick/utils.rb, line 84
def random_string(len)
  rand_max = RAND_CHARS.bytesize
  ret = ""
  len.times{ ret << RAND_CHARS[rand(rand_max)] }
  ret
end
set_close_on_exec(io) click to toggle source

Sets the close on exec flag for io

# File lib/webrick/utils.rb, line 27
def set_close_on_exec(io)
  io.close_on_exec = true if io.respond_to?(:close_on_exec=)
end
set_non_blocking(io) click to toggle source

Sets IO operations on io to be non-blocking

# File lib/webrick/utils.rb, line 20
def set_non_blocking(io)
  io.nonblock = true if io.respond_to?(:nonblock=)
end
su(user) click to toggle source

Changes the process's uid and gid to the ones of user

# File lib/webrick/utils.rb, line 34
def su(user)
  if pw = Etc.getpwnam(user)
    Process::initgroups(user, pw.gid)
    Process::Sys::setgid(pw.gid)
    Process::Sys::setuid(pw.uid)
  else
    warn("WEBrick::Utils::su doesn't work on this platform", uplevel: 1)
  end
end
timeout(seconds, exception=Timeout::Error) { || ... } click to toggle source

Executes the passed block and raises exception if execution takes more than seconds.

If seconds is zero or nil, simply executes the block

# File lib/webrick/utils.rb, line 258
def timeout(seconds, exception=Timeout::Error)
  return yield if seconds.nil? or seconds.zero?
  # raise ThreadError, "timeout within critical session" if Thread.critical
  id = TimeoutHandler.register(seconds, exception)
  begin
    yield(seconds)
  ensure
    TimeoutHandler.cancel(id)
  end
end