From 79ef600f272f413d2d67ee34254e17cbfe3aaa67 Mon Sep 17 00:00:00 2001 From: Taylor Vann Date: Mon, 19 Oct 2026 16:07:24 -0700 Subject: [PATCH 1/7] make addresses explicit in config --- LICENSE | 2 +- README.md | 14 ++++++++------ ...ample.json => reverse_proxy.config.example.json | 8 ++++---- src/addresses.rs | 11 ++++++----- src/config.rs | 12 ++++++++---- 5 files changed, 27 insertions(+), 20 deletions(-) rename reverse_proxy_config.example.json => reverse_proxy.config.example.json (62%) diff --git a/LICENSE b/LICENSE index 539791b..6d4f5e2 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ BSD 3-Clause License -Copyright (c) 2022, W-lfpup +Copyright (c) 2026, Here By There LLC All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/README.md b/README.md index b3f1b9d..adb5bdc 100644 --- a/README.md +++ b/README.md @@ -31,12 +31,14 @@ All filepaths can be absolute or relative to the config filepath. "host_and_port": "", "key_filepath": "", "cert_filepath": "", - "addresses": [ - ["", ""] - ], - "dangerous_self_signed_addresses": [ - ["", ""] - ] + "addresses": [{ + "incoming": "origin_address", + "outgoing": "destination_address", + }], + "dangerous_self_signed_addresses": [{ + "incoming": "origin_address", + "outgoing": "destination_address", + }] } ``` diff --git a/reverse_proxy_config.example.json b/reverse_proxy.config.example.json similarity index 62% rename from reverse_proxy_config.example.json rename to reverse_proxy.config.example.json index 892c61d..81e7477 100644 --- a/reverse_proxy_config.example.json +++ b/reverse_proxy.config.example.json @@ -3,9 +3,9 @@ "key_filepath": "./demo/self-signed-key.key", "cert_filepath": "./demo/self-signed-cert.crt", "addresses": [ - [ - "https://127.0.0.1", - "http://127.0.0.1:3000" - ] + { + "incoming": "https://example.com", + "outgoing": "http://127.0.0.1:3000" + } ] } \ No newline at end of file diff --git a/src/addresses.rs b/src/addresses.rs index 0c7b1a3..e078c97 100644 --- a/src/addresses.rs +++ b/src/addresses.rs @@ -1,4 +1,4 @@ -use crate::config::Config; +use crate::config::{Address, Config}; use crate::errors::Error; use crate::response::{AddressMap, AddressParams}; use hyper::Uri; @@ -20,11 +20,12 @@ pub fn create_address_map(config: &Config) -> Result { fn add_addresses_to_map( url_map: &mut AddressMap, - addresses: &Vec<(String, String)>, + addresses: &Vec
, is_dangerous: bool, ) -> Result<(), Error> { - for (source_str, target_str) in addresses { - let source_uri = match Uri::try_from(source_str) { + for address in addresses { + let Address { incoming, outgoing } = address; + let source_uri = match Uri::try_from(incoming) { Ok(uri) => uri, Err(e) => return Err(Error::Uri(e)), }; @@ -38,7 +39,7 @@ fn add_addresses_to_map( } }; - let uri = match Uri::try_from(target_str) { + let uri = match Uri::try_from(outgoing) { Ok(uri) => uri, Err(e) => return Err(Error::Uri(e)), }; diff --git a/src/config.rs b/src/config.rs index 07cbaf0..737847d 100644 --- a/src/config.rs +++ b/src/config.rs @@ -6,17 +6,21 @@ use tokio::fs; use crate::errors::Error; +#[derive(Clone, Serialize, Deserialize, Debug)] +pub struct Address { + pub incoming: String, + pub outgoing: String, +} + #[derive(Clone, Serialize, Deserialize, Debug)] pub struct Config { pub host_and_port: String, pub key_filepath: PathBuf, pub cert_filepath: PathBuf, - pub addresses: Vec<(String, String)>, - pub dangerous_self_signed_addresses: Option>, + pub addresses: Vec
, + pub dangerous_self_signed_addresses: Option>, } -// Serde path fs errors in one function - pub async fn from_filepath(filepath: &PathBuf) -> Result { let config_path = match path::absolute(filepath) { Ok(pb) => pb, From eb9cf18c3159f9b85c481894213a8dfe97951ed6 Mon Sep 17 00:00:00 2001 From: Taylor Vann Date: Mon, 19 Oct 2026 16:42:40 -0700 Subject: [PATCH 2/7] remove commented out code --- src/main.rs | 2 +- src/requests.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index e31736d..493bbc7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -64,7 +64,7 @@ async fn main() -> Result<(), Error> { Err(e) => return Err(Error::Io(e)), }; - println!("Reverse Proxy: {}", &config.host_and_port); + println!("Reverse proxy @ {}", &config.host_and_port); loop { let (socket, _remote_addr) = match listener.accept().await { diff --git a/src/requests.rs b/src/requests.rs index 2234e0d..656ac5b 100644 --- a/src/requests.rs +++ b/src/requests.rs @@ -17,7 +17,6 @@ fn get_host_and_authority<'a>(uri: &Uri) -> Result<(String, String), &'a str> { let host = match uri.host() { Some(h) => h.to_string(), _ => return Err("failed to retrieve downstream URI from upstream URI"), - // _ => return Err(Error::Custom("failed to retrieve downstream URI from upstream URI".to_string())), }; let port = match uri.port() { From 2c8825c7e4db21322de9199296d0704ea6ea36a1 Mon Sep 17 00:00:00 2001 From: Taylor Vann Date: Mon, 19 Oct 2026 16:59:43 -0700 Subject: [PATCH 3/7] bump minor version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 805ba61..c7a1a7d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "reverse_proxy" -version = "0.2.1" +version = "0.2.2" edition = "2024" [dependencies] From 813b7bcca8e927e7c75800fe0039ba0150b7d1a7 Mon Sep 17 00:00:00 2001 From: Taylor Vann Date: Wed, 21 Oct 2026 00:51:39 -0700 Subject: [PATCH 4/7] prepare for address clone --- Cargo.toml | 2 +- reverse_proxy.config.example.json | 2 +- src/addresses.rs | 9 ++++++--- src/config.rs | 3 +-- src/main.rs | 3 +-- src/response.rs | 3 +-- src/service.rs | 25 +++++++++++++++++++++++++ 7 files changed, 36 insertions(+), 11 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c7a1a7d..01773fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "reverse_proxy" -version = "0.2.2" +version = "0.3.1" edition = "2024" [dependencies] diff --git a/reverse_proxy.config.example.json b/reverse_proxy.config.example.json index 81e7477..64e06fe 100644 --- a/reverse_proxy.config.example.json +++ b/reverse_proxy.config.example.json @@ -8,4 +8,4 @@ "outgoing": "http://127.0.0.1:3000" } ] -} \ No newline at end of file +} diff --git a/src/addresses.rs b/src/addresses.rs index e078c97..6086b3f 100644 --- a/src/addresses.rs +++ b/src/addresses.rs @@ -25,12 +25,12 @@ fn add_addresses_to_map( ) -> Result<(), Error> { for address in addresses { let Address { incoming, outgoing } = address; - let source_uri = match Uri::try_from(incoming) { + let incoming_uri = match Uri::try_from(incoming) { Ok(uri) => uri, Err(e) => return Err(Error::Uri(e)), }; - let source_host = match source_uri.host() { + let incoming_host = match incoming_uri.host() { Some(h) => h, _ => { return Err(Error::Custom( @@ -44,7 +44,10 @@ fn add_addresses_to_map( Err(e) => return Err(Error::Uri(e)), }; - url_map.insert(source_host.to_string(), AddressParams { uri, is_dangerous }); + url_map.insert( + incoming_host.to_string(), + AddressParams { uri, is_dangerous }, + ); } Ok(()) diff --git a/src/config.rs b/src/config.rs index 737847d..cdd4c4c 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,11 +1,10 @@ +use crate::errors::Error; use serde::{Deserialize, Serialize}; use serde_json; use std::path; use std::path::PathBuf; use tokio::fs; -use crate::errors::Error; - #[derive(Clone, Serialize, Deserialize, Debug)] pub struct Address { pub incoming: String, diff --git a/src/main.rs b/src/main.rs index 493bbc7..efbcfed 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,4 @@ +use crate::errors::Error; use hyper_util::rt::{TokioExecutor, TokioIo}; use hyper_util::server::conn::auto::Builder; use native_tls::Identity; @@ -13,8 +14,6 @@ mod requests; mod response; mod service; -use crate::errors::Error; - #[tokio::main] async fn main() -> Result<(), Error> { // create config diff --git a/src/response.rs b/src/response.rs index a725d04..b3a811d 100644 --- a/src/response.rs +++ b/src/response.rs @@ -1,3 +1,4 @@ +use crate::requests; use bytes::Bytes; use http_body_util::combinators::BoxBody; use hyper::body::Incoming; @@ -6,8 +7,6 @@ use hyper::{Request, Response, StatusCode, Uri, header}; use std::collections::HashMap; use std::sync::Arc; -use crate::requests; - pub type BoxedResponse = Response>; const URI_FROM_REQUEST_ERROR: &str = "unable to parse upstream URI from request"; diff --git a/src/service.rs b/src/service.rs index 02d92f7..86a2640 100644 --- a/src/service.rs +++ b/src/service.rs @@ -18,6 +18,31 @@ impl Service> for Svc { fn call(&self, req: Request) -> Self::Future { let addresses = self.addresses.clone(); + + // get address first then send to boxed response + // instead of copying the entire address book + + // let host = match get_host(&req) { + // Some(uri) => uri, + // _ => { + // return requests::create_fallback_response( + // &StatusCode::BAD_REQUEST, + // &URI_FROM_REQUEST_ERROR, + // ); + // } + // }; + + // // get target uri + // let address_params = match addresses.get(&host) { + // Some(params) => params, + // _ => { + // return requests::create_fallback_response( + // &StatusCode::BAD_GATEWAY, + // &URI_FROM_REQUEST_ERROR, + // ); + // } + // }; + Box::pin(async move { build_response(req, addresses).await }) } } From 395fc9990e61c46d0ff8755a4a675132abc62eee Mon Sep 17 00:00:00 2001 From: Taylor Vann Date: Wed, 21 Oct 2026 13:55:01 -0700 Subject: [PATCH 5/7] only send address params --- src/response.rs | 96 +++++++++++-------------------------------------- src/service.rs | 85 +++++++++++++++++++++++++++++-------------- 2 files changed, 80 insertions(+), 101 deletions(-) diff --git a/src/response.rs b/src/response.rs index b3a811d..d744201 100644 --- a/src/response.rs +++ b/src/response.rs @@ -3,14 +3,13 @@ use bytes::Bytes; use http_body_util::combinators::BoxBody; use hyper::body::Incoming; use hyper::http::uri::InvalidUriParts; -use hyper::{Request, Response, StatusCode, Uri, header}; +use hyper::{Request, Response, StatusCode, Uri}; use std::collections::HashMap; -use std::sync::Arc; pub type BoxedResponse = Response>; -const URI_FROM_REQUEST_ERROR: &str = "unable to parse upstream URI from request"; -const UPSTREAM_URI_ERROR: &str = "falied to update request with upstream URI"; +pub const URI_FROM_REQUEST_ERROR: &str = "unable to parse upstream URI from request"; +pub const UPSTREAM_URI_ERROR: &str = "falied to update request with upstream URI"; #[derive(Clone, Debug)] pub struct AddressParams { @@ -20,74 +19,10 @@ pub struct AddressParams { pub type AddressMap = HashMap; -pub async fn build_response( - mut req: Request, - addresses: Arc>, -) -> Result { - let host = match get_host(&req) { - Some(uri) => uri, - _ => { - return requests::create_fallback_response( - &StatusCode::BAD_REQUEST, - &URI_FROM_REQUEST_ERROR, - ); - } - }; - - // get target uri - let address_params = match addresses.get(&host) { - Some(params) => params, - _ => { - return requests::create_fallback_response( - &StatusCode::BAD_GATEWAY, - &URI_FROM_REQUEST_ERROR, - ); - } - }; - - if let Err(_) = update_request_with_dest_uri(&mut req, &address_params.uri) { - return requests::create_fallback_response( - &StatusCode::INTERNAL_SERVER_ERROR, - &UPSTREAM_URI_ERROR, - ); - }; - - get_response(req, address_params.is_dangerous).await -} - -fn get_host(req: &Request) -> Option { - // http2 - if let Some(host) = req.uri().host() { - return Some(host.to_string()); - }; - - // http 1 - let host_header = match req.headers().get(header::HOST) { - Some(h) => h, - _ => return None, - }; - - let host_str = match host_header.to_str() { - Ok(hs) => hs, - _ => return None, - }; - - let host_as_uri = match Uri::try_from(host_str) { - Ok(hau) => hau, - _ => return None, - }; - - if let Some(host) = host_as_uri.host() { - return Some(host.to_string()); - } - - None -} - fn update_request_with_dest_uri( - req: &mut Request, + mut req: Request, target_uri: &Uri, -) -> Result<(), InvalidUriParts> { +) -> Result, InvalidUriParts> { let mut dest_parts = target_uri.clone().into_parts(); dest_parts.path_and_query = None; @@ -100,14 +35,25 @@ fn update_request_with_dest_uri( Err(e) => return Err(e), }; - Ok(()) + Ok(req) } -async fn get_response( +pub async fn build_response( req: Request, - is_dangerous: bool, + address_params: AddressParams, ) -> Result { let version = req.version(); + + let req = match update_request_with_dest_uri(req, &address_params.uri) { + Ok(r) => r, + _ => { + return requests::create_fallback_response( + &StatusCode::INTERNAL_SERVER_ERROR, + &UPSTREAM_URI_ERROR, + ); + } + }; + let scheme = match req.uri().scheme() { Some(a) => a.as_str(), _ => "http", @@ -115,10 +61,10 @@ async fn get_response( match (version, scheme) { (hyper::Version::HTTP_2, "https") => { - requests::send_http2_tls_request(req, is_dangerous).await + requests::send_http2_tls_request(req, address_params.is_dangerous).await } (hyper::Version::HTTP_2, _) => requests::send_http2_request(req).await, - (_, "https") => requests::send_http1_tls_request(req, is_dangerous).await, + (_, "https") => requests::send_http1_tls_request(req, address_params.is_dangerous).await, _ => requests::send_http1_request(req).await, } } diff --git a/src/service.rs b/src/service.rs index 86a2640..fb93f12 100644 --- a/src/service.rs +++ b/src/service.rs @@ -1,5 +1,8 @@ +use crate::requests; +use crate::response; use crate::response::{AddressMap, BoxedResponse, build_response}; -use hyper::Request; +use hyper::{Request, StatusCode, Uri, header}; + use hyper::body::Incoming; use hyper::http; use hyper::service::Service; @@ -19,30 +22,60 @@ impl Service> for Svc { fn call(&self, req: Request) -> Self::Future { let addresses = self.addresses.clone(); - // get address first then send to boxed response - // instead of copying the entire address book - - // let host = match get_host(&req) { - // Some(uri) => uri, - // _ => { - // return requests::create_fallback_response( - // &StatusCode::BAD_REQUEST, - // &URI_FROM_REQUEST_ERROR, - // ); - // } - // }; - - // // get target uri - // let address_params = match addresses.get(&host) { - // Some(params) => params, - // _ => { - // return requests::create_fallback_response( - // &StatusCode::BAD_GATEWAY, - // &URI_FROM_REQUEST_ERROR, - // ); - // } - // }; - - Box::pin(async move { build_response(req, addresses).await }) + let host = match get_host(&req) { + Some(uri) => uri, + _ => { + return Box::pin(async move { + requests::create_fallback_response( + &StatusCode::BAD_REQUEST, + &response::URI_FROM_REQUEST_ERROR, + ) + }); + } + }; + + // get target uri + let address_params = match addresses.get(&host) { + Some(params) => params.clone(), + _ => { + return Box::pin(async move { + requests::create_fallback_response( + &StatusCode::BAD_GATEWAY, + &response::URI_FROM_REQUEST_ERROR, + ) + }); + } + }; + + Box::pin(async move { build_response(req, address_params).await }) } } + +pub fn get_host(req: &Request) -> Option { + // http2 + if let Some(host) = req.uri().host() { + return Some(host.to_string()); + }; + + // http 1 + let host_header = match req.headers().get(header::HOST) { + Some(h) => h, + _ => return None, + }; + + let host_str = match host_header.to_str() { + Ok(hs) => hs, + _ => return None, + }; + + let host_as_uri = match Uri::try_from(host_str) { + Ok(hau) => hau, + _ => return None, + }; + + if let Some(host) = host_as_uri.host() { + return Some(host.to_string()); + } + + None +} From 1331b21d630ade9f661cb3b29671cbf4664668ce Mon Sep 17 00:00:00 2001 From: Taylor Vann Date: Wed, 21 Oct 2026 14:03:57 -0700 Subject: [PATCH 6/7] format --- src/service.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/service.rs b/src/service.rs index fb93f12..c94353d 100644 --- a/src/service.rs +++ b/src/service.rs @@ -1,11 +1,10 @@ use crate::requests; use crate::response; use crate::response::{AddressMap, BoxedResponse, build_response}; -use hyper::{Request, StatusCode, Uri, header}; - use hyper::body::Incoming; use hyper::http; use hyper::service::Service; +use hyper::{Request, StatusCode, Uri, header}; use std::future::Future; use std::pin::Pin; use std::sync::Arc; From a0c5471b11b18436bde46a05aa9eed29e8fec816 Mon Sep 17 00:00:00 2001 From: Taylor Vann Date: Wed, 21 Oct 2026 14:26:03 -0700 Subject: [PATCH 7/7] remove demo dir --- demo/index.html | 1 - 1 file changed, 1 deletion(-) delete mode 100644 demo/index.html diff --git a/demo/index.html b/demo/index.html deleted file mode 100644 index d0119df..0000000 --- a/demo/index.html +++ /dev/null @@ -1 +0,0 @@ -

hello!