lynx_core/proxy/
https_proxy.rs1use 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 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}