Pass the full domain::Settings into the proxy code
This commit is contained in:
parent
8f74757f23
commit
651f3f4bb7
@ -5,7 +5,7 @@ domain:
|
||||
builtins:
|
||||
foo:
|
||||
kind: proxy
|
||||
url: ok
|
||||
url: http://ok
|
||||
bar:
|
||||
kind: git
|
||||
url: a
|
||||
|
@ -32,9 +32,6 @@ pub enum GetFileError {
|
||||
#[error("file not found")]
|
||||
FileNotFound,
|
||||
|
||||
#[error("origin is of kind proxy")]
|
||||
OriginIsProxy { url: String },
|
||||
|
||||
#[error(transparent)]
|
||||
Unexpected(#[from] unexpected::Error),
|
||||
}
|
||||
@ -249,8 +246,8 @@ impl Manager for ManagerImpl {
|
||||
) -> Result<util::BoxByteStream, GetFileError> {
|
||||
let config = self.domain_store.get(domain)?;
|
||||
|
||||
if let origin::Descr::Proxy { url } = config.origin_descr {
|
||||
return Err(GetFileError::OriginIsProxy { url });
|
||||
if let origin::Descr::Proxy { .. } = config.origin_descr {
|
||||
return Err(unexpected::Error::from("origin is proxy, can't serve file").into());
|
||||
}
|
||||
|
||||
let f = self.origin_store.get_file(&config.origin_descr, path)?;
|
||||
|
@ -22,7 +22,7 @@ impl Error {
|
||||
let mut w = String::new();
|
||||
|
||||
if let Some(prefix) = prefix {
|
||||
write!(w, "{prefix}").expect("error writing prefix");
|
||||
write!(w, "{prefix}: ").expect("error writing prefix");
|
||||
}
|
||||
|
||||
write!(w, "{body}").expect("error formatting body");
|
||||
|
@ -78,6 +78,14 @@ async fn main() {
|
||||
config.service.dns_records.push(primary_cname);
|
||||
}
|
||||
|
||||
for (domain, builtin_domain) in &config.domain.builtins {
|
||||
if let domani::origin::Descr::Proxy { ref url } = builtin_domain.settings.origin_descr {
|
||||
if let Err(e) = domani::origin::proxy::validate_proxy_url(url) {
|
||||
panic!("invalid config for builtin domain {domain}: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
config
|
||||
};
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
use crate::error::unexpected::{self, Mappable};
|
||||
use crate::{domain, origin};
|
||||
use http::header::HeaderValue;
|
||||
use std::{net, str::FromStr};
|
||||
|
||||
@ -6,27 +7,43 @@ use std::{net, str::FromStr};
|
||||
// being served on, it can't be abstracted out into a simple "get_file" operation like other
|
||||
// origins.
|
||||
|
||||
pub fn validate_proxy_url(proxy_url: &str) -> unexpected::Result<()> {
|
||||
let parsed_proxy_url =
|
||||
http::Uri::from_str(proxy_url).or_unexpected_while("parsing proxy url {proxy_url}")?;
|
||||
|
||||
let scheme = parsed_proxy_url.scheme().map_unexpected_while(|| {
|
||||
format!("expected a scheme of http in the proxy url {proxy_url}")
|
||||
})?;
|
||||
|
||||
if scheme != "http" {
|
||||
return Err(unexpected::Error::from(
|
||||
format!("scheme of proxy url {proxy_url} should be 'http'",).as_str(),
|
||||
));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn serve_http_request(
|
||||
settings: &domain::Settings,
|
||||
client_ip: net::IpAddr,
|
||||
proxy_url: &str,
|
||||
mut req: hyper::Request<hyper::Body>,
|
||||
req_is_https: bool,
|
||||
) -> unexpected::Result<hyper::Response<hyper::Body>> {
|
||||
let parsed_proxy_url =
|
||||
http::Uri::from_str(proxy_url).or_unexpected_while("parsing proxy url")?;
|
||||
let proxy_url = if let origin::Descr::Proxy { ref url } = settings.origin_descr {
|
||||
url
|
||||
} else {
|
||||
panic!("non-proxy domain settings passed in: {settings:?}")
|
||||
};
|
||||
|
||||
let scheme = parsed_proxy_url
|
||||
.scheme()
|
||||
.or_unexpected_while("expected a scheme of http in the proxy url")?;
|
||||
if scheme != "http" {
|
||||
return Err(unexpected::Error::from("proxy url scheme should be 'http"));
|
||||
}
|
||||
let parsed_proxy_url =
|
||||
http::Uri::from_str(proxy_url).or_unexpected_while("parsing proxy url {proxy_url}")?;
|
||||
|
||||
// figure out what the host header should be, based on the host[:port] of the proxy_url
|
||||
let host = {
|
||||
let authority = parsed_proxy_url
|
||||
.authority()
|
||||
.or_unexpected_while("getting host from proxy url, there is no host")?;
|
||||
let authority = parsed_proxy_url.authority().or_unexpected_while(format!(
|
||||
"getting host from proxy url {proxy_url}, there is no host"
|
||||
))?;
|
||||
|
||||
let host_and_port;
|
||||
let mut host = authority.host();
|
||||
@ -51,7 +68,7 @@ pub async fn serve_http_request(
|
||||
// ProxyError doesn't actually implement Error :facepalm: so we have to format the error
|
||||
// manually
|
||||
Err(e) => Err(unexpected::Error::from(
|
||||
format!("error while proxying: {e:?}").as_str(),
|
||||
format!("error while proxying to {proxy_url}: {e:?}").as_str(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
@ -165,6 +165,33 @@ impl<'svc> Service {
|
||||
req: Request<Body>,
|
||||
req_is_https: bool,
|
||||
) -> Response<Body> {
|
||||
// first check if the domain is backed by a proxy, and deal with that first
|
||||
match self.domain_manager.get_settings(&domain) {
|
||||
Ok(settings) => {
|
||||
if let origin::Descr::Proxy { .. } = settings.origin_descr {
|
||||
return origin::proxy::serve_http_request(
|
||||
&settings,
|
||||
client_ip,
|
||||
req,
|
||||
req_is_https,
|
||||
)
|
||||
.await
|
||||
.unwrap_or_else(|e| {
|
||||
self.internal_error(format!("proxying {domain}: {e}").as_str())
|
||||
});
|
||||
}
|
||||
// fall out of match
|
||||
}
|
||||
Err(domain::manager::GetSettingsError::NotFound) => {
|
||||
return self.render_error_page(404, "Domain not found");
|
||||
}
|
||||
Err(domain::manager::GetSettingsError::Unexpected(e)) => {
|
||||
return self.internal_error(
|
||||
format!("failed to fetch settings for domain {domain}: {e}").as_str(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let mut path_owned;
|
||||
let path = req.uri().path();
|
||||
|
||||
@ -185,13 +212,6 @@ impl<'svc> Service {
|
||||
Err(domain::manager::GetFileError::FileNotFound) => {
|
||||
self.render_error_page(404, "File not found")
|
||||
}
|
||||
Err(domain::manager::GetFileError::OriginIsProxy { url }) => {
|
||||
origin::proxy::serve_http_request(client_ip, &url, req, req_is_https)
|
||||
.await
|
||||
.unwrap_or_else(|e| {
|
||||
self.internal_error(format!("proxying {domain} to {url}: {e}").as_str())
|
||||
})
|
||||
}
|
||||
Err(domain::manager::GetFileError::Unexpected(e)) => {
|
||||
self.internal_error(format!("failed to fetch file {path}: {e}").as_str())
|
||||
}
|
||||
@ -432,7 +452,7 @@ impl<'svc> Service {
|
||||
}
|
||||
}
|
||||
|
||||
// If a managed domain was given then serve that from its origin
|
||||
// If a managed domain was given then serve that from its origin, which is possibly a proxy
|
||||
if let Some(domain) = maybe_host {
|
||||
return self
|
||||
.serve_origin(client_ip, domain, req, req_is_https)
|
||||
|
Loading…
Reference in New Issue
Block a user