73 lines
1.9 KiB
Rust
73 lines
1.9 KiB
Rust
use axum::http::{HeaderMap, Method};
|
|
use hyper::client::HttpConnector;
|
|
use hyper::http::uri;
|
|
use hyper::{header, Body, Client, Request, Response, Uri};
|
|
use thiserror::Error;
|
|
|
|
#[derive(Debug, Error)]
|
|
pub enum ProxyClientError {
|
|
#[error("Client error: {0}")]
|
|
ClientError(String),
|
|
#[error("URL error: {0}")]
|
|
UriError(#[from] uri::InvalidUri),
|
|
#[error("HTTP error: {0}")]
|
|
HttpError(#[from] axum::http::Error),
|
|
#[error("Hyper error: {0}")]
|
|
HyperError(#[from] hyper::Error),
|
|
}
|
|
|
|
pub struct ProxyClient {
|
|
pub client: Client<HttpConnector, Body>,
|
|
pub upstream: String,
|
|
}
|
|
|
|
impl ProxyClient {
|
|
pub fn new(upstream: String) -> ProxyClient {
|
|
let client = Client::builder().set_host(false).build_http();
|
|
|
|
ProxyClient { client, upstream }
|
|
}
|
|
|
|
pub async fn send(
|
|
&self,
|
|
host: &str,
|
|
path: &str,
|
|
method: Method,
|
|
body: Body,
|
|
headers_in: &HeaderMap,
|
|
) -> Result<Response<Body>, ProxyClientError> {
|
|
let mut builder = Request::builder();
|
|
|
|
let Some(headers) = builder.headers_mut() else {
|
|
return Err(ProxyClientError::ClientError("No headers".to_owned()));
|
|
};
|
|
|
|
*headers = headers_in.clone();
|
|
|
|
headers.insert(
|
|
header::HOST,
|
|
host.parse().map_err(|e| {
|
|
ProxyClientError::ClientError(format!("Invalid header value: {e:?}"))
|
|
})?,
|
|
);
|
|
|
|
let uri = format!("{}/{}", self.upstream, path)
|
|
.parse::<Uri>()
|
|
.map_err(ProxyClientError::UriError)?;
|
|
|
|
let request = builder
|
|
.method(method)
|
|
.uri(uri)
|
|
.body(body)
|
|
.map_err(ProxyClientError::HttpError)?;
|
|
|
|
let response = self
|
|
.client
|
|
.request(request)
|
|
.await
|
|
.map_err(ProxyClientError::HyperError)?;
|
|
|
|
Ok(response)
|
|
}
|
|
}
|