From ef5d1c0f2ac45af52d2ac33722a9c0055bd70047 Mon Sep 17 00:00:00 2001 From: Jun Kurihara Date: Thu, 23 Jun 2022 21:22:28 -0400 Subject: [PATCH] add https redirection --- src/config.rs | 2 +- src/proxy/proxy_handler.rs | 83 ++++++++++++++++++++++++++++++++++---- src/proxy/proxy_main.rs | 10 ++++- 3 files changed, 85 insertions(+), 10 deletions(-) diff --git a/src/config.rs b/src/config.rs index d8ff086..cb2d860 100644 --- a/src/config.rs +++ b/src/config.rs @@ -35,7 +35,7 @@ pub fn parse_opts(globals: &mut Globals, backends: &mut HashMap default_destination_uri: "https://google.com/".parse::().unwrap(), destination_uris: Some(map_example), }, - redirect_to_https: None, // TODO: ここはHTTPの時のみの設定。tlsの存在とは排他的。 + redirect_to_https: Some(true), // TODO: ここはtlsが存在する時はSomeにすべき。Noneはtlsがないときのみのはず tls_cert_path: Some(PathBuf::from(r"localhost1.pem")), tls_cert_key_path: Some(PathBuf::from(r"localhost1.pem")), diff --git a/src/proxy/proxy_handler.rs b/src/proxy/proxy_handler.rs index de8ac9a..4837da9 100644 --- a/src/proxy/proxy_handler.rs +++ b/src/proxy/proxy_handler.rs @@ -9,7 +9,7 @@ use hyper::{ http, server::conn::Http, service::{service_fn, Service}, - Body, Client, HeaderMap, Method, Request, Response, StatusCode, + Body, Client, HeaderMap, Method, Request, Response, StatusCode, Uri, }; use std::{collections::HashMap, net::SocketAddr, pin::Pin, sync::Arc}; use tokio::{ @@ -23,26 +23,95 @@ use tokio::{ pub async fn handle_request( req: Request, client_ip: SocketAddr, + tls_enabled: bool, globals: Arc, -) -> Result, http::Error> { - // http_error(StatusCode::NOT_FOUND) - debug!("{:?}", req); + backends: Arc>, +) -> Result> { + let headers = req.headers(); + + // Here we start to handle with hostname + // Find backend application for given hostname + let (hostname, port) = parse_hostname_port(headers, tls_enabled)?; + let path = req.uri().path(); + let backend = if let Some(be) = backends.get(hostname.as_str()) { + be + } else { + return http_error(StatusCode::SERVICE_UNAVAILABLE); + }; + + // Redirect to https if tls_enabled is false and redirect_to_https is true + if !tls_enabled && backend.redirect_to_https.unwrap_or(false) { + if let Some(https_port) = globals.https_port { + let dest = if https_port == 443 { + format!("https://{}{}", hostname, path) + } else { + format!( + "https://{}:{}{}", + hostname, + globals.https_port.unwrap(), + path + ) + }; + return https_redirection(dest); + } else { + return http_error(StatusCode::SERVICE_UNAVAILABLE); + } + } + + // Find reverse proxy for given path + // let destination_uri = if backend.reverse_proxy.destination_uris.is_some() { + // if let (b) = backend.re + // } else { + // backend.reverse_proxy.default_destination_uri.clone(); + // }; + + debug!("path: {}", req.uri().path()); // if req.version() == hyper::Version::HTTP_11 { // Ok(Response::new(Body::from("Hello World"))) // } else { // Note: it's usually better to return a Response // with an appropriate StatusCode instead of an Err. // Err("not HTTP/1.1, abort connection") - http_error(StatusCode::NOT_FOUND) + // http_error(StatusCode::NOT_FOUND) + https_redirection("https://www.google.com/".to_string()) // } // }); } -#[allow(clippy::unnecessary_wraps)] -fn http_error(status_code: StatusCode) -> Result, http::Error> { +fn http_error(status_code: StatusCode) -> Result> { let response = Response::builder() .status(status_code) .body(Body::empty()) .unwrap(); Ok(response) } + +fn https_redirection(redirect_to: String) -> Result> { + let response = Response::builder() + .status(StatusCode::MOVED_PERMANENTLY) + .header("Location", redirect_to) + .body(Body::empty()) + .unwrap(); + Ok(response) +} + +fn parse_hostname_port(headers: &HeaderMap, tls_enabled: bool) -> Result<(String, u16)> { + let hostname_port = headers + .get("host") + .ok_or_else(|| anyhow!("No host in request header"))?; + let hp_as_uri = hostname_port.to_str().unwrap().parse::().unwrap(); + + let hostname = hp_as_uri + .host() + .ok_or_else(|| anyhow!("Failed to parse hostname"))?; + + let port = if let Some(p) = hp_as_uri.port() { + p.as_u16() + } else if tls_enabled { + 443 + } else { + 80 + }; + + Ok((hostname.to_string(), port)) +} diff --git a/src/proxy/proxy_main.rs b/src/proxy/proxy_main.rs index 6833b79..b28883a 100644 --- a/src/proxy/proxy_main.rs +++ b/src/proxy/proxy_main.rs @@ -1,7 +1,7 @@ use super::proxy_handler::handle_request; use crate::{backend::Backend, error::*, globals::Globals, log::*}; use hyper::{ - client::connect::Connect, server::conn::Http, service::service_fn, Body, Client, Request, + client::connect::Connect, server::conn::Http, service::service_fn, Body, Client, Method, Request, }; use std::{collections::HashMap, net::SocketAddr, sync::Arc}; use tokio::{ @@ -65,7 +65,13 @@ where server.serve_connection( stream, service_fn(move |req: Request| { - handle_request(req, peer_addr, self.globals.clone()) + handle_request( + req, + peer_addr, + self.tls_enabled, + self.globals.clone(), + self.backends.clone(), + ) }), ), )