spin_trigger_http/
outbound_http.rs

1use std::{
2    net::{IpAddr, Ipv4Addr, SocketAddr},
3    sync::Arc,
4};
5
6use http::uri::Scheme;
7use spin_core::async_trait;
8use spin_factor_outbound_http::intercept::{self, InterceptOutcome, InterceptRequest};
9use spin_factor_outbound_networking::parse_service_chaining_target;
10use spin_factors::RuntimeFactors;
11use spin_http::routes::RouteMatch;
12use wasmtime_wasi_http::{HttpError, HttpResult};
13
14use crate::HttpServer;
15
16/// An outbound HTTP interceptor that handles service chaining requests.
17pub struct OutboundHttpInterceptor<F: RuntimeFactors> {
18    server: Arc<HttpServer<F>>,
19}
20
21impl<F: RuntimeFactors> OutboundHttpInterceptor<F> {
22    pub fn new(server: Arc<HttpServer<F>>) -> Self {
23        Self { server }
24    }
25}
26
27const CHAINED_CLIENT_ADDR: SocketAddr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0);
28
29#[async_trait]
30impl<F: RuntimeFactors> intercept::OutboundHttpInterceptor for OutboundHttpInterceptor<F> {
31    async fn intercept(&self, request: InterceptRequest) -> HttpResult<InterceptOutcome> {
32        // Handle service chaining requests
33        if let Some(component_id) = parse_service_chaining_target(request.uri()) {
34            let req = request.into_hyper_request();
35            let path = req.uri().path().to_owned();
36            let route_match = RouteMatch::synthetic(component_id, path);
37            let resp = self
38                .server
39                .handle_trigger_route(req, route_match, Scheme::HTTP, CHAINED_CLIENT_ADDR)
40                .await
41                .map_err(HttpError::trap)?;
42            Ok(InterceptOutcome::Complete(resp))
43        } else {
44            Ok(InterceptOutcome::Continue(request))
45        }
46    }
47}