karbon_framework/http/
proxy.rs1use axum::{
2 body::Body,
3 extract::Request,
4 response::{IntoResponse, Response},
5};
6use hyper_util::{client::legacy::Client, rt::TokioExecutor};
7
8#[derive(Clone)]
13pub struct FrontendProxy {
14 target: String,
15 client: Client<hyper_util::client::legacy::connect::HttpConnector, Body>,
16}
17
18impl FrontendProxy {
19 pub fn new(target: &str) -> Self {
20 let client = Client::builder(TokioExecutor::new())
21 .build_http();
22
23 Self {
24 target: target.trim_end_matches('/').to_string(),
25 client,
26 }
27 }
28
29 pub async fn handle(self, req: Request) -> Response {
31 match self.proxy(req).await {
32 Ok(resp) => resp,
33 Err(e) => {
34 tracing::error!("Proxy error: {e}");
35 (
36 axum::http::StatusCode::BAD_GATEWAY,
37 "Bad gateway".to_string(),
38 )
39 .into_response()
40 }
41 }
42 }
43
44 async fn proxy(&self, req: Request) -> Result<Response, Box<dyn std::error::Error + Send + Sync>> {
45 let path = req.uri().path_and_query()
46 .map(|pq| pq.as_str())
47 .unwrap_or("/");
48
49 let uri = format!("{}{}", self.target, path).parse::<hyper::Uri>()?;
50
51 let (mut parts, body) = req.into_parts();
53 parts.uri = uri;
54
55 let proxy_req = Request::from_parts(parts, body);
56 let resp = self.client.request(proxy_req).await?;
57
58 Ok(resp.into_response())
59 }
60}