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