use anyhow::Context;
use client_util::{get_client, ClientConfig};
use http::Request;
use hyper::header::{Entry, HeaderValue, ToStrError, COOKIE};
use serde::{Deserialize, Serialize};
use crate::client_ip::GetClientIp;
use crate::target::{IntoTarget, ReqBody};
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub struct ProxyPassConfig {
target: String,
#[serde(default)]
client: ClientConfig,
}
pub fn from_config(config: ProxyPassConfig) -> anyhow::Result<impl IntoTarget> {
let client = get_client(config.client.clone())?;
Ok(tower::service_fn(move |mut request: Request<ReqBody>| {
let client = client.clone();
let config = config.clone();
async move {
let client_ip = request.client_ip();
*request.version_mut() = http::Version::default();
if let Entry::Occupied(mut entry) = request.headers_mut().entry(COOKIE) {
if let Ok(new_val) = entry
.iter()
.map(|x| x.to_str())
.collect::<Result<Vec<_>, ToStrError>>()
.map(|x| x.join("; "))
{
entry.insert(HeaderValue::from_str(&new_val).unwrap());
}
}
let request_uri = request.uri().clone();
Ok::<_, anyhow::Error>(
crate::reverse_proxy::call(client_ip, &config.target, request, &client).await
.context(format!("proxying from {} to {}", &request_uri, &config.target))?
)
}
}))
}