From d3e807f6e94777d35d1b16b2759a7c7a8b5b39cc Mon Sep 17 00:00:00 2001
From: Nikolay Kim <fafhrd91@gmail.com>
Date: Wed, 22 May 2019 11:49:27 -0700
Subject: [PATCH] move Payload to inner http request

---
 src/app_service.rs |  4 +++-
 src/handler.rs     | 11 +++++------
 src/request.rs     |  3 +++
 src/service.rs     | 43 ++++++++++++++++++++++---------------------
 src/test.rs        | 11 ++++++-----
 5 files changed, 39 insertions(+), 33 deletions(-)

diff --git a/src/app_service.rs b/src/app_service.rs
index c483a119..88e97de1 100644
--- a/src/app_service.rs
+++ b/src/app_service.rs
@@ -215,19 +215,21 @@ where
             inner.path.get_mut().update(&head.uri);
             inner.path.reset();
             inner.head = head;
+            inner.payload = payload;
             inner.app_data = self.data.clone();
             req
         } else {
             HttpRequest::new(
                 Path::new(Url::new(head.uri.clone())),
                 head,
+                payload,
                 self.rmap.clone(),
                 self.config.clone(),
                 self.data.clone(),
                 self.pool,
             )
         };
-        self.service.call(ServiceRequest::from_parts(req, payload))
+        self.service.call(ServiceRequest::new(req))
     }
 }
 
diff --git a/src/handler.rs b/src/handler.rs
index b53d1638..bd0b3551 100644
--- a/src/handler.rs
+++ b/src/handler.rs
@@ -1,7 +1,7 @@
 use std::convert::Infallible;
 use std::marker::PhantomData;
 
-use actix_http::{Error, Payload, Response};
+use actix_http::{Error, Response};
 use actix_service::{NewService, Service};
 use futures::future::{ok, FutureResult};
 use futures::{try_ready, Async, Future, IntoFuture, Poll};
@@ -331,15 +331,15 @@ where
 
         ExtractResponse {
             fut,
+            req,
             fut_s: None,
-            req: Some((req, payload)),
             service: self.service.clone(),
         }
     }
 }
 
 pub struct ExtractResponse<T: FromRequest, S: Service> {
-    req: Option<(HttpRequest, Payload)>,
+    req: HttpRequest,
     service: S,
     fut: <T::Future as IntoFuture>::Future,
     fut_s: Option<S::Future>,
@@ -362,12 +362,11 @@ where
         }
 
         let item = try_ready!(self.fut.poll().map_err(|e| {
-            let (req, payload) = self.req.take().unwrap();
-            let req = ServiceRequest::from_parts(req, payload);
+            let req = ServiceRequest::new(self.req.clone());
             (e.into(), req)
         }));
 
-        self.fut_s = Some(self.service.call((item, self.req.take().unwrap().0)));
+        self.fut_s = Some(self.service.call((item, self.req.clone())));
         self.poll()
     }
 }
diff --git a/src/request.rs b/src/request.rs
index c6d14b50..07aac8cf 100644
--- a/src/request.rs
+++ b/src/request.rs
@@ -20,6 +20,7 @@ pub struct HttpRequest(pub(crate) Rc<HttpRequestInner>);
 pub(crate) struct HttpRequestInner {
     pub(crate) head: Message<RequestHead>,
     pub(crate) path: Path<Url>,
+    pub(crate) payload: Payload,
     pub(crate) app_data: Rc<Extensions>,
     rmap: Rc<ResourceMap>,
     config: AppConfig,
@@ -31,6 +32,7 @@ impl HttpRequest {
     pub(crate) fn new(
         path: Path<Url>,
         head: Message<RequestHead>,
+        payload: Payload,
         rmap: Rc<ResourceMap>,
         config: AppConfig,
         app_data: Rc<Extensions>,
@@ -39,6 +41,7 @@ impl HttpRequest {
         HttpRequest(Rc::new(HttpRequestInner {
             head,
             path,
+            payload,
             rmap,
             config,
             app_data,
diff --git a/src/service.rs b/src/service.rs
index eee8b0ad..f4f1a205 100644
--- a/src/service.rs
+++ b/src/service.rs
@@ -50,45 +50,46 @@ where
     }
 }
 
-pub struct ServiceRequest {
-    req: HttpRequest,
-    payload: Payload,
-}
+/// An service http request
+///
+/// ServiceRequest allows mutable access to request's internal structures
+pub struct ServiceRequest(HttpRequest);
 
 impl ServiceRequest {
-    /// Construct service request from parts
-    pub(crate) fn from_parts(req: HttpRequest, payload: Payload) -> Self {
-        ServiceRequest { req, payload }
+    /// Construct service request
+    pub(crate) fn new(req: HttpRequest) -> Self {
+        ServiceRequest(req)
     }
 
     /// Deconstruct request into parts
-    pub fn into_parts(self) -> (HttpRequest, Payload) {
-        (self.req, self.payload)
+    pub fn into_parts(mut self) -> (HttpRequest, Payload) {
+        let pl = Rc::get_mut(&mut (self.0).0).unwrap().payload.take();
+        (self.0, pl)
     }
 
     /// Create service response
     #[inline]
     pub fn into_response<B, R: Into<Response<B>>>(self, res: R) -> ServiceResponse<B> {
-        ServiceResponse::new(self.req, res.into())
+        ServiceResponse::new(self.0, res.into())
     }
 
     /// Create service response for error
     #[inline]
     pub fn error_response<B, E: Into<Error>>(self, err: E) -> ServiceResponse<B> {
         let res: Response = err.into().into();
-        ServiceResponse::new(self.req, res.into_body())
+        ServiceResponse::new(self.0, res.into_body())
     }
 
     /// This method returns reference to the request head
     #[inline]
     pub fn head(&self) -> &RequestHead {
-        &self.req.head()
+        &self.0.head()
     }
 
     /// This method returns reference to the request head
     #[inline]
     pub fn head_mut(&mut self) -> &mut RequestHead {
-        self.req.head_mut()
+        self.0.head_mut()
     }
 
     /// Request's uri.
@@ -164,24 +165,24 @@ impl ServiceRequest {
     /// access the matched value for that segment.
     #[inline]
     pub fn match_info(&self) -> &Path<Url> {
-        self.req.match_info()
+        self.0.match_info()
     }
 
     #[inline]
     pub fn match_info_mut(&mut self) -> &mut Path<Url> {
-        self.req.match_info_mut()
+        self.0.match_info_mut()
     }
 
     /// Service configuration
     #[inline]
     pub fn app_config(&self) -> &AppConfig {
-        self.req.app_config()
+        self.0.app_config()
     }
 
     /// Get an application data stored with `App::data()` method during
     /// application configuration.
     pub fn app_data<T: 'static>(&self) -> Option<Data<T>> {
-        if let Some(st) = self.req.0.app_data.get::<Data<T>>() {
+        if let Some(st) = (self.0).0.app_data.get::<Data<T>>() {
             Some(st.clone())
         } else {
             None
@@ -191,7 +192,7 @@ impl ServiceRequest {
     #[doc(hidden)]
     /// Set new app data container
     pub fn set_data_container(&mut self, extensions: Rc<Extensions>) {
-        Rc::get_mut(&mut self.req.0).unwrap().app_data = extensions;
+        Rc::get_mut(&mut (self.0).0).unwrap().app_data = extensions;
     }
 }
 
@@ -213,18 +214,18 @@ impl HttpMessage for ServiceRequest {
     /// Request extensions
     #[inline]
     fn extensions(&self) -> Ref<Extensions> {
-        self.req.extensions()
+        self.0.extensions()
     }
 
     /// Mutable reference to a the request's extensions
     #[inline]
     fn extensions_mut(&self) -> RefMut<Extensions> {
-        self.req.extensions_mut()
+        self.0.extensions_mut()
     }
 
     #[inline]
     fn take_payload(&mut self) -> Payload<Self::Stream> {
-        std::mem::replace(&mut self.payload, Payload::None)
+        Rc::get_mut(&mut (self.0).0).unwrap().payload.take()
     }
 }
 
diff --git a/src/test.rs b/src/test.rs
index dc17e922..89c1a126 100644
--- a/src/test.rs
+++ b/src/test.rs
@@ -512,16 +512,15 @@ impl TestRequest {
         let (head, payload) = self.req.finish().into_parts();
         self.path.get_mut().update(&head.uri);
 
-        let req = HttpRequest::new(
+        ServiceRequest::new(HttpRequest::new(
             self.path,
             head,
+            payload,
             Rc::new(self.rmap),
             AppConfig::new(self.config),
             Rc::new(self.app_data),
             HttpRequestPool::create(),
-        );
-
-        ServiceRequest::from_parts(req, payload)
+        ))
     }
 
     /// Complete request creation and generate `ServiceResponse` instance
@@ -531,12 +530,13 @@ impl TestRequest {
 
     /// Complete request creation and generate `HttpRequest` instance
     pub fn to_http_request(mut self) -> HttpRequest {
-        let (head, _) = self.req.finish().into_parts();
+        let (head, payload) = self.req.finish().into_parts();
         self.path.get_mut().update(&head.uri);
 
         HttpRequest::new(
             self.path,
             head,
+            payload,
             Rc::new(self.rmap),
             AppConfig::new(self.config),
             Rc::new(self.app_data),
@@ -552,6 +552,7 @@ impl TestRequest {
         let req = HttpRequest::new(
             self.path,
             head,
+            Payload::None,
             Rc::new(self.rmap),
             AppConfig::new(self.config),
             Rc::new(self.app_data),