From 43b004cf6ec096a91248049d604b3a918482c766 Mon Sep 17 00:00:00 2001 From: Jun Kurihara Date: Tue, 8 Aug 2023 17:59:20 +0900 Subject: [PATCH] refactor: separeted forwarder definition for more flexibility --- config-example.toml | 5 ++- rpxy-lib/src/handler/forwarder.rs | 58 ++++++++++++++++++++++++++++ rpxy-lib/src/handler/handler_main.rs | 12 ++++-- rpxy-lib/src/handler/mod.rs | 6 ++- rpxy-lib/src/lib.rs | 18 ++++----- 5 files changed, 84 insertions(+), 15 deletions(-) create mode 100644 rpxy-lib/src/handler/forwarder.rs diff --git a/config-example.toml b/config-example.toml index 605067c..3d90761 100644 --- a/config-example.toml +++ b/config-example.toml @@ -56,7 +56,10 @@ upstream = [ { location = 'www.yahoo.co.jp', tls = true }, ] load_balance = "round_robin" # or "random" or "sticky" (sticky session) or "none" (fix to the first one, default) -upstream_options = ["override_host", "convert_https_to_2"] +upstream_options = [ + "override_host", + "force_http2_upstream", # mutually exclusive with "force_http11_upstream" +] # Non-default destination in "localhost" app, which is routed by "path" [[apps.localhost.reverse_proxy]] diff --git a/rpxy-lib/src/handler/forwarder.rs b/rpxy-lib/src/handler/forwarder.rs new file mode 100644 index 0000000..bbcebca --- /dev/null +++ b/rpxy-lib/src/handler/forwarder.rs @@ -0,0 +1,58 @@ +use crate::error::RpxyError; +use async_trait::async_trait; +use derive_builder::Builder; +use hyper::{ + body::{Body, HttpBody}, + client::{connect::Connect, HttpConnector}, + Client, Request, Response, +}; +use hyper_rustls::HttpsConnector; + +#[async_trait] +/// Definition of the forwarder that simply forward requests from downstream client to upstream app servers. +pub trait ForwardRequest { + type Error; + async fn request(&self, req: Request) -> Result, Self::Error>; +} + +#[derive(Builder, Clone)] +/// Forwarder struct +pub struct Forwarder +where + C: Connect + Clone + Sync + Send + 'static, +{ + // TODO: need `h2c` or http/2-only client separately + inner: Client, +} + +#[async_trait] +impl ForwardRequest for Forwarder +where + B: HttpBody + Send + 'static, + B::Data: Send, + B::Error: Into>, + C: Connect + Clone + Sync + Send + 'static, +{ + type Error = RpxyError; + async fn request(&self, req: Request) -> Result, Self::Error> { + // TODO: + // TODO: Implement here a client that handles `h2c` requests + // TODO: + self.inner.request(req).await.map_err(RpxyError::Hyper) + } +} + +impl Forwarder, Body> { + pub async fn new() -> Self { + // let connector = TrustDnsResolver::default().into_rustls_webpki_https_connector(); + let connector = hyper_rustls::HttpsConnectorBuilder::new() + .with_webpki_roots() + .https_or_http() + .enable_http1() + .enable_http2() + .build(); + + let inner = Client::builder().build::<_, Body>(connector); + Self { inner } + } +} diff --git a/rpxy-lib/src/handler/handler_main.rs b/rpxy-lib/src/handler/handler_main.rs index c450dea..22e05ca 100644 --- a/rpxy-lib/src/handler/handler_main.rs +++ b/rpxy-lib/src/handler/handler_main.rs @@ -1,5 +1,11 @@ // Highly motivated by https://github.com/felipenoris/hyper-reverse-proxy -use super::{utils_headers::*, utils_request::*, utils_synth_response::*, HandlerContext}; +use super::{ + forwarder::{ForwardRequest, Forwarder}, + utils_headers::*, + utils_request::*, + utils_synth_response::*, + HandlerContext, +}; use crate::{ backend::{Backend, UpstreamGroup}, certs::CryptoSource, @@ -14,7 +20,7 @@ use hyper::{ client::connect::Connect, header::{self, HeaderValue}, http::uri::Scheme, - Body, Client, Request, Response, StatusCode, Uri, Version, + Body, Request, Response, StatusCode, Uri, Version, }; use std::{net::SocketAddr, sync::Arc}; use tokio::{io::copy_bidirectional, time::timeout}; @@ -27,7 +33,7 @@ where T: Connect + Clone + Sync + Send + 'static, U: CryptoSource + Clone, { - forwarder: Arc>, + forwarder: Arc>, globals: Arc>, } diff --git a/rpxy-lib/src/handler/mod.rs b/rpxy-lib/src/handler/mod.rs index aed9831..854bd8f 100644 --- a/rpxy-lib/src/handler/mod.rs +++ b/rpxy-lib/src/handler/mod.rs @@ -1,3 +1,4 @@ +mod forwarder; mod handler_main; mod utils_headers; mod utils_request; @@ -5,7 +6,10 @@ mod utils_synth_response; #[cfg(feature = "sticky-cookie")] use crate::backend::LbContext; -pub use handler_main::{HttpMessageHandler, HttpMessageHandlerBuilder, HttpMessageHandlerBuilderError}; +pub use { + forwarder::Forwarder, + handler_main::{HttpMessageHandler, HttpMessageHandlerBuilder, HttpMessageHandlerBuilderError}, +}; #[allow(dead_code)] #[derive(Debug)] diff --git a/rpxy-lib/src/lib.rs b/rpxy-lib/src/lib.rs index b2a777c..c2b8f0e 100644 --- a/rpxy-lib/src/lib.rs +++ b/rpxy-lib/src/lib.rs @@ -8,9 +8,14 @@ mod log; mod proxy; mod utils; -use crate::{error::*, globals::Globals, handler::HttpMessageHandlerBuilder, log::*, proxy::ProxyBuilder}; +use crate::{ + error::*, + globals::Globals, + handler::{Forwarder, HttpMessageHandlerBuilder}, + log::*, + proxy::ProxyBuilder, +}; use futures::future::select_all; -use hyper::Client; // use hyper_trust_dns::TrustDnsResolver; use std::sync::Arc; @@ -62,17 +67,10 @@ where request_count: Default::default(), runtime_handle: runtime_handle.clone(), }); - // let connector = TrustDnsResolver::default().into_rustls_webpki_https_connector(); - let connector = hyper_rustls::HttpsConnectorBuilder::new() - .with_webpki_roots() - .https_or_http() - .enable_http1() - .enable_http2() - .build(); // TODO: HTTP2 only client is needed for http2 cleartext case let msg_handler = HttpMessageHandlerBuilder::default() - .forwarder(Arc::new(Client::builder().build::<_, hyper::Body>(connector))) + .forwarder(Arc::new(Forwarder::new().await)) .globals(globals.clone()) .build()?;