You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
51 lines
1.5 KiB
51 lines
1.5 KiB
use crate::error::unexpected;
|
|
use std::net;
|
|
|
|
use hyper::body::Incoming;
|
|
use hyper_reverse_proxy::ReverseProxy;
|
|
use hyper_util::client::legacy::connect::HttpConnector;
|
|
use hyper_util::rt::TokioExecutor;
|
|
|
|
fn proxy_client() -> &'static ReverseProxy<HttpConnector> {
|
|
use std::sync::OnceLock;
|
|
static PROXY_CLIENT: OnceLock<ReverseProxy<HttpConnector>> = OnceLock::new();
|
|
PROXY_CLIENT.get_or_init(|| {
|
|
ReverseProxy::new(
|
|
hyper_util::client::legacy::Builder::new(TokioExecutor::new())
|
|
.build::<_, Incoming>(HttpConnector::new()),
|
|
)
|
|
})
|
|
}
|
|
|
|
pub async fn serve_http_request(
|
|
proxy_addr: &str,
|
|
headers: &http::header::HeaderMap,
|
|
client_ip: net::IpAddr,
|
|
mut req: hyper::Request<Incoming>,
|
|
req_is_https: bool,
|
|
) -> unexpected::Result<hyper::Response<Incoming>> {
|
|
for (name, value) in headers {
|
|
if value.is_empty() {
|
|
req.headers_mut().remove(name);
|
|
continue;
|
|
}
|
|
|
|
req.headers_mut().insert(name, value.clone());
|
|
}
|
|
|
|
if req_is_https {
|
|
req.headers_mut().insert(
|
|
"x-forwarded-proto",
|
|
http::header::HeaderValue::from_static("https"),
|
|
);
|
|
}
|
|
|
|
match proxy_client().call(client_ip, proxy_addr, req).await {
|
|
Ok(res) => Ok(res),
|
|
// 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 to {proxy_addr}: {e:?}").as_str(),
|
|
)),
|
|
}
|
|
}
|
|
|