lynx_core/proxy/
https_proxy.rs

1use std::sync::Arc;
2
3use anyhow::Error;
4use http::StatusCode;
5use http_body_util::combinators::BoxBody;
6use hyper::body::{Bytes, Incoming};
7use hyper::service::service_fn;
8use hyper::{Method, Request, Response};
9use hyper_util::rt::{TokioExecutor, TokioIo};
10use nanoid::nanoid;
11use tokio_rustls::TlsAcceptor;
12use tracing::{error, info, trace};
13
14use crate::proxy::http_proxy::proxy_http_request;
15use crate::server_context::CA_MANAGER;
16use crate::utils::empty;
17
18pub async fn https_proxy(
19    req: Request<Incoming>,
20) -> anyhow::Result<Response<BoxBody<Bytes, Error>>> {
21    info!("proxy https request");
22    let mut res = Response::default();
23    let authority = match req.uri().authority().cloned() {
24        Some(authority) => authority,
25        None => {
26            *res.status_mut() = StatusCode::BAD_REQUEST;
27            return Ok(res);
28        }
29    };
30    // Upgrade to tls connect
31    if Method::CONNECT == req.method() {
32        tokio::task::spawn(async move {
33            match hyper::upgrade::on(req).await {
34                Ok(upgraded) => {
35                    let upgraded = TokioIo::new(upgraded);
36                    let ca_manager = CA_MANAGER.get().expect("cert manager not found");
37                    let server_config = match ca_manager.gen_server_config(&authority).await {
38                        Ok(server_config) => server_config,
39                        Err(err) => {
40                            error!("Failed to build server config: {err}");
41                            return;
42                        }
43                    };
44                    trace!("start build tls stream");
45                    let stream = match TlsAcceptor::from(server_config).accept(upgraded).await {
46                        Ok(stream) => stream,
47                        Err(err) => {
48                            error!("Failed to build tls stream: {err}");
49                            return;
50                        }
51                    };
52                    trace!("end build tls stream");
53                    let service = service_fn(|mut req| async move {
54                        info!("proxying http request {:?}", req);
55                        req.extensions_mut().insert(Arc::new(nanoid!()));
56                        let res = proxy_http_request(req).await;
57                        match res {
58                            Ok(res) => Ok::<_, hyper::Error>(res),
59                            Err(err) => {
60                                error!("proxy http request error: {}", err.to_string());
61                                Ok(Response::new(empty()))
62                            }
63                        }
64                    });
65                    if let Err(err) =
66                        hyper_util::server::conn::auto::Builder::new(TokioExecutor::new())
67                            .serve_connection_with_upgrades(TokioIo::new(stream), service)
68                            .await
69                    {
70                        error!("HTTPS proxy connect error: {:?}", err);
71                    }
72                }
73                Err(e) => {
74                    error!("upgrade error: {:?}", e)
75                }
76            }
77        });
78    }
79    Ok(Response::new(empty()))
80}