From 7bd904063707300f8421ef1864d7dc1940df3589 Mon Sep 17 00:00:00 2001 From: Jun Kurihara Date: Thu, 28 Jul 2022 20:45:22 +0900 Subject: [PATCH] use bytesname trait to explicitly convert &str/string to ascii lower-cased byte names of server / path --- src/backend/mod.rs | 10 ++++----- src/backend/upstream.rs | 5 ++--- src/config/parse.rs | 17 +++++++-------- src/handler/handler_main.rs | 7 +------ src/main.rs | 3 ++- src/proxy/proxy_h3.rs | 2 +- src/proxy/proxy_main.rs | 3 +-- src/proxy/proxy_tls.rs | 6 +++--- src/utils/bytes_name.rs | 41 ++++++++++++++++++++++--------------- src/utils/mod.rs | 1 + 10 files changed, 49 insertions(+), 46 deletions(-) diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 08577a0..3d042fe 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -1,7 +1,10 @@ mod upstream; mod upstream_opts; -use crate::log::*; +use crate::{ + log::*, + utils::{BytesName, PathNameBytesExp, ServerNameBytesExp}, +}; use rustc_hash::FxHashMap as HashMap; use std::{ fs::File, @@ -17,11 +20,6 @@ use tokio_rustls::rustls::{ pub use upstream::{ReverseProxy, Upstream, UpstreamGroup}; pub use upstream_opts::UpstreamOption; -// Server name (hostname or ip address) and path name representation in backends -// For searching hashmap or key list by exact or longest-prefix matching -pub type ServerNameBytesExp = Vec; // lowercase ascii bytes -pub type PathNameBytesExp = Vec; // lowercase ascii bytes - /// Struct serving information to route incoming connections, like server name to be handled and tls certs/keys settings. pub struct Backend { pub app_name: String, diff --git a/src/backend/upstream.rs b/src/backend/upstream.rs index 03a3648..4c588f9 100644 --- a/src/backend/upstream.rs +++ b/src/backend/upstream.rs @@ -1,4 +1,4 @@ -use super::{PathNameBytesExp, UpstreamOption}; +use super::{BytesName, PathNameBytesExp, UpstreamOption}; use crate::log::*; use rand::Rng; use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet}; @@ -19,8 +19,7 @@ impl ReverseProxy { pub fn get<'a>(&self, path_str: impl Into>) -> Option<&UpstreamGroup> { // trie使ってlongest prefix match させてもいいけどルート記述は少ないと思われるので、 // コスト的にこの程度で十分 - let path_lc = path_str.into().to_ascii_lowercase(); - let path_bytes = path_lc.as_bytes(); + let path_bytes = &(path_str.to_path_name_vec())[..]; let matched_upstream = self .upstream diff --git a/src/config/parse.rs b/src/config/parse.rs index 2475336..9f1d289 100644 --- a/src/config/parse.rs +++ b/src/config/parse.rs @@ -1,10 +1,11 @@ use super::toml::{ConfigToml, ReverseProxyOption}; use crate::{ - backend::{Backend, PathNameBytesExp, ReverseProxy, UpstreamGroup, UpstreamOption}, + backend::{Backend, ReverseProxy, UpstreamGroup, UpstreamOption}, constants::*, error::*, globals::*, log::*, + utils::{BytesName, PathNameBytesExp}, }; use clap::Arg; use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet}; @@ -91,7 +92,7 @@ pub fn parse_opts(globals: &mut Globals) -> std::result::Result<(), anyhow::Erro // each app for (app_name, app) in apps.0.iter() { ensure!(app.server_name.is_some(), "Missing server_name"); - let server_name = app.server_name.as_ref().unwrap().to_ascii_lowercase(); + let server_name_string = app.server_name.as_ref().unwrap(); // TLS settings let (tls_cert_path, tls_cert_key_path, https_redirection) = if app.tls.is_none() { @@ -122,10 +123,10 @@ pub fn parse_opts(globals: &mut Globals) -> std::result::Result<(), anyhow::Erro let reverse_proxy = get_reverse_proxy(app.reverse_proxy.as_ref().unwrap())?; globals.backends.apps.insert( - server_name.as_bytes().to_vec(), + server_name_string.to_server_name_vec(), Backend { app_name: app_name.to_owned(), - server_name: server_name.to_owned(), + server_name: server_name_string.to_ascii_lowercase(), reverse_proxy, tls_cert_path, @@ -133,7 +134,7 @@ pub fn parse_opts(globals: &mut Globals) -> std::result::Result<(), anyhow::Erro https_redirection, }, ); - info!("Registering application: {} ({})", app_name, server_name); + info!("Registering application: {} ({})", app_name, server_name_string); } // default backend application for plaintext http requests @@ -194,8 +195,8 @@ fn get_reverse_proxy(rp_settings: &[ReverseProxyOption]) -> std::result::Result< let mut upstream: HashMap = HashMap::default(); rp_settings.iter().for_each(|rpo| { let path = match &rpo.path { - Some(p) => p.as_bytes().to_ascii_lowercase(), - None => "/".as_bytes().to_ascii_lowercase(), + Some(p) => p.to_path_name_vec(), + None => "/".to_path_name_vec(), }; let elem = UpstreamGroup { @@ -204,7 +205,7 @@ fn get_reverse_proxy(rp_settings: &[ReverseProxyOption]) -> std::result::Result< replace_path: rpo .replace_path .as_ref() - .map_or_else(|| None, |v| Some(v.as_bytes().to_ascii_lowercase())), + .map_or_else(|| None, |v| Some(v.to_path_name_vec())), cnt: Default::default(), lb: Default::default(), opts: { diff --git a/src/handler/handler_main.rs b/src/handler/handler_main.rs index d2c1e30..373c363 100644 --- a/src/handler/handler_main.rs +++ b/src/handler/handler_main.rs @@ -1,11 +1,6 @@ // Highly motivated by https://github.com/felipenoris/hyper-reverse-proxy use super::{utils_headers::*, utils_request::*, utils_synth_response::*}; -use crate::{ - backend::{ServerNameBytesExp, UpstreamGroup}, - error::*, - globals::Globals, - log::*, -}; +use crate::{backend::UpstreamGroup, error::*, globals::Globals, log::*, utils::ServerNameBytesExp}; use hyper::{ client::connect::Connect, header::{self, HeaderValue}, diff --git a/src/main.rs b/src/main.rs index 92e2ba1..e4cf195 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,13 +16,14 @@ mod proxy; mod utils; use crate::{ - backend::{Backend, Backends, ServerNameBytesExp}, + backend::{Backend, Backends}, config::parse_opts, constants::*, error::*, globals::*, log::*, proxy::Proxy, + utils::ServerNameBytesExp, }; use futures::future::select_all; use handler::HttpMessageHandler; diff --git a/src/proxy/proxy_h3.rs b/src/proxy/proxy_h3.rs index 9efce98..1de5545 100644 --- a/src/proxy/proxy_h3.rs +++ b/src/proxy/proxy_h3.rs @@ -1,5 +1,5 @@ use super::Proxy; -use crate::{backend::ServerNameBytesExp, error::*, log::*}; +use crate::{error::*, log::*, utils::ServerNameBytesExp}; use bytes::{Buf, Bytes}; use h3::{quic::BidiStream, server::RequestStream}; use hyper::{client::connect::Connect, Body, Request, Response}; diff --git a/src/proxy/proxy_main.rs b/src/proxy/proxy_main.rs index 4b823ab..964ad70 100644 --- a/src/proxy/proxy_main.rs +++ b/src/proxy/proxy_main.rs @@ -1,5 +1,5 @@ // use super::proxy_handler::handle_request; -use crate::{backend::ServerNameBytesExp, error::*, globals::Globals, handler::HttpMessageHandler, log::*}; +use crate::{error::*, globals::Globals, handler::HttpMessageHandler, log::*, utils::ServerNameBytesExp}; use hyper::{client::connect::Connect, server::conn::Http, service::service_fn, Body, Request}; use std::{net::SocketAddr, sync::Arc}; use tokio::{ @@ -61,7 +61,6 @@ where } debug!("Request incoming: current # {}", request_count.current()); - // let inner = tls_server_name.map_or_else(|| None, |v| Some(v.as_bytes().to_ascii_lowercase())); self.globals.runtime_handle.clone().spawn(async move { timeout( self.globals.proxy_timeout + Duration::from_secs(1), diff --git a/src/proxy/proxy_tls.rs b/src/proxy/proxy_tls.rs index 835fb6f..0e63a10 100644 --- a/src/proxy/proxy_tls.rs +++ b/src/proxy/proxy_tls.rs @@ -1,5 +1,5 @@ use super::proxy_main::{LocalExecutor, Proxy}; -use crate::{constants::*, error::*, log::*}; +use crate::{constants::*, error::*, log::*, utils::BytesName}; use hyper::{client::connect::Connect, server::conn::Http}; use rustls::ServerConfig; use std::sync::Arc; @@ -66,7 +66,7 @@ where let (_, conn) = stream.get_ref(); let server_name = conn.sni_hostname(); debug!("HTTP/2 or 1.1: SNI in ClientHello: {:?}", server_name); - let server_name = server_name.map_or_else(|| None, |v| Some(v.as_bytes().to_ascii_lowercase())); + let server_name = server_name.map_or_else(|| None, |v| Some(v.to_server_name_vec())); if server_name.is_none(){ Err(anyhow!("No SNI is given")) } else { @@ -140,7 +140,7 @@ where Err(_) => continue }; let new_server_name = match hsd_downcast.server_name { - Some(sn) => sn.as_bytes().to_ascii_lowercase(), + Some(sn) => sn.to_server_name_vec(), None => { warn!("HTTP/3 no SNI is given"); continue; diff --git a/src/utils/bytes_name.rs b/src/utils/bytes_name.rs index e8af08c..c7c8def 100644 --- a/src/utils/bytes_name.rs +++ b/src/utils/bytes_name.rs @@ -1,22 +1,31 @@ -use bytes::{Buf, Bytes}; +// Server name (hostname or ip address) and path name representation in backends +// For searching hashmap or key list by exact or longest-prefix matching +pub type ServerNameBytesExp = Vec; // lowercase ascii bytes + +// #[derive(Clone, Debug)] +// pub struct ServerNameBytesExp(Vec); + +pub type PathNameBytesExp = Vec; // lowercase ascii bytes pub trait BytesName { - type Output: Buf; - fn to_bytes(self) -> Self::Output; - fn to_ascii_lowercase_bytes(self) -> Self::Output; + type OutputSv: Send + Sync + 'static; + type OutputPath; + fn to_server_name_vec(self) -> Self::OutputSv; + fn to_path_name_vec(self) -> Self::OutputPath; } -impl> BytesName for T { - type Output = Bytes; +impl<'a, T: Into>> BytesName for T { + type OutputSv = ServerNameBytesExp; + type OutputPath = PathNameBytesExp; - fn to_bytes(self) -> Self::Output { - let b = self.into().bytes().collect::>(); - Bytes::from(b) + fn to_server_name_vec(self) -> Self::OutputSv { + let name = self.into().bytes().collect::>().to_ascii_lowercase(); + name } - fn to_ascii_lowercase_bytes(self) -> Self::Output { - let b = self.into().bytes().collect::>().to_ascii_lowercase(); - Bytes::from(b) + fn to_path_name_vec(self) -> Self::OutputPath { + let name = self.into().bytes().collect::>().to_ascii_lowercase(); + name } } @@ -26,10 +35,10 @@ mod tests { #[test] fn bytes_name_str_works() { let s = "OK_string"; - let bn = s.to_bytes(); - let bn_lc = s.to_ascii_lowercase_bytes(); + let bn = s.to_path_name_vec(); + let bn_lc = s.to_server_name_vec(); - assert_eq!(Bytes::from(s.as_bytes()), bn); - assert_eq!(Bytes::from("ok_string"), bn_lc); + assert_eq!(Vec::from(s.as_bytes()), bn); + assert_eq!(Vec::from(s.as_bytes()), bn_lc); } } diff --git a/src/utils/mod.rs b/src/utils/mod.rs index bdc2381..ed8d4ff 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,4 +1,5 @@ mod bytes_name; mod socket_addr; +pub use bytes_name::{BytesName, PathNameBytesExp, ServerNameBytesExp}; pub use socket_addr::ToCanonical;