# 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