use bytesname trait to explicitly convert &str/string to ascii lower-cased byte names of server / path
This commit is contained in:
parent
4d590f328f
commit
7bd9040637
10 changed files with 49 additions and 46 deletions
|
|
@ -1,7 +1,10 @@
|
||||||
mod upstream;
|
mod upstream;
|
||||||
mod upstream_opts;
|
mod upstream_opts;
|
||||||
|
|
||||||
use crate::log::*;
|
use crate::{
|
||||||
|
log::*,
|
||||||
|
utils::{BytesName, PathNameBytesExp, ServerNameBytesExp},
|
||||||
|
};
|
||||||
use rustc_hash::FxHashMap as HashMap;
|
use rustc_hash::FxHashMap as HashMap;
|
||||||
use std::{
|
use std::{
|
||||||
fs::File,
|
fs::File,
|
||||||
|
|
@ -17,11 +20,6 @@ use tokio_rustls::rustls::{
|
||||||
pub use upstream::{ReverseProxy, Upstream, UpstreamGroup};
|
pub use upstream::{ReverseProxy, Upstream, UpstreamGroup};
|
||||||
pub use upstream_opts::UpstreamOption;
|
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.
|
/// Struct serving information to route incoming connections, like server name to be handled and tls certs/keys settings.
|
||||||
pub struct Backend {
|
pub struct Backend {
|
||||||
pub app_name: String,
|
pub app_name: String,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{PathNameBytesExp, UpstreamOption};
|
use super::{BytesName, PathNameBytesExp, UpstreamOption};
|
||||||
use crate::log::*;
|
use crate::log::*;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet};
|
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> {
|
pub fn get<'a>(&self, path_str: impl Into<Cow<'a, str>>) -> Option<&UpstreamGroup> {
|
||||||
// trie使ってlongest prefix match させてもいいけどルート記述は少ないと思われるので、
|
// trie使ってlongest prefix match させてもいいけどルート記述は少ないと思われるので、
|
||||||
// コスト的にこの程度で十分
|
// コスト的にこの程度で十分
|
||||||
let path_lc = path_str.into().to_ascii_lowercase();
|
let path_bytes = &(path_str.to_path_name_vec())[..];
|
||||||
let path_bytes = path_lc.as_bytes();
|
|
||||||
|
|
||||||
let matched_upstream = self
|
let matched_upstream = self
|
||||||
.upstream
|
.upstream
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
use super::toml::{ConfigToml, ReverseProxyOption};
|
use super::toml::{ConfigToml, ReverseProxyOption};
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::{Backend, PathNameBytesExp, ReverseProxy, UpstreamGroup, UpstreamOption},
|
backend::{Backend, ReverseProxy, UpstreamGroup, UpstreamOption},
|
||||||
constants::*,
|
constants::*,
|
||||||
error::*,
|
error::*,
|
||||||
globals::*,
|
globals::*,
|
||||||
log::*,
|
log::*,
|
||||||
|
utils::{BytesName, PathNameBytesExp},
|
||||||
};
|
};
|
||||||
use clap::Arg;
|
use clap::Arg;
|
||||||
use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet};
|
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
|
// each app
|
||||||
for (app_name, app) in apps.0.iter() {
|
for (app_name, app) in apps.0.iter() {
|
||||||
ensure!(app.server_name.is_some(), "Missing server_name");
|
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
|
// TLS settings
|
||||||
let (tls_cert_path, tls_cert_key_path, https_redirection) = if app.tls.is_none() {
|
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())?;
|
let reverse_proxy = get_reverse_proxy(app.reverse_proxy.as_ref().unwrap())?;
|
||||||
|
|
||||||
globals.backends.apps.insert(
|
globals.backends.apps.insert(
|
||||||
server_name.as_bytes().to_vec(),
|
server_name_string.to_server_name_vec(),
|
||||||
Backend {
|
Backend {
|
||||||
app_name: app_name.to_owned(),
|
app_name: app_name.to_owned(),
|
||||||
server_name: server_name.to_owned(),
|
server_name: server_name_string.to_ascii_lowercase(),
|
||||||
reverse_proxy,
|
reverse_proxy,
|
||||||
|
|
||||||
tls_cert_path,
|
tls_cert_path,
|
||||||
|
|
@ -133,7 +134,7 @@ pub fn parse_opts(globals: &mut Globals) -> std::result::Result<(), anyhow::Erro
|
||||||
https_redirection,
|
https_redirection,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
info!("Registering application: {} ({})", app_name, server_name);
|
info!("Registering application: {} ({})", app_name, server_name_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
// default backend application for plaintext http requests
|
// 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();
|
let mut upstream: HashMap<PathNameBytesExp, UpstreamGroup> = HashMap::default();
|
||||||
rp_settings.iter().for_each(|rpo| {
|
rp_settings.iter().for_each(|rpo| {
|
||||||
let path = match &rpo.path {
|
let path = match &rpo.path {
|
||||||
Some(p) => p.as_bytes().to_ascii_lowercase(),
|
Some(p) => p.to_path_name_vec(),
|
||||||
None => "/".as_bytes().to_ascii_lowercase(),
|
None => "/".to_path_name_vec(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let elem = UpstreamGroup {
|
let elem = UpstreamGroup {
|
||||||
|
|
@ -204,7 +205,7 @@ fn get_reverse_proxy(rp_settings: &[ReverseProxyOption]) -> std::result::Result<
|
||||||
replace_path: rpo
|
replace_path: rpo
|
||||||
.replace_path
|
.replace_path
|
||||||
.as_ref()
|
.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(),
|
cnt: Default::default(),
|
||||||
lb: Default::default(),
|
lb: Default::default(),
|
||||||
opts: {
|
opts: {
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,6 @@
|
||||||
// Highly motivated by https://github.com/felipenoris/hyper-reverse-proxy
|
// Highly motivated by https://github.com/felipenoris/hyper-reverse-proxy
|
||||||
use super::{utils_headers::*, utils_request::*, utils_synth_response::*};
|
use super::{utils_headers::*, utils_request::*, utils_synth_response::*};
|
||||||
use crate::{
|
use crate::{backend::UpstreamGroup, error::*, globals::Globals, log::*, utils::ServerNameBytesExp};
|
||||||
backend::{ServerNameBytesExp, UpstreamGroup},
|
|
||||||
error::*,
|
|
||||||
globals::Globals,
|
|
||||||
log::*,
|
|
||||||
};
|
|
||||||
use hyper::{
|
use hyper::{
|
||||||
client::connect::Connect,
|
client::connect::Connect,
|
||||||
header::{self, HeaderValue},
|
header::{self, HeaderValue},
|
||||||
|
|
|
||||||
|
|
@ -16,13 +16,14 @@ mod proxy;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::{Backend, Backends, ServerNameBytesExp},
|
backend::{Backend, Backends},
|
||||||
config::parse_opts,
|
config::parse_opts,
|
||||||
constants::*,
|
constants::*,
|
||||||
error::*,
|
error::*,
|
||||||
globals::*,
|
globals::*,
|
||||||
log::*,
|
log::*,
|
||||||
proxy::Proxy,
|
proxy::Proxy,
|
||||||
|
utils::ServerNameBytesExp,
|
||||||
};
|
};
|
||||||
use futures::future::select_all;
|
use futures::future::select_all;
|
||||||
use handler::HttpMessageHandler;
|
use handler::HttpMessageHandler;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use super::Proxy;
|
use super::Proxy;
|
||||||
use crate::{backend::ServerNameBytesExp, error::*, log::*};
|
use crate::{error::*, log::*, utils::ServerNameBytesExp};
|
||||||
use bytes::{Buf, Bytes};
|
use bytes::{Buf, Bytes};
|
||||||
use h3::{quic::BidiStream, server::RequestStream};
|
use h3::{quic::BidiStream, server::RequestStream};
|
||||||
use hyper::{client::connect::Connect, Body, Request, Response};
|
use hyper::{client::connect::Connect, Body, Request, Response};
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// use super::proxy_handler::handle_request;
|
// 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 hyper::{client::connect::Connect, server::conn::Http, service::service_fn, Body, Request};
|
||||||
use std::{net::SocketAddr, sync::Arc};
|
use std::{net::SocketAddr, sync::Arc};
|
||||||
use tokio::{
|
use tokio::{
|
||||||
|
|
@ -61,7 +61,6 @@ where
|
||||||
}
|
}
|
||||||
debug!("Request incoming: current # {}", request_count.current());
|
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 {
|
self.globals.runtime_handle.clone().spawn(async move {
|
||||||
timeout(
|
timeout(
|
||||||
self.globals.proxy_timeout + Duration::from_secs(1),
|
self.globals.proxy_timeout + Duration::from_secs(1),
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use super::proxy_main::{LocalExecutor, Proxy};
|
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 hyper::{client::connect::Connect, server::conn::Http};
|
||||||
use rustls::ServerConfig;
|
use rustls::ServerConfig;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
@ -66,7 +66,7 @@ where
|
||||||
let (_, conn) = stream.get_ref();
|
let (_, conn) = stream.get_ref();
|
||||||
let server_name = conn.sni_hostname();
|
let server_name = conn.sni_hostname();
|
||||||
debug!("HTTP/2 or 1.1: SNI in ClientHello: {:?}", server_name);
|
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(){
|
if server_name.is_none(){
|
||||||
Err(anyhow!("No SNI is given"))
|
Err(anyhow!("No SNI is given"))
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -140,7 +140,7 @@ where
|
||||||
Err(_) => continue
|
Err(_) => continue
|
||||||
};
|
};
|
||||||
let new_server_name = match hsd_downcast.server_name {
|
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 => {
|
None => {
|
||||||
warn!("HTTP/3 no SNI is given");
|
warn!("HTTP/3 no SNI is given");
|
||||||
continue;
|
continue;
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
pub trait BytesName {
|
||||||
type Output: Buf;
|
type OutputSv: Send + Sync + 'static;
|
||||||
fn to_bytes(self) -> Self::Output;
|
type OutputPath;
|
||||||
fn to_ascii_lowercase_bytes(self) -> Self::Output;
|
fn to_server_name_vec(self) -> Self::OutputSv;
|
||||||
|
fn to_path_name_vec(self) -> Self::OutputPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Into<String>> BytesName for T {
|
impl<'a, T: Into<std::borrow::Cow<'a, str>>> BytesName for T {
|
||||||
type Output = Bytes;
|
type OutputSv = ServerNameBytesExp;
|
||||||
|
type OutputPath = PathNameBytesExp;
|
||||||
|
|
||||||
fn to_bytes(self) -> Self::Output {
|
fn to_server_name_vec(self) -> Self::OutputSv {
|
||||||
let b = self.into().bytes().collect::<Vec<u8>>();
|
let name = self.into().bytes().collect::<Vec<u8>>().to_ascii_lowercase();
|
||||||
Bytes::from(b)
|
name
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_ascii_lowercase_bytes(self) -> Self::Output {
|
fn to_path_name_vec(self) -> Self::OutputPath {
|
||||||
let b = self.into().bytes().collect::<Vec<u8>>().to_ascii_lowercase();
|
let name = self.into().bytes().collect::<Vec<u8>>().to_ascii_lowercase();
|
||||||
Bytes::from(b)
|
name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -26,10 +35,10 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn bytes_name_str_works() {
|
fn bytes_name_str_works() {
|
||||||
let s = "OK_string";
|
let s = "OK_string";
|
||||||
let bn = s.to_bytes();
|
let bn = s.to_path_name_vec();
|
||||||
let bn_lc = s.to_ascii_lowercase_bytes();
|
let bn_lc = s.to_server_name_vec();
|
||||||
|
|
||||||
assert_eq!(Bytes::from(s.as_bytes()), bn);
|
assert_eq!(Vec::from(s.as_bytes()), bn);
|
||||||
assert_eq!(Bytes::from("ok_string"), bn_lc);
|
assert_eq!(Vec::from(s.as_bytes()), bn_lc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
mod bytes_name;
|
mod bytes_name;
|
||||||
mod socket_addr;
|
mod socket_addr;
|
||||||
|
|
||||||
|
pub use bytes_name::{BytesName, PathNameBytesExp, ServerNameBytesExp};
|
||||||
pub use socket_addr::ToCanonical;
|
pub use socket_addr::ToCanonical;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue