-
Notifications
You must be signed in to change notification settings - Fork 260
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2817 from lann/intercept-spin
Support interceptor in spin outbound http
- Loading branch information
Showing
9 changed files
with
256 additions
and
75 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
use http::{Request, Response}; | ||
use http_body_util::{BodyExt, Full}; | ||
use spin_world::async_trait; | ||
use wasmtime_wasi_http::{body::HyperOutgoingBody, HttpResult}; | ||
|
||
pub type HyperBody = HyperOutgoingBody; | ||
|
||
/// An outbound HTTP request interceptor to be used with | ||
/// [`InstanceState::set_request_interceptor`]. | ||
#[async_trait] | ||
pub trait OutboundHttpInterceptor: Send + Sync { | ||
/// Intercept an outgoing HTTP request. | ||
/// | ||
/// If this method returns [`InterceptedResponse::Continue`], the (possibly | ||
/// updated) request will be passed on to the default outgoing request | ||
/// handler. | ||
/// | ||
/// If this method returns [`InterceptedResponse::Intercepted`], the inner | ||
/// result will be returned as the result of the request, bypassing the | ||
/// default handler. The `request` will also be dropped immediately. | ||
async fn intercept(&self, request: InterceptRequest) -> HttpResult<InterceptOutcome>; | ||
} | ||
|
||
/// The type returned by an [`OutboundHttpInterceptor`]. | ||
pub enum InterceptOutcome { | ||
/// The intercepted request will be passed on to the default outgoing | ||
/// request handler. | ||
Continue(InterceptRequest), | ||
/// The given response will be returned as the result of the intercepted | ||
/// request, bypassing the default handler. | ||
Complete(Response<HyperBody>), | ||
} | ||
|
||
/// An intercepted outgoing HTTP request. | ||
/// | ||
/// This is a wrapper that implements `DerefMut<Target = Request<()>>` for | ||
/// inspection and modification of the request envelope. If the body needs to be | ||
/// consumed, call [`Self::into_hyper_request`]. | ||
pub struct InterceptRequest { | ||
inner: Request<()>, | ||
body: InterceptBody, | ||
} | ||
|
||
enum InterceptBody { | ||
Hyper(HyperBody), | ||
Vec(Vec<u8>), | ||
} | ||
|
||
impl InterceptRequest { | ||
pub fn into_hyper_request(self) -> Request<HyperBody> { | ||
let (parts, ()) = self.inner.into_parts(); | ||
Request::from_parts(parts, self.body.into()) | ||
} | ||
|
||
pub(crate) fn into_vec_request(self) -> Option<Request<Vec<u8>>> { | ||
let InterceptBody::Vec(bytes) = self.body else { | ||
return None; | ||
}; | ||
let (parts, ()) = self.inner.into_parts(); | ||
Some(Request::from_parts(parts, bytes)) | ||
} | ||
} | ||
|
||
impl std::ops::Deref for InterceptRequest { | ||
type Target = Request<()>; | ||
|
||
fn deref(&self) -> &Self::Target { | ||
&self.inner | ||
} | ||
} | ||
|
||
impl std::ops::DerefMut for InterceptRequest { | ||
fn deref_mut(&mut self) -> &mut Self::Target { | ||
&mut self.inner | ||
} | ||
} | ||
|
||
impl From<Request<HyperBody>> for InterceptRequest { | ||
fn from(req: Request<HyperBody>) -> Self { | ||
let (parts, body) = req.into_parts(); | ||
Self { | ||
inner: Request::from_parts(parts, ()), | ||
body: InterceptBody::Hyper(body), | ||
} | ||
} | ||
} | ||
|
||
impl From<Request<Vec<u8>>> for InterceptRequest { | ||
fn from(req: Request<Vec<u8>>) -> Self { | ||
let (parts, body) = req.into_parts(); | ||
Self { | ||
inner: Request::from_parts(parts, ()), | ||
body: InterceptBody::Vec(body), | ||
} | ||
} | ||
} | ||
|
||
impl From<InterceptBody> for HyperBody { | ||
fn from(body: InterceptBody) -> Self { | ||
match body { | ||
InterceptBody::Hyper(body) => body, | ||
InterceptBody::Vec(bytes) => { | ||
Full::new(bytes.into()).map_err(|err| match err {}).boxed() | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.