actix_web_buffering/
lib.rs

1//! Request/Response body buffering with support spooled to a temp file on disk
2//!
3//! Use it in actix-web middleware. For example this is used at [actix-web-detached-jws-middleware](https://crates.io/crates/actix-web-detached-jws-middleware)
4//!
5//! # Example:
6//! ```ignore
7//! use std::{
8//!     cell::RefCell,
9//!     pin::Pin,
10//!     rc::Rc,
11//!     sync::Arc,
12//!     task::{Context, Poll},
13//! };
14//!
15//! use actix_service::Transform;
16//! use actix_web::{
17//!     dev::{Body, Service, ServiceRequest, ServiceResponse},
18//!     web,
19//!     web::BytesMut,
20//!     App, Error, HttpMessage, HttpResponse, HttpServer, Responder,
21//! };
22//! use actix_web_buffering::{
23//!     enable_request_buffering, enable_response_buffering, FileBufferingStreamWrapper,
24//! };
25//! use futures::{
26//!     future::{ok, Ready},
27//!     stream::StreamExt,
28//!     Future, FutureExt,
29//! };
30//!
31//! #[actix_web::main]
32//! async fn main() -> std::io::Result<()> {
33//!     let wrapper = FileBufferingStreamWrapper::new()
34//!         .tmp_dir(std::env::temp_dir())
35//!         .threshold(1024 * 30)
36//!         .produce_chunk_size(1024 * 30)
37//!         .buffer_limit(Some(1024 * 30 * 10));
38//!
39//!     let wrapper = Arc::new(wrapper);
40//!
41//!     HttpServer::new(move || {
42//!         let r1 = Arc::clone(&wrapper);
43//!         let r2 = Arc::clone(&wrapper);
44//!         App::new()
45//!             .wrap(Example(r1))
46//!             .wrap(Example(r2))
47//!             .service(web::resource("/").route(web::post().to(echo)))
48//!     })
49//!     .bind("127.0.0.1:8080")?
50//!     .run()
51//!     .await
52//! }
53//!
54//! async fn echo(req_body: String) -> impl Responder {
55//!     HttpResponse::Ok().body(req_body)
56//! }
57//!
58//! struct Example(Arc<FileBufferingStreamWrapper>);
59//!
60//! impl<S> Transform<S> for Example
61//! where
62//!     S: Service<Request = ServiceRequest, Response = ServiceResponse<Body>, Error = Error> + 'static,
63//! {
64//!     type Request = ServiceRequest;
65//!     type Response = ServiceResponse<Body>;
66//!     type Error = Error;
67//!     type InitError = ();
68//!     type Transform = ExampleMiddleware<S>;
69//!     type Future = Ready<Result<Self::Transform, Self::InitError>>;
70//!
71//!     fn new_transform(&self, service: S) -> Self::Future {
72//!         ok(ExampleMiddleware {
73//!             service: Rc::new(RefCell::new(service)),
74//!             wrapper: Arc::clone(&self.0),
75//!         })
76//!     }
77//! }
78//! pub struct ExampleMiddleware<S> {
79//!     service: Rc<RefCell<S>>,
80//!     wrapper: Arc<FileBufferingStreamWrapper>,
81//! }
82//!
83//! impl<S> Service for ExampleMiddleware<S>
84//! where
85//!     S: Service<Request = ServiceRequest, Response = ServiceResponse<Body>, Error = Error> + 'static,
86//! {
87//!     type Request = ServiceRequest;
88//!     type Response = ServiceResponse<Body>;
89//!     type Error = Error;
90//!     type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>;
91//!
92//!     fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
93//!         self.service.poll_ready(cx)
94//!     }
95//!
96//!     fn call(&mut self, mut req: ServiceRequest) -> Self::Future {
97//!         let mut svc = self.service.clone();
98//!         let wrapper = self.wrapper.clone();
99//!
100//!         async move {
101//!             enable_request_buffering(&wrapper, &mut req);
102//!
103//!             let mut stream = req.take_payload();
104//!             let mut body = BytesMut::new();
105//!             while let Some(chunk) = stream.next().await {
106//!                 body.extend_from_slice(&chunk.unwrap());
107//!             }
108//!             req.set_payload(stream);
109//!             println!("request body: {:?}", body);
110//!
111//!             let svc_res = svc.call(req).await?;
112//!
113//!             let mut svc_res = enable_response_buffering(&wrapper, svc_res);
114//!
115//!             let mut stream = svc_res.take_body();
116//!             let mut body = BytesMut::new();
117//!             while let Some(chunk) = stream.next().await {
118//!                 body.extend_from_slice(&chunk.unwrap());
119//!             }
120//!             let svc_res = svc_res.map_body(|_, _| stream);
121//!             println!("response body: {:?}", body);
122//!
123//!             Ok(svc_res)
124//!         }
125//!         .boxed_local()
126//!     }
127//! }
128//! ```
129pub mod buffering;
130
131pub use crate::buffering::{
132    enable_request_buffering, enable_response_buffering, FileBufferingStreamWrapper,
133};