From 32b173966c422a4f660cefa29ac012330e4d7e92 Mon Sep 17 00:00:00 2001 From: Jun Kurihara Date: Fri, 18 Aug 2023 18:15:36 +0900 Subject: [PATCH] feat: separated feature cache --- .github/workflows/docker_build_push.yml | 2 +- rpxy-bin/Cargo.toml | 3 ++- rpxy-bin/src/config/toml.rs | 23 ++++++++--------- rpxy-bin/src/constants.rs | 7 +----- rpxy-lib/Cargo.toml | 7 +++--- rpxy-lib/src/constants.rs | 9 +++++++ rpxy-lib/src/globals.rs | 20 ++++++++++----- rpxy-lib/src/handler/cache.rs | 4 +-- rpxy-lib/src/handler/forwarder.rs | 33 ++++++++++++++++++++----- rpxy-lib/src/handler/mod.rs | 1 + rpxy-lib/src/lib.rs | 3 +++ 11 files changed, 76 insertions(+), 36 deletions(-) diff --git a/.github/workflows/docker_build_push.yml b/.github/workflows/docker_build_push.yml index e2d801c..2f4d565 100644 --- a/.github/workflows/docker_build_push.yml +++ b/.github/workflows/docker_build_push.yml @@ -42,7 +42,7 @@ jobs: - target: "s2n" dockerfile: ./docker/Dockerfile build-args: | - "CARGO_FEATURES=--no-default-features --features http3-s2n" + "CARGO_FEATURES=--no-default-features --features http3-s2n cache" "ADDITIONAL_DEPS=pkg-config libssl-dev cmake libclang1 gcc g++" platforms: linux/amd64,linux/arm64 tags-suffix: "-s2n" diff --git a/rpxy-bin/Cargo.toml b/rpxy-bin/Cargo.toml index 69d21c8..326a0fc 100644 --- a/rpxy-bin/Cargo.toml +++ b/rpxy-bin/Cargo.toml @@ -12,9 +12,10 @@ publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] -default = ["http3-quinn"] +default = ["http3-quinn", "cache"] http3-quinn = ["rpxy-lib/http3-quinn"] http3-s2n = ["rpxy-lib/http3-s2n"] +cache = ["rpxy-lib/cache"] [dependencies] rpxy-lib = { path = "../rpxy-lib/", default-features = false, features = [ diff --git a/rpxy-bin/src/config/toml.rs b/rpxy-bin/src/config/toml.rs index f655347..2d03895 100644 --- a/rpxy-bin/src/config/toml.rs +++ b/rpxy-bin/src/config/toml.rs @@ -6,7 +6,7 @@ use crate::{ use rpxy_lib::{reexports::Uri, AppConfig, ProxyConfig, ReverseProxyConfig, TlsConfig, UpstreamUri}; use rustc_hash::FxHashMap as HashMap; use serde::Deserialize; -use std::{fs, net::SocketAddr, path::PathBuf}; +use std::{fs, net::SocketAddr}; #[derive(Deserialize, Debug, Default, PartialEq, Eq, Clone)] pub struct ConfigToml { @@ -32,6 +32,7 @@ pub struct Http3Option { pub max_idle_timeout: Option, } +#[cfg(feature = "cache")] #[derive(Deserialize, Debug, Default, PartialEq, Eq, Clone)] pub struct CacheOption { pub cache_dir: Option, @@ -43,6 +44,7 @@ pub struct CacheOption { pub struct Experimental { #[cfg(any(feature = "http3-quinn", feature = "http3-s2n"))] pub h3: Option, + #[cfg(feature = "cache")] pub cache: Option, pub ignore_sni_consistency: Option, } @@ -169,20 +171,19 @@ impl TryInto for &ConfigToml { proxy_config.sni_consistency = !ignore; } + #[cfg(feature = "cache")] if let Some(cache_option) = &exp.cache { proxy_config.cache_enabled = true; proxy_config.cache_dir = match &cache_option.cache_dir { - Some(cache_dir) => Some(PathBuf::from(cache_dir)), - None => Some(PathBuf::from(CACHE_DIR)), - }; - proxy_config.cache_max_entry = match &cache_option.max_cache_entry { - Some(num) => Some(*num), - None => Some(MAX_CACHE_ENTRY), - }; - proxy_config.cache_max_each_size = match &cache_option.max_cache_each_size { - Some(num) => Some(*num), - None => Some(MAX_CACHE_EACH_SIZE), + Some(cache_dir) => Some(std::path::PathBuf::from(cache_dir)), + None => Some(std::path::PathBuf::from(CACHE_DIR)), }; + if let Some(num) = cache_option.max_cache_entry { + proxy_config.cache_max_entry = num; + } + if let Some(num) = cache_option.max_cache_each_size { + proxy_config.cache_max_each_size = num; + } } } diff --git a/rpxy-bin/src/constants.rs b/rpxy-bin/src/constants.rs index 54fa7dd..53c8bbc 100644 --- a/rpxy-bin/src/constants.rs +++ b/rpxy-bin/src/constants.rs @@ -2,11 +2,6 @@ pub const LISTEN_ADDRESSES_V4: &[&str] = &["0.0.0.0"]; pub const LISTEN_ADDRESSES_V6: &[&str] = &["[::]"]; pub const CONFIG_WATCH_DELAY_SECS: u32 = 20; +#[cfg(feature = "cache")] // Cache directory pub const CACHE_DIR: &str = "./cache"; -// # of entries in cache -pub const MAX_CACHE_ENTRY: usize = 1_000; -// max size for each file in bytes -pub const MAX_CACHE_EACH_SIZE: usize = 65_535; - -// TODO: max cache size in total diff --git a/rpxy-lib/Cargo.toml b/rpxy-lib/Cargo.toml index 59b76f6..8dc7c8f 100644 --- a/rpxy-lib/Cargo.toml +++ b/rpxy-lib/Cargo.toml @@ -12,10 +12,11 @@ publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] -default = ["http3-quinn", "sticky-cookie"] +default = ["http3-quinn", "sticky-cookie", "cache"] http3-quinn = ["quinn", "h3", "h3-quinn", "socket2"] http3-s2n = ["h3", "s2n-quic", "s2n-quic-rustls", "s2n-quic-h3"] sticky-cookie = ["base64", "sha2", "chrono"] +cache = ["http-cache-semantics", "lru"] [dependencies] rand = "0.8.5" @@ -74,8 +75,8 @@ s2n-quic-h3 = { path = "../submodules/s2n-quic/quic/s2n-quic-h3/", optional = tr s2n-quic-rustls = { path = "../submodules/s2n-quic/quic/s2n-quic-rustls/", optional = true } # cache -http-cache-semantics = { path = "../submodules/rusty-http-cache-semantics/" } -lru = { version = "0.11.0" } +http-cache-semantics = { path = "../submodules/rusty-http-cache-semantics/", optional = true } +lru = { version = "0.11.0", optional = true } # cookie handling for sticky cookie chrono = { version = "0.4.26", default-features = false, features = [ diff --git a/rpxy-lib/src/constants.rs b/rpxy-lib/src/constants.rs index b7b0bff..510836a 100644 --- a/rpxy-lib/src/constants.rs +++ b/rpxy-lib/src/constants.rs @@ -31,3 +31,12 @@ pub mod H3 { #[cfg(feature = "sticky-cookie")] /// For load-balancing with sticky cookie pub const STICKY_COOKIE_NAME: &str = "rpxy_srv_id"; + +#[cfg(feature = "cache")] +// # of entries in cache +pub const MAX_CACHE_ENTRY: usize = 1_000; +#[cfg(feature = "cache")] +// max size for each file in bytes +pub const MAX_CACHE_EACH_SIZE: usize = 65_535; + +// TODO: max cache size in total diff --git a/rpxy-lib/src/globals.rs b/rpxy-lib/src/globals.rs index 8a782b6..6f2efb0 100644 --- a/rpxy-lib/src/globals.rs +++ b/rpxy-lib/src/globals.rs @@ -9,11 +9,11 @@ use crate::{ utils::{BytesName, PathNameBytesExp}, }; use rustc_hash::FxHashMap as HashMap; +use std::net::SocketAddr; use std::sync::{ atomic::{AtomicUsize, Ordering}, Arc, }; -use std::{net::SocketAddr, path::PathBuf}; use tokio::time::Duration; /// Global object containing proxy configurations and shared object like counters. @@ -53,10 +53,14 @@ pub struct ProxyConfig { // experimentals pub sni_consistency: bool, // Handler + #[cfg(feature = "cache")] pub cache_enabled: bool, - pub cache_dir: Option, - pub cache_max_entry: Option, - pub cache_max_each_size: Option, + #[cfg(feature = "cache")] + pub cache_dir: Option, + #[cfg(feature = "cache")] + pub cache_max_entry: usize, + #[cfg(feature = "cache")] + pub cache_max_each_size: usize, // All need to make packet acceptor #[cfg(any(feature = "http3-quinn", feature = "http3-s2n"))] @@ -93,10 +97,14 @@ impl Default for ProxyConfig { sni_consistency: true, + #[cfg(feature = "cache")] cache_enabled: false, + #[cfg(feature = "cache")] cache_dir: None, - cache_max_entry: None, - cache_max_each_size: None, + #[cfg(feature = "cache")] + cache_max_entry: MAX_CACHE_ENTRY, + #[cfg(feature = "cache")] + cache_max_each_size: MAX_CACHE_EACH_SIZE, #[cfg(any(feature = "http3-quinn", feature = "http3-s2n"))] http3: false, diff --git a/rpxy-lib/src/handler/cache.rs b/rpxy-lib/src/handler/cache.rs index c676c45..ce8aac4 100644 --- a/rpxy-lib/src/handler/cache.rs +++ b/rpxy-lib/src/handler/cache.rs @@ -121,14 +121,14 @@ impl RpxyCache { let path = globals.proxy_config.cache_dir.as_ref().unwrap(); let cache_file_manager = Arc::new(RwLock::new(CacheFileManager::new(path, &globals.runtime_handle).await)); let inner = Arc::new(Mutex::new(LruCache::new( - std::num::NonZeroUsize::new(globals.proxy_config.cache_max_entry.unwrap()).unwrap(), + std::num::NonZeroUsize::new(globals.proxy_config.cache_max_entry).unwrap(), ))); Some(Self { cache_file_manager, inner, runtime_handle: globals.runtime_handle.clone(), - max_each_size: globals.proxy_config.cache_max_each_size.unwrap(), + max_each_size: globals.proxy_config.cache_max_each_size, }) } diff --git a/rpxy-lib/src/handler/forwarder.rs b/rpxy-lib/src/handler/forwarder.rs index ed480bf..ce49433 100644 --- a/rpxy-lib/src/handler/forwarder.rs +++ b/rpxy-lib/src/handler/forwarder.rs @@ -1,8 +1,11 @@ +#[cfg(feature = "cache")] use super::cache::{get_policy_if_cacheable, RpxyCache}; -use crate::{error::RpxyError, globals::Globals, log::*, CryptoSource}; +#[cfg(feature = "cache")] +use crate::log::*; +use crate::{error::RpxyError, globals::Globals, CryptoSource}; use async_trait::async_trait; +#[cfg(feature = "cache")] use bytes::Buf; -use derive_builder::Builder; use hyper::{ body::{Body, HttpBody}, client::{connect::Connect, HttpConnector}, @@ -11,6 +14,8 @@ use hyper::{ }; use hyper_rustls::HttpsConnector; +#[cfg(feature = "cache")] +/// Build synthetic request to cache fn build_synth_req_for_cache(req: &Request) -> Request<()> { let mut builder = Request::builder() .method(req.method()) @@ -30,12 +35,12 @@ pub trait ForwardRequest { async fn request(&self, req: Request) -> Result, Self::Error>; } -#[derive(Builder, Clone)] /// Forwarder struct responsible to cache handling pub struct Forwarder where C: Connect + Clone + Sync + Send + 'static, { + #[cfg(feature = "cache")] cache: Option, inner: Client, inner_h2: Client, // `h2c` or http/2-only client is defined separately @@ -50,6 +55,8 @@ where C: Connect + Clone + Sync + Send + 'static, { type Error = RpxyError; + + #[cfg(feature = "cache")] async fn request(&self, req: Request) -> Result, Self::Error> { let mut synth_req = None; if self.cache.is_some() { @@ -99,10 +106,19 @@ where // res Ok(Response::from_parts(parts, Body::from(aggregated))) } + + #[cfg(not(feature = "cache"))] + async fn request(&self, req: Request) -> Result, Self::Error> { + match req.version() { + Version::HTTP_2 => self.inner_h2.request(req).await.map_err(RpxyError::Hyper), // handles `h2c` requests + _ => self.inner.request(req).await.map_err(RpxyError::Hyper), + } + } } impl Forwarder, Body> { - pub async fn new(globals: &std::sync::Arc>) -> Self { + /// Build forwarder + pub async fn new(_globals: &std::sync::Arc>) -> Self { // let connector = TrustDnsResolver::default().into_rustls_webpki_https_connector(); let connector = hyper_rustls::HttpsConnectorBuilder::new() .with_webpki_roots() @@ -119,7 +135,12 @@ impl Forwarder, Body> { let inner = Client::builder().build::<_, Body>(connector); let inner_h2 = Client::builder().http2_only(true).build::<_, Body>(connector_h2); - let cache = RpxyCache::new(globals).await; - Self { inner, inner_h2, cache } + #[cfg(feature = "cache")] + { + let cache = RpxyCache::new(_globals).await; + Self { inner, inner_h2, cache } + } + #[cfg(not(feature = "cache"))] + Self { inner, inner_h2 } } } diff --git a/rpxy-lib/src/handler/mod.rs b/rpxy-lib/src/handler/mod.rs index f2d3e43..84e0226 100644 --- a/rpxy-lib/src/handler/mod.rs +++ b/rpxy-lib/src/handler/mod.rs @@ -1,3 +1,4 @@ +#[cfg(feature = "cache")] mod cache; mod forwarder; mod handler_main; diff --git a/rpxy-lib/src/lib.rs b/rpxy-lib/src/lib.rs index 0596625..fd242c5 100644 --- a/rpxy-lib/src/lib.rs +++ b/rpxy-lib/src/lib.rs @@ -60,11 +60,14 @@ where if !proxy_config.sni_consistency { info!("Ignore consistency between TLS SNI and Host header (or Request line). Note it violates RFC."); } + #[cfg(feature = "cache")] if proxy_config.cache_enabled { info!( "Cache is enabled: cache dir = {:?}", proxy_config.cache_dir.as_ref().unwrap() ); + } else { + info!("Cache is disabled") } // build global