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