Skip to content

Commit

Permalink
Merge pull request #26 from HenningHolmDE/redirect_http_server
Browse files Browse the repository at this point in the history
feat: http to https redirection support
  • Loading branch information
joseluisq committed Jan 4, 2021
2 parents 1535367 + 63a05fa commit c4df0d3
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 9 deletions.
10 changes: 10 additions & 0 deletions README.md
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions src/config.rs
Expand Up @@ -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,
Expand Down
55 changes: 46 additions & 9 deletions src/main.rs
Expand Up @@ -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;

Expand All @@ -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| {
Expand All @@ -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

Expand All @@ -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)]
Expand Down

0 comments on commit c4df0d3

Please sign in to comment.