spin_factor_outbound_http/
intercept.rs1use std::net::SocketAddr;
2
3use http::{Request, Response};
4use http_body_util::{BodyExt, Full};
5use spin_world::async_trait;
6use wasmtime_wasi_http::{body::HyperOutgoingBody, HttpResult};
7
8pub type HyperBody = HyperOutgoingBody;
9
10#[async_trait]
13pub trait OutboundHttpInterceptor: Send + Sync {
14 async fn intercept(&self, request: InterceptRequest) -> HttpResult<InterceptOutcome>;
24}
25
26pub enum InterceptOutcome {
28 Continue(InterceptRequest),
31 Complete(Response<HyperBody>),
34}
35
36pub struct InterceptRequest {
42 inner: Request<()>,
43 body: InterceptBody,
44 pub(crate) override_connect_addr: Option<SocketAddr>,
45}
46
47enum InterceptBody {
48 Hyper(HyperBody),
49 Vec(Vec<u8>),
50}
51
52impl InterceptRequest {
53 pub fn override_connect_addr(&mut self, endpoint: SocketAddr) {
63 self.override_connect_addr = Some(endpoint);
64 }
65
66 pub fn into_hyper_request(self) -> Request<HyperBody> {
67 let (parts, ()) = self.inner.into_parts();
68 Request::from_parts(parts, self.body.into())
69 }
70
71 pub(crate) fn into_vec_request(self) -> Option<Request<Vec<u8>>> {
72 let InterceptBody::Vec(bytes) = self.body else {
73 return None;
74 };
75 let (parts, ()) = self.inner.into_parts();
76 Some(Request::from_parts(parts, bytes))
77 }
78}
79
80impl std::ops::Deref for InterceptRequest {
81 type Target = Request<()>;
82
83 fn deref(&self) -> &Self::Target {
84 &self.inner
85 }
86}
87
88impl std::ops::DerefMut for InterceptRequest {
89 fn deref_mut(&mut self) -> &mut Self::Target {
90 &mut self.inner
91 }
92}
93
94impl From<Request<HyperBody>> for InterceptRequest {
95 fn from(req: Request<HyperBody>) -> Self {
96 let (parts, body) = req.into_parts();
97 Self {
98 inner: Request::from_parts(parts, ()),
99 body: InterceptBody::Hyper(body),
100 override_connect_addr: None,
101 }
102 }
103}
104
105impl From<Request<Vec<u8>>> for InterceptRequest {
106 fn from(req: Request<Vec<u8>>) -> Self {
107 let (parts, body) = req.into_parts();
108 Self {
109 inner: Request::from_parts(parts, ()),
110 body: InterceptBody::Vec(body),
111 override_connect_addr: None,
112 }
113 }
114}
115
116impl From<InterceptBody> for HyperBody {
117 fn from(body: InterceptBody) -> Self {
118 match body {
119 InterceptBody::Hyper(body) => body,
120 InterceptBody::Vec(bytes) => {
121 Full::new(bytes.into()).map_err(|err| match err {}).boxed()
122 }
123 }
124 }
125}