| 
1 | 1 | use anyhow::Result;  | 
2 |  | -use axum::{  | 
3 |  | -    Router,  | 
4 |  | -    body::Body,  | 
5 |  | -    extract::State,  | 
6 |  | -    http::{Request, StatusCode},  | 
7 |  | -    response::{IntoResponse, Response},  | 
8 |  | -};  | 
9 |  | -use hyper_util::{  | 
10 |  | -    // https://github.com/hyperium/hyper/issues/3948  | 
11 |  | -    client::legacy::{Client, connect::HttpConnector},  | 
12 |  | -    rt::TokioExecutor,  | 
13 |  | -};  | 
14 |  | -use std::sync::Arc;  | 
15 |  | -use tracing::{error, info};  | 
16 |  | - | 
17 |  | -#[derive(Clone)]  | 
18 |  | -struct ProxyState {  | 
19 |  | -    client: Client<HttpConnector, Body>,  | 
20 |  | -    proxy_port: u16,  | 
21 |  | -}  | 
22 |  | - | 
23 |  | -pub async fn serve(addr: &str, proxy_port: u16) -> Result<()> {  | 
24 |  | -    let client = Client::builder(TokioExecutor::new()).build_http();  | 
25 |  | -    let state = Arc::new(ProxyState { client, proxy_port });  | 
26 |  | -    let router = Router::new().fallback(proxy_handler).with_state(state);  | 
 | 2 | +use axum::Router;  | 
 | 3 | +use axum_reverse_proxy::ReverseProxy;  | 
 | 4 | +use tracing::info;  | 
 | 5 | + | 
 | 6 | +pub async fn proxy(addr: &str, proxy_port: u16) -> Result<()> {  | 
 | 7 | +    let process_host = format!("http://localhost:{}", proxy_port);  | 
 | 8 | +    let proxy = ReverseProxy::new("/", &process_host);  | 
 | 9 | +    let app: Router = proxy.into();  | 
27 | 10 |     let listener = tokio::net::TcpListener::bind(&addr).await?;  | 
28 | 11 |     info!(component = "http", addr = %addr, proxy_port, "listening");  | 
29 |  | -    axum::serve(listener, router).await?;  | 
 | 12 | +    axum::serve(listener, app).await?;  | 
30 | 13 |     Ok(())  | 
31 | 14 | }  | 
32 |  | - | 
33 |  | -async fn proxy_handler(  | 
34 |  | -    State(state): State<Arc<ProxyState>>,  | 
35 |  | -    mut req: Request<Body>,  | 
36 |  | -) -> Result<Response, RoutingError> {  | 
37 |  | -    let proxy_uri = format!(  | 
38 |  | -        "http://127.0.0.1:{}{}",  | 
39 |  | -        state.proxy_port,  | 
40 |  | -        req.uri()  | 
41 |  | -            .path_and_query()  | 
42 |  | -            .map(|pq| pq.as_str())  | 
43 |  | -            .unwrap_or("/")  | 
44 |  | -    );  | 
45 |  | - | 
46 |  | -    info!(  | 
47 |  | -        method = %req.method(),  | 
48 |  | -        uri = %req.uri(),  | 
49 |  | -        proxy_uri = %proxy_uri,  | 
50 |  | -        "proxying request"  | 
51 |  | -    );  | 
52 |  | - | 
53 |  | -    *req.uri_mut() = proxy_uri.parse().map_err(|e| {  | 
54 |  | -        error!("failed to parse proxy URI: {}", e);  | 
55 |  | -        RoutingError::BadRequest  | 
56 |  | -    })?;  | 
57 |  | - | 
58 |  | -    let response = state.client.request(req).await.map_err(|e| {  | 
59 |  | -        error!("proxy request failed: {}", e);  | 
60 |  | -        RoutingError::ProxyError  | 
61 |  | -    })?;  | 
62 |  | - | 
63 |  | -    Ok(response.map(Body::new))  | 
64 |  | -}  | 
65 |  | - | 
66 |  | -enum RoutingError {  | 
67 |  | -    BadRequest,  | 
68 |  | -    ProxyError,  | 
69 |  | -}  | 
70 |  | - | 
71 |  | -impl IntoResponse for RoutingError {  | 
72 |  | -    fn into_response(self) -> Response {  | 
73 |  | -        let (status, message) = match self {  | 
74 |  | -            RoutingError::BadRequest => (StatusCode::BAD_REQUEST, "Bad request"),  | 
75 |  | -            RoutingError::ProxyError => (StatusCode::BAD_GATEWAY, "Proxy error"),  | 
76 |  | -        };  | 
77 |  | -        (status, message).into_response()  | 
78 |  | -    }  | 
79 |  | -}  | 
0 commit comments