1
0
mirror of https://github.com/actix/examples synced 2025-01-23 06:14:35 +01:00
examples/middleware/various/src/read_response_body.rs

124 lines
3.0 KiB
Rust
Raw Normal View History

2022-02-22 12:12:17 +00:00
use std::{
future::{ready, Future, Ready},
marker::PhantomData,
pin::Pin,
task::{Context, Poll},
};
2019-12-07 23:59:24 +06:00
2022-02-22 12:12:17 +00:00
use actix_web::{
body::{BodySize, MessageBody},
dev::{self, Service, ServiceRequest, ServiceResponse, Transform},
web::{Bytes, BytesMut},
Error,
};
pub struct Logging;
impl<S: 'static, B> Transform<S, ServiceRequest> for Logging
where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
B: MessageBody + 'static,
{
type Response = ServiceResponse<BodyLogger<B>>;
type Error = Error;
type InitError = ();
type Transform = LoggingMiddleware<S>;
2019-12-07 23:59:24 +06:00
type Future = Ready<Result<Self::Transform, Self::InitError>>;
fn new_transform(&self, service: S) -> Self::Future {
ready(Ok(LoggingMiddleware { service }))
}
}
pub struct LoggingMiddleware<S> {
service: S,
}
impl<S, B> Service<ServiceRequest> for LoggingMiddleware<S>
where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
B: MessageBody,
{
type Response = ServiceResponse<BodyLogger<B>>;
type Error = Error;
type Future = WrapperStream<S, B>;
dev::forward_ready!(service);
fn call(&self, req: ServiceRequest) -> Self::Future {
WrapperStream {
fut: self.service.call(req),
_t: PhantomData,
}
}
}
2019-12-07 23:59:24 +06:00
#[pin_project::pin_project]
pub struct WrapperStream<S, B>
where
B: MessageBody,
S: Service<ServiceRequest>,
{
2019-12-07 23:59:24 +06:00
#[pin]
fut: S::Future,
_t: PhantomData<(B,)>,
}
impl<S, B> Future for WrapperStream<S, B>
where
B: MessageBody,
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
{
2019-12-07 23:59:24 +06:00
type Output = Result<ServiceResponse<BodyLogger<B>>, Error>;
2019-12-07 23:59:24 +06:00
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
2022-02-22 12:12:17 +00:00
let res = futures_util::ready!(self.project().fut.poll(cx));
2019-12-07 23:59:24 +06:00
Poll::Ready(res.map(|res| {
res.map_body(move |_, body| BodyLogger {
body,
body_accum: BytesMut::new(),
})
2019-12-07 23:59:24 +06:00
}))
}
}
2020-09-12 16:49:45 +01:00
#[pin_project::pin_project(PinnedDrop)]
pub struct BodyLogger<B> {
2020-09-12 16:49:45 +01:00
#[pin]
body: B,
body_accum: BytesMut,
}
2020-09-12 16:49:45 +01:00
#[pin_project::pinned_drop]
impl<B> PinnedDrop for BodyLogger<B> {
fn drop(self: Pin<&mut Self>) {
println!("response body: {:?}", self.body_accum);
}
}
impl<B: MessageBody> MessageBody for BodyLogger<B> {
type Error = B::Error;
fn size(&self) -> BodySize {
self.body.size()
}
2020-09-12 16:49:45 +01:00
fn poll_next(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Option<Result<Bytes, Self::Error>>> {
2020-09-12 16:49:45 +01:00
let this = self.project();
match this.body.poll_next(cx) {
2019-12-07 23:59:24 +06:00
Poll::Ready(Some(Ok(chunk))) => {
2020-09-12 16:49:45 +01:00
this.body_accum.extend_from_slice(&chunk);
2019-12-07 23:59:24 +06:00
Poll::Ready(Some(Ok(chunk)))
}
2019-12-07 23:59:24 +06:00
Poll::Ready(Some(Err(e))) => Poll::Ready(Some(Err(e))),
Poll::Ready(None) => Poll::Ready(None),
Poll::Pending => Poll::Pending,
}
}
}