index : static-web-server.git

ascending towards madness

author Jose Quintana <joseluisquintana20@gmail.com> 2021-01-04 1:01:15.0 +00:00:00
committer GitHub <noreply@github.com> 2021-01-04 1:01:15.0 +00:00:00
commit
c4df0d3fdfd0726d9b400d1e6569c848897c10b0 [patch]
tree
382a57fb76a011f9edd78cd80c907037f302bd88
parent
15353672dc89c68fd72f6aa9cd6b8b9e9433e2a5
parent
63a05faebf5bd584a555e78bf69cefd67e8b253b
download
c4df0d3fdfd0726d9b400d1e6569c848897c10b0.tar.gz

Merge pull request #26 from HenningHolmDE/redirect_http_server

feat: http to https redirection support

Diff

 README.md     | 10 ++++++++++
 src/config.rs |  6 ++++++
 src/main.rs   | 55 ++++++++++++++++++++++++++++++++++++++++++++++---------
 3 files changed, 62 insertions(+), 9 deletions(-)

diff --git a/README.md b/README.md
index 2091523..bb1056b 100644
--- a/README.md
+++ b/README.md
@@ -20,6 +20,7 @@
- First-class [Docker]https://docs.docker.com/get-started/overview/ support. [Scratch]https://hub.docker.com/_/scratch and latest [Alpine Linux]https://hub.docker.com/_/alpine Docker images available.
- Server configurable via environment variables or CLI arguments.
- MacOs binary support (`x86_64-apple-darwin`) thanks to [Rust Linux / Darwin Builder]https://github.com/joseluisq/rust-linux-darwin-builder.
- Additional HTTP redirect server for redirecting HTTP traffic to HTTPS site.

## Releases

@@ -47,6 +48,8 @@ Server can be configured either via environment variables or their equivalent co
| `SERVER_TLS` | Enables TLS/SSL support. Make sure also to adjust current server port. | Default `false` |
| `SERVER_TLS_PKCS12` | A cryptographic identity [PKCS #12]https://docs.rs/native-tls/0.2.3/native_tls/struct.Identity.html#method.from_pkcs12 bundle file path containing a [X509 certificate]https://en.wikipedia.org/wiki/X.509 along with its corresponding private key and chain of certificates to a trusted root. | Default empty |
| `SERVER_TLS_PKCS12_PASSWD` | A specified password to decrypt the private key. | Default empty |
| `SERVER_TLS_REDIRECT_FROM` | Host port for redirecting HTTP requests to HTTPS. This option enables the HTTP redirect feature | Default empty (disabled) |
| `SERVER_TLS_REDIRECT_HOST` | Host name of HTTPS site for redirecting HTTP requests to. | Default host address |
| `SERVER_CORS_ALLOW_ORIGINS` | Specify a CORS list of allowed origin hosts separated by comas with no whitespaces. Host ports or protocols aren't being checked. Use an asterisk (*) to allow any host. See [Iron CORS crate]https://docs.rs/iron-cors/0.8.0/iron_cors/#mode-1-whitelist. | Default empty (which means CORS is disabled) |

### Command-line arguments
@@ -92,6 +95,13 @@ OPTIONS:
            corresponding private key and chain of certificates to a trusted root [env: SERVER_TLS_PKCS12=]  [default: ]
        --tls-pkcs12-passwd <tls-pkcs12-passwd>
            A specified password to decrypt the private key [env: SERVER_TLS_PKCS12_PASSWD=]  [default: ]

        --tls-redirect-from <tls-redirect-from>
            Host port for redirecting HTTP requests to HTTPS. This option enables the HTTP redirect feature [env:
            SERVER_TLS_REDIRECT_FROM=]
        --tls-redirect-host <tls-redirect-host>
            Host name of HTTPS site for redirecting HTTP requests to. Defaults to host address [env:
            SERVER_TLS_REDIRECT_HOST=]
```

## TLS/SSL
diff --git a/src/config.rs b/src/config.rs
index 4b7448d..a3ce7b6 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -41,6 +41,12 @@ pub struct Options {
    #[structopt(long, default_value = "", env = "SERVER_TLS_PKCS12_PASSWD")]
    /// A specified password to decrypt the private key.
    pub tls_pkcs12_passwd: String,
    #[structopt(long, env = "SERVER_TLS_REDIRECT_FROM")]
    /// Host port for redirecting HTTP requests to HTTPS. This option enables the HTTP redirect feature.
    pub tls_redirect_from: Option<u16>,
    #[structopt(long, env = "SERVER_TLS_REDIRECT_HOST")]
    /// Host name of HTTPS site for redirecting HTTP requests to. Defaults to host address.
    pub tls_redirect_host: Option<String>,
    #[structopt(long, default_value = "error", env = "SERVER_LOG_LEVEL")]
    /// Specify a logging level in lower case.
    pub log_level: String,
diff --git a/src/main.rs b/src/main.rs
index fcd2e8a..50cfd90 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -7,7 +7,8 @@ extern crate log;

use crate::config::Options;
use hyper_native_tls::NativeTlsServer;
use iron::prelude::*;
use iron::{prelude::*, Listening};
use iron_staticfile_middleware::HttpToHttpsRedirect;
use staticfiles::*;
use structopt::StructOpt;

@@ -19,12 +20,21 @@ mod logger;
mod signal_manager;
mod staticfiles;

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

fn on_server_running(server_name: &str, running_servers: &Vec<RunningServer>) {
    // Notify when server is running
    logger::log_server(&format!(
        "Static {} Server \"{}\" is listening on {}",
        proto, server_name, addr
    ));
    running_servers.iter().for_each(|server| {
        logger::log_server(&format!(
            "{} Server \"{}\" is listening on {}",
            server.server_type, server_name, server.listening.socket
        ))
    });

    // Wait for incoming signals (E.g Ctrl+C (SIGINT), SIGTERM, etc
    signal_manager::wait_for_signal(|sig: signal::Signal| {
@@ -42,7 +52,6 @@ fn main() {
    logger::init(&opts.log_level);

    let addr = &format!("{}{}{}", opts.host, ":", opts.port);
    let proto = if opts.tls { "HTTPS" } else { "HTTP" };

    // Configure & launch the HTTP server

@@ -54,19 +63,47 @@ fn main() {
        cors_allow_origins: opts.cors_allow_origins,
    });

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

        match Iron::new(files.handle()).https(addr, ssl) {
            Result::Ok(_) => on_server_running(&opts.name, &proto, addr),
            Result::Ok(listening) => running_servers.push(RunningServer {
                listening,
                server_type: "Static HTTPS".to_string(),
            }),
            Result::Err(err) => panic!("{:?}", err),
        }

        // 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) {
                Result::Ok(listening) => running_servers.push(RunningServer {
                    listening,
                    server_type: "Redirect HTTP".to_string(),
                }),
                Result::Err(err) => panic!("{:?}", err),
            }
        }
    } else {
        // Launch static HTTP server
        match Iron::new(files.handle()).http(addr) {
            Result::Ok(_) => on_server_running(&opts.name, &proto, addr),
            Result::Ok(listening) => running_servers.push(RunningServer {
                listening,
                server_type: "Static HTTP".to_string(),
            }),
            Result::Err(err) => panic!("{:?}", err),
        }
    }
    on_server_running(&opts.name, &running_servers);
}

#[cfg(test)]