diff --git a/actix-http/examples/echo.rs b/actix-http/examples/echo.rs index 0b1a5081c..f9188ed9f 100644 --- a/actix-http/examples/echo.rs +++ b/actix-http/examples/echo.rs @@ -28,8 +28,6 @@ async fn main() -> io::Result<()> { .insert_header(("x-head", HeaderValue::from_static("dummy value!"))) .body(body); - res.req_data_mut().insert(5usize); - Ok::<_, Error>(res) }) // No TLS diff --git a/actix-http/examples/res-ext.rs b/actix-http/examples/res-ext.rs new file mode 100644 index 000000000..6418a301b --- /dev/null +++ b/actix-http/examples/res-ext.rs @@ -0,0 +1,53 @@ +use std::{convert::Infallible, io}; + +use actix_http::{ + body::EitherBody, HttpMessage as _, HttpService, Request, Response, StatusCode, +}; +use actix_server::Server; + +#[actix_rt::main] +async fn main() -> io::Result<()> { + env_logger::init_from_env(env_logger::Env::new().default_filter_or("info")); + + Server::build() + .bind("hello-world", ("127.0.0.1", 8080), || { + HttpService::build() + .client_timeout(1000) + .client_disconnect(1000) + .finish(|req: Request| async move { + let mut res = Response::build(StatusCode::OK).body("Hello world!"); + + match req.path() { + "/" => {} + + "/ext" => { + res.extensions_mut().insert(123u8); + } + + "/more" => { + res.extensions_mut().insert(123u8); + res.extensions_mut().insert(123u16); + res.extensions_mut().insert(123u32); + res.extensions_mut().insert(123u64); + res.extensions_mut().insert(123u128); + res.extensions_mut().insert(123i8); + res.extensions_mut().insert(123i16); + res.extensions_mut().insert(123i32); + res.extensions_mut().insert(123i64); + res.extensions_mut().insert(123i128); + } + + _ => { + return Ok(Response::not_found() + .map_body(|_, body| EitherBody::right(body))) + } + } + + Ok::<_, Infallible>(res) + }) + .tcp() + })? + .workers(4) + .run() + .await +} diff --git a/actix-http/src/error.rs b/actix-http/src/error.rs index cdf495c45..df6d3813a 100644 --- a/actix-http/src/error.rs +++ b/actix-http/src/error.rs @@ -387,6 +387,7 @@ impl StdError for DispatchError { /// A set of error that can occur during parsing content type. #[derive(Debug, Display, Error)] +#[cfg_attr(test, derive(PartialEq))] #[non_exhaustive] pub enum ContentTypeError { /// Can not parse content type @@ -398,28 +399,14 @@ pub enum ContentTypeError { UnknownEncoding, } -#[cfg(test)] -mod content_type_test_impls { - use super::*; - - impl std::cmp::PartialEq for ContentTypeError { - fn eq(&self, other: &Self) -> bool { - match self { - Self::ParseError => matches!(other, ContentTypeError::ParseError), - Self::UnknownEncoding => { - matches!(other, ContentTypeError::UnknownEncoding) - } - } - } - } -} - #[cfg(test)] mod tests { - use super::*; - use http::{Error as HttpError, StatusCode}; use std::io; + use http::{Error as HttpError, StatusCode}; + + use super::*; + #[test] fn test_into_response() { let resp: Response = ParseError::Incomplete.into(); diff --git a/actix-http/src/http_message.rs b/actix-http/src/http_message.rs index ccaa320fa..3c91b2f40 100644 --- a/actix-http/src/http_message.rs +++ b/actix-http/src/http_message.rs @@ -25,10 +25,10 @@ pub trait HttpMessage: Sized { /// Message payload stream fn take_payload(&mut self) -> Payload; - /// Request's extensions container + /// Returns a reference to the request-local data container. fn extensions(&self) -> Ref<'_, Extensions>; - /// Mutable reference to a the request's extensions container + /// Returns a mutable reference to the request-local data container. fn extensions_mut(&self) -> RefMut<'_, Extensions>; /// Get a header. diff --git a/actix-http/src/requests/request.rs b/actix-http/src/requests/request.rs index 4eaaba8e1..0f8e78d46 100644 --- a/actix-http/src/requests/request.rs +++ b/actix-http/src/requests/request.rs @@ -19,7 +19,7 @@ pub struct Request

{ pub(crate) payload: Payload

, pub(crate) head: Message, pub(crate) conn_data: Option>, - pub(crate) req_data: RefCell, + pub(crate) extensions: RefCell, } impl

HttpMessage for Request

{ @@ -34,16 +34,14 @@ impl

HttpMessage for Request

{ mem::replace(&mut self.payload, Payload::None) } - /// Request extensions #[inline] fn extensions(&self) -> Ref<'_, Extensions> { - self.req_data.borrow() + self.extensions.borrow() } - /// Mutable reference to a the request's extensions #[inline] fn extensions_mut(&self) -> RefMut<'_, Extensions> { - self.req_data.borrow_mut() + self.extensions.borrow_mut() } } @@ -52,7 +50,7 @@ impl From> for Request { Request { head, payload: Payload::None, - req_data: RefCell::new(Extensions::default()), + extensions: RefCell::new(Extensions::default()), conn_data: None, } } @@ -65,7 +63,7 @@ impl Request { Request { head: Message::new(), payload: Payload::None, - req_data: RefCell::new(Extensions::default()), + extensions: RefCell::new(Extensions::default()), conn_data: None, } } @@ -77,7 +75,7 @@ impl

Request

{ Request { payload, head: Message::new(), - req_data: RefCell::new(Extensions::default()), + extensions: RefCell::new(Extensions::default()), conn_data: None, } } @@ -90,7 +88,7 @@ impl

Request

{ Request { payload, head: self.head, - req_data: self.req_data, + extensions: self.extensions, conn_data: self.conn_data, }, pl, @@ -195,16 +193,17 @@ impl

Request

{ .and_then(|container| container.get::()) } - /// Returns the connection data container if an [on-connect] callback was registered. + /// Returns the connection-level data/extensions container if an [on-connect] callback was + /// registered, leaving an empty one in its place. /// /// [on-connect]: crate::HttpServiceBuilder::on_connect_ext pub fn take_conn_data(&mut self) -> Option> { self.conn_data.take() } - /// Returns the request data container, leaving an empty one in it's place. + /// Returns the request-local data/extensions container, leaving an empty one in its place. pub fn take_req_data(&mut self) -> Extensions { - mem::take(self.req_data.get_mut()) + mem::take(self.extensions.get_mut()) } } diff --git a/actix-http/src/responses/response.rs b/actix-http/src/responses/response.rs index 08dddb90a..7a0bae516 100644 --- a/actix-http/src/responses/response.rs +++ b/actix-http/src/responses/response.rs @@ -128,18 +128,6 @@ impl Response { self.head.keep_alive() } - /// Returns a reference to the extensions of this response. - #[inline] - pub fn extensions(&self) -> Ref<'_, Extensions> { - self.extensions.borrow() - } - - /// Returns a mutable reference to the extensions of this response. - #[inline] - pub fn extensions_mut(&self) -> RefMut<'_, Extensions> { - self.extensions.borrow_mut() - } - /// Returns a reference to the body of this response. #[inline] pub fn body(&self) -> &B { @@ -185,7 +173,9 @@ impl Response { self.replace_body(()) } - /// Returns new response with mapped body. + /// Map the current body type to another using a closure. Returns a new response. + /// + /// Closure receives the response head and the current body type. #[inline] pub fn map_body(mut self, f: F) -> Response where diff --git a/awc/src/responses/response.rs b/awc/src/responses/response.rs index 017c59744..02ffdbab2 100644 --- a/awc/src/responses/response.rs +++ b/awc/src/responses/response.rs @@ -67,7 +67,9 @@ impl ClientResponse { &self.head().headers } - /// Set a body and return previous body value + /// Map the current body type to another using a closure. Returns a new response. + /// + /// Closure receives the response head and the current body type. pub fn map_body(mut self, f: F) -> ClientResponse where F: FnOnce(&mut ResponseHead, Payload) -> Payload, @@ -117,18 +119,6 @@ impl ClientResponse { self } - /// Returns a reference to the extensions of this response. - #[inline] - pub fn req_data(&self) -> Ref<'_, Extensions> { - self.extensions.borrow() - } - - /// Returns a mutable reference to the extensions of this response. - #[inline] - pub fn req_data_mut(&self) -> RefMut<'_, Extensions> { - self.extensions.borrow_mut() - } - /// Load request cookies. #[cfg(feature = "cookies")] pub fn cookies(&self) -> Result>>, CookieParseError> { @@ -241,11 +231,11 @@ impl HttpMessage for ClientResponse { } fn extensions(&self) -> Ref<'_, Extensions> { - self.req_data() + self.extensions.borrow() } fn extensions_mut(&self) -> RefMut<'_, Extensions> { - self.req_data_mut() + self.extensions.borrow_mut() } } diff --git a/src/app_service.rs b/src/app_service.rs index 56b24f0d8..717e53ff7 100644 --- a/src/app_service.rs +++ b/src/app_service.rs @@ -18,7 +18,7 @@ use crate::{ AppServiceFactory, BoxedHttpService, BoxedHttpServiceFactory, ServiceRequest, ServiceResponse, }, - Error, HttpResponse, + Error, HttpMessage, HttpResponse, }; type Guards = Vec>; @@ -201,27 +201,29 @@ where actix_service::forward_ready!(service); fn call(&self, mut req: Request) -> Self::Future { - let req_data = Rc::new(RefCell::new(req.take_req_data())); + let extensions = Rc::new(RefCell::new(req.take_req_data())); let conn_data = req.take_conn_data(); let (head, payload) = req.into_parts(); - let req = if let Some(mut req) = self.app_state.pool().pop() { - let inner = Rc::get_mut(&mut req.inner).unwrap(); - inner.path.get_mut().update(&head.uri); - inner.path.reset(); - inner.head = head; - inner.conn_data = conn_data; - inner.req_data = req_data; - req - } else { - HttpRequest::new( + let req = match self.app_state.pool().pop() { + Some(mut req) => { + let inner = Rc::get_mut(&mut req.inner).unwrap(); + inner.path.get_mut().update(&head.uri); + inner.path.reset(); + inner.head = head; + inner.conn_data = conn_data; + inner.extensions = extensions; + req + } + + None => HttpRequest::new( Path::new(Url::new(head.uri.clone())), head, - self.app_state.clone(), - self.app_data.clone(), + Rc::clone(&self.app_state), + Rc::clone(&self.app_data), conn_data, - req_data, - ) + extensions, + ), }; self.service.call(ServiceRequest::new(req, payload)) diff --git a/src/request.rs b/src/request.rs index 2eed75a36..bcab79205 100644 --- a/src/request.rs +++ b/src/request.rs @@ -41,7 +41,7 @@ pub(crate) struct HttpRequestInner { pub(crate) path: Path, pub(crate) app_data: SmallVec<[Rc; 4]>, pub(crate) conn_data: Option>, - pub(crate) req_data: Rc>, + pub(crate) extensions: Rc>, app_state: Rc, } @@ -53,7 +53,7 @@ impl HttpRequest { app_state: Rc, app_data: Rc, conn_data: Option>, - req_data: Rc>, + extensions: Rc>, ) -> HttpRequest { let mut data = SmallVec::<[Rc; 4]>::new(); data.push(app_data); @@ -65,7 +65,7 @@ impl HttpRequest { app_state, app_data: data, conn_data, - req_data, + extensions, }), } } @@ -162,14 +162,6 @@ impl HttpRequest { self.resource_map().match_name(self.path()) } - pub fn req_data(&self) -> Ref<'_, Extensions> { - self.inner.req_data.borrow() - } - - pub fn req_data_mut(&self) -> RefMut<'_, Extensions> { - self.inner.req_data.borrow_mut() - } - /// Returns a reference a piece of connection data set in an [on-connect] callback. /// /// ```ignore @@ -359,12 +351,12 @@ impl HttpMessage for HttpRequest { #[inline] fn extensions(&self) -> Ref<'_, Extensions> { - self.req_data() + self.inner.extensions.borrow() } #[inline] fn extensions_mut(&self) -> RefMut<'_, Extensions> { - self.req_data_mut() + self.inner.extensions.borrow_mut() } #[inline] @@ -385,7 +377,10 @@ impl Drop for HttpRequest { // Inner is borrowed mut here and; get req data mutably to reduce borrow check. Also // we know the req_data Rc will not have any cloned at this point to unwrap is okay. - Rc::get_mut(&mut inner.req_data).unwrap().get_mut().clear(); + Rc::get_mut(&mut inner.extensions) + .unwrap() + .get_mut() + .clear(); // a re-borrow of pool is necessary here. let req = Rc::clone(&self.inner); diff --git a/src/response/response.rs b/src/response/response.rs index f24a75b19..74ccbad89 100644 --- a/src/response/response.rs +++ b/src/response/response.rs @@ -22,7 +22,7 @@ use { cookie::Cookie, }; -use crate::{error::Error, HttpRequest, HttpResponseBuilder, Responder}; +use crate::{error::Error, HttpMessage, HttpRequest, HttpResponseBuilder, Responder}; /// An outgoing response. pub struct HttpResponse { @@ -216,7 +216,9 @@ impl HttpResponse { } } - /// Set a body and return previous body value + /// Map the current body type to another using a closure. Returns a new response. + /// + /// Closure receives the response head and the current body type. pub fn map_body(self, f: F) -> HttpResponse where F: FnOnce(&mut ResponseHead, B) -> B2, diff --git a/src/service.rs b/src/service.rs index 4ca2b518a..b8d6125a9 100644 --- a/src/service.rs +++ b/src/service.rs @@ -399,32 +399,32 @@ impl ServiceResponse { ServiceResponse::new(self.request, response) } - /// Get reference to original request + /// Returns reference to original request. #[inline] pub fn request(&self) -> &HttpRequest { &self.request } - /// Get reference to response + /// Returns reference to response. #[inline] pub fn response(&self) -> &HttpResponse { &self.response } - /// Get mutable reference to response + /// Returns mutable reference to response. #[inline] pub fn response_mut(&mut self) -> &mut HttpResponse { &mut self.response } - /// Get the response status code + /// Returns response status code. #[inline] pub fn status(&self) -> StatusCode { self.response.status() } - #[inline] /// Returns response's headers. + #[inline] pub fn headers(&self) -> &HeaderMap { self.response.headers() } @@ -441,13 +441,9 @@ impl ServiceResponse { (self.request, self.response) } - /// Extract response body - #[inline] - pub fn into_body(self) -> B { - self.response.into_body() - } - - /// Set a new body + /// Map the current body type to another using a closure. Returns a new response. + /// + /// Closure receives the response head and the current body type. #[inline] pub fn map_body(self, f: F) -> ServiceResponse where @@ -478,6 +474,12 @@ impl ServiceResponse { { self.map_body(|_, body| body.boxed()) } + + /// Consumes the response and returns its body. + #[inline] + pub fn into_body(self) -> B { + self.response.into_body() + } } impl From> for HttpResponse {