From 11cd3f2b58dc45c715f42aac545e4d60dfe38b28 Mon Sep 17 00:00:00 2001 From: Rishad Baniya <54678051+rishadbaniya@users.noreply.github.com> Date: Wed, 13 Oct 2021 19:51:42 +0545 Subject: [PATCH] Middleware example - Redirect http connections to https (#457) --- Cargo.lock | 9 +++ Cargo.toml | 1 + basics/middleware-http-to-https/Cargo.toml | 13 +++++ basics/middleware-http-to-https/README.md | 12 ++++ basics/middleware-http-to-https/cert.pem | 1 + basics/middleware-http-to-https/key.pem | 1 + basics/middleware-http-to-https/src/main.rs | 61 +++++++++++++++++++++ 7 files changed, 98 insertions(+) create mode 100644 basics/middleware-http-to-https/Cargo.toml create mode 100644 basics/middleware-http-to-https/README.md create mode 120000 basics/middleware-http-to-https/cert.pem create mode 120000 basics/middleware-http-to-https/key.pem create mode 100644 basics/middleware-http-to-https/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 39ed64ce..6293b625 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3768,6 +3768,15 @@ dependencies = [ "env_logger 0.9.0", ] +[[package]] +name = "middleware-http-to-https" +version = "0.1.0" +dependencies = [ + "actix-web 3.3.2", + "futures", + "rustls 0.18.1", +] + [[package]] name = "mime" version = "0.3.16" diff --git a/Cargo.toml b/Cargo.toml index af509ad3..67df3638 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ members = [ "basics/http-proxy", "basics/json-validation", "basics/middleware", + "basics/middleware-http-to-https", "basics/middleware-ext-mut", "basics/nested-routing", "basics/run-in-thread", diff --git a/basics/middleware-http-to-https/Cargo.toml b/basics/middleware-http-to-https/Cargo.toml new file mode 100644 index 00000000..32b7c1da --- /dev/null +++ b/basics/middleware-http-to-https/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "middleware-http-to-https" +version = "0.1.0" +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +actix-web = {version = "3", features = ["rustls"]} +rustls = "0.18" +futures = "0.3" + + diff --git a/basics/middleware-http-to-https/README.md b/basics/middleware-http-to-https/README.md new file mode 100644 index 00000000..e3090538 --- /dev/null +++ b/basics/middleware-http-to-https/README.md @@ -0,0 +1,12 @@ +## Middleware eg - redirect any http connection to use https connection + +This example is the next step after implementing this example : [Setup TLS via rustls](https://github.com/actix/examples/tree/master/security/rustls). + +You might have already implemented TLS(using one of the ways mentioned in the example of security section), and have setup your server to listen to port 443(for https). + +Now, the only problem left to solve is, to listen to **http** connections as well and redirect them to use **https** + +## Usage + +**Note :** You will be required to use sudo while running the binary to access port 80 and 443 + diff --git a/basics/middleware-http-to-https/cert.pem b/basics/middleware-http-to-https/cert.pem new file mode 120000 index 00000000..f9bcc09f --- /dev/null +++ b/basics/middleware-http-to-https/cert.pem @@ -0,0 +1 @@ +cert.pem \ No newline at end of file diff --git a/basics/middleware-http-to-https/key.pem b/basics/middleware-http-to-https/key.pem new file mode 120000 index 00000000..9ba3d1b8 --- /dev/null +++ b/basics/middleware-http-to-https/key.pem @@ -0,0 +1 @@ +key.pem \ No newline at end of file diff --git a/basics/middleware-http-to-https/src/main.rs b/basics/middleware-http-to-https/src/main.rs new file mode 100644 index 00000000..012da6b9 --- /dev/null +++ b/basics/middleware-http-to-https/src/main.rs @@ -0,0 +1,61 @@ +use std::fs::File; +use std::io::BufReader; + +use actix_web::dev::Service; +use futures::future::FutureExt; + +use actix_web::{get, App, HttpServer}; +use actix_web::{http, HttpResponse}; +use futures::future; +use futures::future::Either; +use rustls::internal::pemfile::{certs, pkcs8_private_keys}; +use rustls::{NoClientAuth, ServerConfig}; + +#[get("/")] +async fn index() -> String { + String::from( + "FOO BAR

FOO BAR

", + ) +} + +#[actix_web::main] +async fn main() -> std::io::Result<()> { + let mut config = ServerConfig::new(NoClientAuth::new()); + let cert_file = &mut BufReader::new(File::open("cert.pem").unwrap()); + let key_file = &mut BufReader::new(File::open("key.pem").unwrap()); + + let cert_chain = certs(cert_file).unwrap(); + let mut keys = pkcs8_private_keys(key_file).unwrap(); + + config.set_single_cert(cert_chain, keys.remove(0)).unwrap(); + + HttpServer::new(|| { + App::new() + .wrap_fn(|sreq, srv| { + let host = sreq.connection_info().host().to_owned(); + let uri = sreq.uri().to_owned(); + let url = format!("https://{}{}", host, uri); + + // If the scheme is "https" then it will let other services below this wrap_fn + // handle the request and if it's "http" then a response with redirect status code + // will be sent whose "location" header will be same as before, with just "http" + // changed to "https" + // + if sreq.connection_info().scheme() == "https" { + Either::Left(srv.call(sreq).map(|res| res)) + } else { + println!("An http request has arrived here, i will redirect it to use https"); + return Either::Right(future::ready(Ok(sreq.into_response( + HttpResponse::MovedPermanently() + .header(http::header::LOCATION, url) + .finish(), + )))); + } + }) + .service(index) + }) + .bind("0.0.0.0:80")? // Port 80 to listen for http request + .bind_rustls("0.0.0.0:443", config)? // Port 443 to listen for https request + .run() + .await +}