diff --git a/CHANGES.md b/CHANGES.md index f37f8b466..2a2e2e414 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,13 +1,13 @@ # Changes -## not released yet + +## [1.0.8] - 2019-09-xx ### Added -* Add `middleware::Conditon` that conditionally enables another middleware +* Add `middleware::Conditon` that conditionally enables another middleware -### Fixed +* Allow to re-construct `ServiceRequest` from `HttpRequest` and `Payload` -* h2 will use error response #1080 ## [1.0.7] - 2019-08-29 diff --git a/actix-http/CHANGES.md b/actix-http/CHANGES.md index d603cde7b..849839378 100644 --- a/actix-http/CHANGES.md +++ b/actix-http/CHANGES.md @@ -8,6 +8,8 @@ ### Fixed +* h2 will use error response #1080 + * on_connect result isn't added to request extensions for http2 requests #1009 diff --git a/src/service.rs b/src/service.rs index 1d475cf15..8b94dd284 100644 --- a/src/service.rs +++ b/src/service.rs @@ -68,6 +68,34 @@ impl ServiceRequest { (self.0, pl) } + /// Construct request from parts. + /// + /// `ServiceRequest` can be re-constructed only if `req` hasnt been cloned. + pub fn from_parts( + mut req: HttpRequest, + pl: Payload, + ) -> Result { + if Rc::strong_count(&req.0) == 1 && Rc::weak_count(&req.0) == 0 { + Rc::get_mut(&mut req.0).unwrap().payload = pl; + Ok(ServiceRequest(req)) + } else { + Err((req, pl)) + } + } + + /// Construct request from request. + /// + /// `HttpRequest` implements `Clone` trait via `Rc` type. `ServiceRequest` + /// can be re-constructed only if rc's strong pointers count eq 1 and + /// weak pointers count is 0. + pub fn from_request(req: HttpRequest) -> Result { + if Rc::strong_count(&req.0) == 1 && Rc::weak_count(&req.0) == 0 { + Ok(ServiceRequest(req)) + } else { + Err(req) + } + } + /// Create service response #[inline] pub fn into_response>>(self, res: R) -> ServiceResponse { @@ -514,6 +542,27 @@ mod tests { use crate::test::{call_service, init_service, TestRequest}; use crate::{guard, http, web, App, HttpResponse}; + #[test] + fn test_service_request() { + let req = TestRequest::default().to_srv_request(); + let (r, pl) = req.into_parts(); + assert!(ServiceRequest::from_parts(r, pl).is_ok()); + + let req = TestRequest::default().to_srv_request(); + let (r, pl) = req.into_parts(); + let _r2 = r.clone(); + assert!(ServiceRequest::from_parts(r, pl).is_err()); + + let req = TestRequest::default().to_srv_request(); + let (r, _pl) = req.into_parts(); + assert!(ServiceRequest::from_request(r).is_ok()); + + let req = TestRequest::default().to_srv_request(); + let (r, _pl) = req.into_parts(); + let _r2 = r.clone(); + assert!(ServiceRequest::from_request(r).is_err()); + } + #[test] fn test_service() { let mut srv = init_service(