reconsider error and introduce custom error using thiserror
This commit is contained in:
parent
a0aed6d848
commit
6d41830eba
8 changed files with 61 additions and 27 deletions
|
|
@ -52,6 +52,7 @@ bytes = "1.2.0"
|
||||||
quinn = { version = "0.8.3", optional = true }
|
quinn = { version = "0.8.3", optional = true }
|
||||||
h3 = { git = "https://github.com/hyperium/h3.git", optional = true }
|
h3 = { git = "https://github.com/hyperium/h3.git", optional = true }
|
||||||
h3-quinn = { git = "https://github.com/hyperium/h3.git", optional = true }
|
h3-quinn = { git = "https://github.com/hyperium/h3.git", optional = true }
|
||||||
|
thiserror = "1.0.31"
|
||||||
|
|
||||||
|
|
||||||
[target.'cfg(not(target_env = "msvc"))'.dependencies]
|
[target.'cfg(not(target_env = "msvc"))'.dependencies]
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,12 @@ pub enum UpstreamOption {
|
||||||
// TODO: Adds more options for heder override
|
// TODO: Adds more options for heder override
|
||||||
}
|
}
|
||||||
impl TryFrom<&str> for UpstreamOption {
|
impl TryFrom<&str> for UpstreamOption {
|
||||||
type Error = anyhow::Error;
|
type Error = RpxyError;
|
||||||
fn try_from(val: &str) -> Result<Self> {
|
fn try_from(val: &str) -> Result<Self> {
|
||||||
match val {
|
match val {
|
||||||
"override_host" => Ok(Self::OverrideHost),
|
"override_host" => Ok(Self::OverrideHost),
|
||||||
"upgrade_insecure_requests" => Ok(Self::UpgradeInsecureRequests),
|
"upgrade_insecure_requests" => Ok(Self::UpgradeInsecureRequests),
|
||||||
_ => Err(anyhow!("Unsupported header option")),
|
_ => Err(RpxyError::Other(anyhow!("Unsupported header option"))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ use std::net::SocketAddr;
|
||||||
// #[cfg(feature = "tls")]
|
// #[cfg(feature = "tls")]
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
pub fn parse_opts(globals: &mut Globals) -> Result<()> {
|
pub fn parse_opts(globals: &mut Globals) -> std::result::Result<(), anyhow::Error> {
|
||||||
let _ = include_str!("../../Cargo.toml");
|
let _ = include_str!("../../Cargo.toml");
|
||||||
let options = clap::command!().arg(
|
let options = clap::command!().arg(
|
||||||
Arg::new("config_file")
|
Arg::new("config_file")
|
||||||
|
|
@ -191,7 +191,7 @@ pub fn parse_opts(globals: &mut Globals) -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_reverse_proxy(rp_settings: &[ReverseProxyOption]) -> Result<ReverseProxy> {
|
fn get_reverse_proxy(rp_settings: &[ReverseProxyOption]) -> std::result::Result<ReverseProxy, anyhow::Error> {
|
||||||
let mut upstream: HashMap<PathNameLC, UpstreamGroup> = HashMap::default();
|
let mut upstream: HashMap<PathNameLC, 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 {
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ impl UpstreamParams {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConfigToml {
|
impl ConfigToml {
|
||||||
pub fn new(config_file: &str) -> Result<Self> {
|
pub fn new(config_file: &str) -> std::result::Result<Self, anyhow::Error> {
|
||||||
let config_str = fs::read_to_string(config_file).context("Failed to read config file")?;
|
let config_str = fs::read_to_string(config_file).context("Failed to read config file")?;
|
||||||
|
|
||||||
toml::from_str(&config_str).context("Failed to parse toml config")
|
toml::from_str(&config_str).context("Failed to parse toml config")
|
||||||
|
|
|
||||||
52
src/error.rs
52
src/error.rs
|
|
@ -1,12 +1,42 @@
|
||||||
pub use anyhow::{anyhow, bail, ensure, Context, Result};
|
pub use anyhow::{anyhow, bail, ensure, Context};
|
||||||
// use thiserror::Error;
|
use std::io;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
// #[allow(clippy::enum_variant_names)]
|
pub type Result<T> = std::result::Result<T, RpxyError>;
|
||||||
// #[derive(Debug, Error)]
|
|
||||||
// pub enum RpxyError {
|
/// Describes things that can go wrong in the Rpxy
|
||||||
// // IoError,
|
#[derive(Debug, Error)]
|
||||||
// #[error("ConfigError: {0}")]
|
pub enum RpxyError {
|
||||||
// ConfigError(String),
|
#[error("Http Message Handler Error: {0}")]
|
||||||
// // ConnectionError,
|
Handler(&'static str),
|
||||||
// // HttpError,
|
|
||||||
// }
|
#[error("Http Request Message Error: {0}")]
|
||||||
|
Request(&'static str),
|
||||||
|
|
||||||
|
#[error("I/O Error")]
|
||||||
|
Io(#[from] io::Error),
|
||||||
|
|
||||||
|
#[error("Quic Connection Error")]
|
||||||
|
QuicConn(#[from] quinn::ConnectionError),
|
||||||
|
|
||||||
|
#[error("H3 Error")]
|
||||||
|
H3(#[from] h3::Error),
|
||||||
|
|
||||||
|
#[error("rustls Connection Error")]
|
||||||
|
Rustls(#[from] rustls::Error),
|
||||||
|
|
||||||
|
#[error("Hyper Error")]
|
||||||
|
Hyper(#[from] hyper::Error),
|
||||||
|
|
||||||
|
#[error("Hyper Http Error")]
|
||||||
|
HyperHttp(#[from] hyper::http::Error),
|
||||||
|
|
||||||
|
#[error("Hyper Http HeaderValue Error")]
|
||||||
|
HyperHeaderValue(#[from] hyper::header::InvalidHeaderValue),
|
||||||
|
|
||||||
|
#[error("Hyper Http HeaderName Error")]
|
||||||
|
HyperHeaderName(#[from] hyper::header::InvalidHeaderName),
|
||||||
|
|
||||||
|
#[error(transparent)]
|
||||||
|
Other(#[from] anyhow::Error),
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -263,7 +263,9 @@ where
|
||||||
apply_upstream_options_to_header(headers, client_addr, upstream_group, &upstream_chosen.uri)?;
|
apply_upstream_options_to_header(headers, client_addr, upstream_group, &upstream_chosen.uri)?;
|
||||||
|
|
||||||
// update uri in request
|
// update uri in request
|
||||||
ensure!(upstream_chosen.uri.authority().is_some() && upstream_chosen.uri.scheme().is_some());
|
if !(upstream_chosen.uri.authority().is_some() && upstream_chosen.uri.scheme().is_some()) {
|
||||||
|
return Err(RpxyError::Handler("Upstream uri `scheme` and `authority` is broken"));
|
||||||
|
};
|
||||||
let new_uri = Uri::builder()
|
let new_uri = Uri::builder()
|
||||||
.scheme(upstream_chosen.uri.scheme().unwrap().as_str())
|
.scheme(upstream_chosen.uri.scheme().unwrap().as_str())
|
||||||
.authority(upstream_chosen.uri.authority().unwrap().as_str());
|
.authority(upstream_chosen.uri.authority().unwrap().as_str());
|
||||||
|
|
@ -277,7 +279,9 @@ where
|
||||||
let new_pq = match &upstream_group.replace_path {
|
let new_pq = match &upstream_group.replace_path {
|
||||||
Some(new_path) => {
|
Some(new_path) => {
|
||||||
let matched_path: &[u8] = upstream_group.path.as_ref();
|
let matched_path: &[u8] = upstream_group.path.as_ref();
|
||||||
ensure!(!matched_path.is_empty() && org_pq.len() >= matched_path.len());
|
if matched_path.is_empty() || org_pq.len() < matched_path.len() {
|
||||||
|
return Err(RpxyError::Handler("Upstream uri `path and query` is broken"));
|
||||||
|
};
|
||||||
let mut new_pq = Vec::<u8>::with_capacity(org_pq.len() - matched_path.len() + new_path.len());
|
let mut new_pq = Vec::<u8>::with_capacity(org_pq.len() - matched_path.len() + new_path.len());
|
||||||
new_pq.extend_from_slice(new_path);
|
new_pq.extend_from_slice(new_path);
|
||||||
new_pq.extend_from_slice(&org_pq[matched_path.len()..]);
|
new_pq.extend_from_slice(&org_pq[matched_path.len()..]);
|
||||||
|
|
|
||||||
|
|
@ -63,10 +63,9 @@ impl<B> ParseHost for Request<B> {
|
||||||
let uri_host = self.uri().host();
|
let uri_host = self.uri().host();
|
||||||
// let uri_port = self.uri().port_u16();
|
// let uri_port = self.uri().port_u16();
|
||||||
|
|
||||||
ensure!(
|
if !(!(headers_host.is_none() && uri_host.is_none())) {
|
||||||
!(headers_host.is_none() && uri_host.is_none()),
|
return Err(RpxyError::Request("No host in request header"));
|
||||||
"No host in request header"
|
}
|
||||||
);
|
|
||||||
|
|
||||||
// prioritize server_name in uri
|
// prioritize server_name in uri
|
||||||
uri_host.map_or_else(
|
uri_host.map_or_else(
|
||||||
|
|
@ -75,8 +74,8 @@ impl<B> ParseHost for Request<B> {
|
||||||
if m.starts_with(&[b'[']) {
|
if m.starts_with(&[b'[']) {
|
||||||
// v6 address with bracket case. if port is specified, always it is in this case.
|
// v6 address with bracket case. if port is specified, always it is in this case.
|
||||||
let mut iter = m.split(|ptr| ptr == &b'[' || ptr == &b']');
|
let mut iter = m.split(|ptr| ptr == &b'[' || ptr == &b']');
|
||||||
iter.next().ok_or_else(|| anyhow!("Invalid Host"))?; // first item is always blank
|
iter.next().ok_or(RpxyError::Request("Invalid Host"))?; // first item is always blank
|
||||||
iter.next().ok_or_else(|| anyhow!("Invalid Host"))
|
iter.next().ok_or(RpxyError::Request("Invalid Host"))
|
||||||
} else if m.len() - m.split(|v| v == &b':').fold(0, |acc, s| acc + s.len()) >= 2 {
|
} else if m.len() - m.split(|v| v == &b':').fold(0, |acc, s| acc + s.len()) >= 2 {
|
||||||
// v6 address case, if 2 or more ':' is contained
|
// v6 address case, if 2 or more ':' is contained
|
||||||
Ok(m)
|
Ok(m)
|
||||||
|
|
@ -85,7 +84,7 @@ impl<B> ParseHost for Request<B> {
|
||||||
m.split(|colon| colon == &b':')
|
m.split(|colon| colon == &b':')
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.next()
|
.next()
|
||||||
.ok_or_else(|| anyhow!("Invalid Host"))
|
.ok_or(RpxyError::Request("Invalid Host"))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|v| Ok(v.as_bytes()),
|
|v| Ok(v.as_bytes()),
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ where
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
warn!("QUIC accepting connection failed: {:?}", err);
|
warn!("QUIC accepting connection failed: {:?}", err);
|
||||||
return Err(anyhow!("{}", err));
|
return Err(RpxyError::QuicConn(err));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -104,7 +104,7 @@ where
|
||||||
debug!("HTTP/3 incoming request trailers");
|
debug!("HTTP/3 incoming request trailers");
|
||||||
sender.send_trailers(trailers.unwrap()).await?;
|
sender.send_trailers(trailers.unwrap()).await?;
|
||||||
}
|
}
|
||||||
Ok(()) as Result<()>
|
Ok(())
|
||||||
});
|
});
|
||||||
|
|
||||||
let new_req: Request<Body> = Request::from_parts(req_parts, req_body);
|
let new_req: Request<Body> = Request::from_parts(req_parts, req_body);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue