index : static-web-server.git

ascending towards madness

use hyper_native_tls::NativeTlsServer;
use iron::{Chain, Iron, Listening};

use crate::staticfile_middleware::HttpToHttpsRedirect;
use crate::staticfiles::*;
use crate::{config::Options, logger, signals};

/// Struct for holding a reference to a running iron server instance
#[derive(Debug)]
struct RunningServer {
    listening: Listening,
    server_type: String,
}

/// Run HTTP/HTTPS web server
pub fn run(opts: Options) {
    logger::init(&opts.log_level);

    let addr = &format!("{}{}{}", opts.host, ":", opts.port);

    // Configure & launch the HTTP server
    let files = StaticFiles::new(StaticFilesOptions {
        root_dir: opts.root,
        assets_dir: opts.assets,
        page_50x_path: opts.page50x,
        page_404_path: opts.page404,
        cors_allow_origins: opts.cors_allow_origins.unwrap_or_default(),
        directory_listing: opts.directory_listing.unwrap_or_default(),
    });

    let mut running_servers = Vec::new();
    if opts.tls.unwrap_or_default() {
        // Launch static HTTPS server
        let ssl = NativeTlsServer::new(
            opts.tls_pkcs12.unwrap_or_default(),
            &opts.tls_pkcs12_passwd.unwrap_or_default(),
        )
        .unwrap();

        match Iron::new(files.handle()).https(addr, ssl) {
            Ok(listening) => running_servers.push(RunningServer {
                listening,
                server_type: "HTTPS".to_string(),
            }),
            Err(err) => {
                error!("Error binding to address {} for https: {}", addr, err);
                std::process::exit(1)
            }
        }

        // Launch redirect HTTP server (if requested)
        if let Some(port_redirect) = opts.tls_redirect_from {
            let addr_redirect = &format!("{}{}{}", opts.host, ":", port_redirect);
            let host_redirect = match opts.tls_redirect_host.as_ref() {
                Some(host) => host,
                None => &opts.host,
            };
            let handler =
                Chain::new(HttpToHttpsRedirect::new(&host_redirect, opts.port).permanent());
            match Iron::new(handler).http(addr_redirect) {
                Ok(listening) => running_servers.push(RunningServer {
                    listening,
                    server_type: "Redirect HTTP".to_string(),
                }),
                Err(err) => {
                    error!(
                        "Error binding to address {} for http redirection: {}",
                        addr, err
                    );
                    std::process::exit(1)
                }
            }
        }
    } else {
        // Launch static HTTP server
        match Iron::new(files.handle()).http(addr) {
            Ok(listening) => running_servers.push(RunningServer {
                listening,
                server_type: "HTTP".to_string(),
            }),
            Err(err) => {
                error!("Error binding to address {} for http: {}", addr, err);
                std::process::exit(1)
            }
        }
    }

    on_server_running(&opts.name.unwrap_or_default(), &running_servers);
}

fn on_server_running(server_name: &str, running_servers: &[RunningServer]) {
    // Notify when server is running
    running_servers.iter().for_each(|server| {
        let mut servername = String::new();
        if !server_name.is_empty() {
            servername = format!(" ({})", servername);
        }

        logger::log_server(&format!(
            "{} Server{} is listening on {}",
            server.server_type, servername, server.listening.socket
        ))
    });

    signals::wait_for_ctrl_c()
}