Skip to main content

rama_http/layer/upgrade/http_proxy_connect/
response.rs

1use crate::{
2    Request, Response, StatusCode, layer::upgrade::UpgradeResponse,
3    service::web::response::IntoResponse as _,
4};
5use rama_core::{Service, extensions::Extensions, telemetry::tracing};
6use rama_net::{ConnectorTargetInputExt, Protocol, client::ConnectorTarget};
7
8#[derive(Debug, Clone, Default)]
9#[non_exhaustive]
10/// A lazy [`Service`] which acknowledges an HTTP (proxy) CONNECT request
11/// without first establishing the egress connection.
12///
13/// This is appropriate when the upgraded application stream must be observed
14/// before egress can be selected or constructed, such as application-aware
15/// routing for a custom tunneled protocol. It deliberately means that a
16/// successful CONNECT response does not confirm egress reachability.
17///
18/// For an ordinary HTTP proxy, including MITM where the CONNECT authority is
19/// the target, use [`EagerHttpProxyConnector`](super::EagerHttpProxyConnector)
20/// so the client receives a successful response only after the egress
21/// connection has been established.
22pub struct LazyHttpProxyConnectReplyService;
23
24impl LazyHttpProxyConnectReplyService {
25    #[inline(always)]
26    #[must_use]
27    /// Create a new [`LazyHttpProxyConnectReplyService`].
28    pub fn new() -> Self {
29        Self
30    }
31}
32
33impl<Body> Service<Request<Body>> for LazyHttpProxyConnectReplyService
34where
35    Body: Send + 'static,
36{
37    type Output = UpgradeResponse<Request<Body>, Response>;
38    type Error = Response;
39
40    async fn serve(&self, req: Request<Body>) -> Result<Self::Output, Self::Error> {
41        let extensions = Extensions::new();
42
43        if let Some(authority) = req.connector_target_with_default_port(Protocol::HTTP_DEFAULT_PORT)
44        {
45            tracing::info!(
46                server.address = %authority.host,
47                server.port = authority.port,
48                "accept CONNECT: insert proxy (connector) target into extensions",
49            );
50            extensions.insert(ConnectorTarget(authority));
51        } else {
52            tracing::error!("http proxy, error extracting connector target");
53            return Err(StatusCode::BAD_REQUEST.into_response());
54        }
55
56        Ok(UpgradeResponse {
57            request: req,
58            response: StatusCode::OK.into_response(),
59            extensions,
60        })
61    }
62}