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