class Bridgetown::Commands::Serve

Constants

DIRECTORY_INDEX

Attributes

loaded_config[RW]

Public Class Methods

banner() click to toggle source

Public Instance Methods

serve() click to toggle source
# File lib/bridgetown-core/commands/serve.rb, line 54
def serve
  @mutex = Mutex.new
  @run_cond = ConditionVariable.new
  @running = false

  no_watch = options["watch"] == false

  options = Thor::CoreExt::HashWithIndifferentAccess.new(self.options)

  options["serving"] = true
  options["watch"] = true unless no_watch

  # TODO: this prints the configuration file log message out-of-order
  self.class.loaded_config = configuration_with_overrides(options)
  if Bridgetown.environment == "development"
    self.class.loaded_config["url"] = default_url(self.class.loaded_config)
  end

  invoke(Build, [], options)
  start_server
end

Protected Instance Methods

boot_or_detach(server, opts) click to toggle source

Keep in our area with a thread or detach the server as requested by the user. This method determines what we do based on what you ask us to do.

# File lib/bridgetown-core/commands/serve.rb, line 171
def boot_or_detach(server, opts)
  if opts["detach"]
    pid = Process.fork do
      server.start
    end

    Process.detach(pid)
    Bridgetown.logger.info "Server detached with pid '#{pid}'.", \
                           "Run `pkill -f bridgetown' or `kill -9 #{pid}'" \
                           " to stop the server."
  else
    t = Thread.new { server.start }
    trap("INT") { server.shutdown }
    t.join
  end
end
create_error_page() click to toggle source
# File lib/bridgetown-core/commands/serve.rb, line 92
def create_error_page
  @header["Content-Type"] = "text/html; charset=UTF-8"
  @body = IO.read(File.join(@config[:DocumentRoot], "404.html"))
end
default_url(config) click to toggle source
# File lib/bridgetown-core/commands/serve.rb, line 133
def default_url(config)
  format_url(
    config["ssl_cert"] && config["ssl_key"],
    config["host"] == "127.0.0.1" ? "localhost" : config["host"],
    config["port"]
  )
end
enable_logging(opts) click to toggle source

Make the stack verbose if the user requests it.

# File lib/bridgetown-core/commands/serve.rb, line 189
def enable_logging(opts)
  opts[:AccessLog] = []
  level = WEBrick::Log.const_get(opts[:BridgetownOptions]["verbose"] ? :DEBUG : :WARN)
  opts[:Logger] = WEBrick::Log.new($stdout, level)
end
enable_ssl(opts) click to toggle source

Add SSL to the stack if the user triggers –enable-ssl and they provide both types of certificates commonly needed. Raise if they forget to add one of the certificates.

# File lib/bridgetown-core/commands/serve.rb, line 198
def enable_ssl(opts)
  cert, key, src =
    opts[:BridgetownOptions].values_at("ssl_cert", "ssl_key", "source")

  return if cert.nil? && key.nil?
  raise "Missing --ssl_cert or --ssl_key. Both are required." unless cert && key

  require "openssl"
  require "webrick/https"

  opts[:SSLCertificate] = OpenSSL::X509::Certificate.new(read_file(src, cert))
  begin
    opts[:SSLPrivateKey] = OpenSSL::PKey::RSA.new(read_file(src, key))
  rescue StandardError
    if defined?(OpenSSL::PKey::EC)
      opts[:SSLPrivateKey] = OpenSSL::PKey::EC.new(read_file(src, key))
    else
      raise
    end
  end
  opts[:SSLEnable] = true
end
file_handler_opts() click to toggle source

Recreate NondisclosureName under utf-8 circumstance

# File lib/bridgetown-core/commands/serve.rb, line 150
def file_handler_opts
  WEBrick::Config::FileHandler.merge(
    FancyIndexing: true,
    NondisclosureName: [
      ".ht*", "~*",
    ]
  )
end
format_url(ssl_enabled, address, port, baseurl = nil) click to toggle source
# File lib/bridgetown-core/commands/serve.rb, line 141
def format_url(ssl_enabled, address, port, baseurl = nil)
  format("%<prefix>s://%<address>s:%<port>i%<baseurl>s",
         prefix: ssl_enabled ? "https" : "http",
         address: address,
         port: port,
         baseurl: baseurl ? "#{baseurl}/" : "")
end
mime_types() click to toggle source
# File lib/bridgetown-core/commands/serve.rb, line 244
def mime_types
  file = File.expand_path("../mime.types", __dir__)
  WEBrick::HTTPUtils.load_mime_types(file)
end
read_file(source_dir, file_path) click to toggle source
# File lib/bridgetown-core/commands/serve.rb, line 249
def read_file(source_dir, file_path)
  File.read(Bridgetown.sanitized_path(source_dir, file_path))
end
server_address(server, options = {}) click to toggle source
# File lib/bridgetown-core/commands/serve.rb, line 159
def server_address(server, options = {})
  format_url(
    server.config[:SSLEnable],
    server.config[:BindAddress],
    server.config[:Port],
    options["baseurl"]
  )
end
setup(destination) click to toggle source
# File lib/bridgetown-core/commands/serve.rb, line 86
def setup(destination)
  require_relative "serve/servlet"

  FileUtils.mkdir_p(destination)
  if File.exist?(File.join(destination, "404.html"))
    WEBrick::HTTPResponse.class_eval do
      def create_error_page
        @header["Content-Type"] = "text/html; charset=UTF-8"
        @body = IO.read(File.join(@config[:DocumentRoot], "404.html"))
      end
    end
  end
end
shutdown() click to toggle source
# File lib/bridgetown-core/commands/serve.rb, line 129
def shutdown
  @server.shutdown if running?
end
start_callback(detached) click to toggle source
# File lib/bridgetown-core/commands/serve.rb, line 221
def start_callback(detached)
  unless detached
    proc do
      @mutex.synchronize do
        @running = true
        Bridgetown.logger.info("Server running…", "press ctrl-c to stop.")
        @run_cond.broadcast
      end
    end
  end
end
start_server() click to toggle source
# File lib/bridgetown-core/commands/serve.rb, line 78
def start_server
  config = self.class.loaded_config
  destination = config["destination"]
  setup(destination)

  start_up_webrick(config, destination)
end
start_up_webrick(opts, destination) click to toggle source
# File lib/bridgetown-core/commands/serve.rb, line 120
def start_up_webrick(opts, destination)
  @server = WEBrick::HTTPServer.new(webrick_opts(opts)).tap { |o| o.unmount("") }
  @server.mount(opts["base_path"].to_s, Servlet, destination, file_handler_opts)

  Bridgetown.logger.info "Server address:", server_address(@server, opts)
  launch_browser @server, opts if opts["open_url"]
  boot_or_detach @server, opts
end
stop_callback(detached) click to toggle source
# File lib/bridgetown-core/commands/serve.rb, line 233
def stop_callback(detached)
  unless detached
    proc do
      @mutex.synchronize do
        @running = false
        @run_cond.broadcast
      end
    end
  end
end
webrick_opts(opts) click to toggle source
# File lib/bridgetown-core/commands/serve.rb, line 100
def webrick_opts(opts)
  opts = {
    BridgetownOptions: opts,
    DoNotReverseLookup: true,
    MimeTypes: mime_types,
    DocumentRoot: opts["destination"],
    StartCallback: start_callback(opts["detach"]),
    StopCallback: stop_callback(opts["detach"]),
    BindAddress: opts["host"],
    Port: opts["port"],
    DirectoryIndex: DIRECTORY_INDEX,
  }

  opts[:DirectoryIndex] = [] if opts[:BridgetownOptions]["show_dir_listing"]

  enable_ssl(opts)
  enable_logging(opts)
  opts
end