use bytesname trait to explicitly convert &str/string to ascii lower-cased byte names of server / path

This commit is contained in:
Jun Kurihara 2022-07-28 20:45:22 +09:00
commit 7bd9040637
No known key found for this signature in database
GPG key ID: 48ADFD173ED22B03
10 changed files with 49 additions and 46 deletions

View file

@ -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<u8>; // lowercase ascii bytes
pub type PathNameBytesExp = Vec<u8>; // 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,

View file

@ -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<Cow<'a, str>>) -> 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

View file

@ -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<PathNameBytesExp, UpstreamGroup> = 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: {

View file

@ -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},

View file

@ -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;

View file

@ -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};

View file

@ -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),

View file

@ -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;

View file

@ -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<u8>; // lowercase ascii bytes
// #[derive(Clone, Debug)]
// pub struct ServerNameBytesExp(Vec<u8>);
pub type PathNameBytesExp = Vec<u8>; // 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<T: Into<String>> BytesName for T {
type Output = Bytes;
impl<'a, T: Into<std::borrow::Cow<'a, str>>> BytesName for T {
type OutputSv = ServerNameBytesExp;
type OutputPath = PathNameBytesExp;
fn to_bytes(self) -> Self::Output {
let b = self.into().bytes().collect::<Vec<u8>>();
Bytes::from(b)
fn to_server_name_vec(self) -> Self::OutputSv {
let name = self.into().bytes().collect::<Vec<u8>>().to_ascii_lowercase();
name
}
fn to_ascii_lowercase_bytes(self) -> Self::Output {
let b = self.into().bytes().collect::<Vec<u8>>().to_ascii_lowercase();
Bytes::from(b)
fn to_path_name_vec(self) -> Self::OutputPath {
let name = self.into().bytes().collect::<Vec<u8>>().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);
}
}

View file

@ -1,4 +1,5 @@
mod bytes_name;
mod socket_addr;
pub use bytes_name::{BytesName, PathNameBytesExp, ServerNameBytesExp};
pub use socket_addr::ToCanonical;