From c2c4a5ba3f696f58ea67355da75c09de7b182e9f Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Thu, 21 Jun 2018 10:45:24 +0600 Subject: [PATCH] fix failure Send+Sync compatibility --- src/error.rs | 10 +++--- src/httpresponse.rs | 74 ++++++++++++++++++++++++++++++++++----------- 2 files changed, 61 insertions(+), 23 deletions(-) diff --git a/src/error.rs b/src/error.rs index f011733b3..3141ad2a3 100644 --- a/src/error.rs +++ b/src/error.rs @@ -24,7 +24,7 @@ pub use cookie::ParseError as CookieParseError; use handler::Responder; use httprequest::HttpRequest; -use httpresponse::{HttpResponse, InnerHttpResponse}; +use httpresponse::{HttpResponse, HttpResponseParts}; /// A specialized [`Result`](https://doc.rust-lang.org/std/result/enum.Result.html) /// for actix web operations @@ -654,7 +654,7 @@ pub struct InternalError { enum InternalErrorType { Status(StatusCode), - Response(Mutex>>), + Response(Mutex>), } impl InternalError { @@ -669,9 +669,7 @@ impl InternalError { /// Create `InternalError` with predefined `HttpResponse`. pub fn from_response(cause: T, response: HttpResponse) -> Self { - let mut resp = response.into_inner(); - resp.drop_unsupported_body(); - + let resp = response.into_parts(); InternalError { cause, status: InternalErrorType::Response(Mutex::new(Some(resp))), @@ -716,7 +714,7 @@ where InternalErrorType::Status(st) => HttpResponse::new(st), InternalErrorType::Response(ref resp) => { if let Some(resp) = resp.lock().unwrap().take() { - HttpResponse::from_inner(resp) + HttpResponse::from_parts(resp) } else { HttpResponse::new(StatusCode::INTERNAL_SERVER_ERROR) } diff --git a/src/httpresponse.rs b/src/httpresponse.rs index 8caf470ce..4e139ef62 100644 --- a/src/httpresponse.rs +++ b/src/httpresponse.rs @@ -299,12 +299,15 @@ impl HttpResponse { self.get_mut().write_capacity = cap; } - pub(crate) fn into_inner(mut self) -> Box { - self.0.take().unwrap() + pub(crate) fn into_parts(mut self) -> HttpResponseParts { + self.0.take().unwrap().into_parts() } - pub(crate) fn from_inner(inner: Box) -> HttpResponse { - HttpResponse(Some(inner), HttpResponsePool::pool()) + pub(crate) fn from_parts(parts: HttpResponseParts) -> HttpResponse { + HttpResponse( + Some(Box::new(InnerHttpResponse::from_parts(parts))), + HttpResponsePool::pool(), + ) } } @@ -880,12 +883,12 @@ impl<'a, S> From<&'a HttpRequest> for HttpResponseBuilder { } #[derive(Debug)] -pub(crate) struct InnerHttpResponse { +struct InnerHttpResponse { version: Option, headers: HeaderMap, status: StatusCode, reason: Option<&'static str>, - pub(crate) body: Body, + body: Body, chunked: Option, encoding: Option, connection_type: Option, @@ -894,10 +897,16 @@ pub(crate) struct InnerHttpResponse { error: Option, } -/// This is here only because `failure::Fail: Send + Sync` which looks insane to me -unsafe impl Sync for InnerHttpResponse {} -/// This is here only because `failure::Fail: Send + Sync` which looks insane to me -unsafe impl Send for InnerHttpResponse {} +pub(crate) struct HttpResponseParts { + version: Option, + headers: HeaderMap, + status: StatusCode, + reason: Option<&'static str>, + body: Option, + encoding: Option, + connection_type: Option, + error: Option, +} impl InnerHttpResponse { #[inline] @@ -918,16 +927,47 @@ impl InnerHttpResponse { } /// This is for failure, we can not have Send + Sync on Streaming and Actor response - pub(crate) fn drop_unsupported_body(&mut self) { - let body = mem::replace(&mut self.body, Body::Empty); - match body { - Body::Empty => (), - Body::Binary(mut bin) => { - self.body = Body::Binary(bin.take().into()); - } + fn into_parts(mut self) -> HttpResponseParts { + let body = match mem::replace(&mut self.body, Body::Empty) { + Body::Empty => None, + Body::Binary(mut bin) => Some(bin.take()), Body::Streaming(_) | Body::Actor(_) => { error!("Streaming or Actor body is not support by error response"); + None } + }; + + HttpResponseParts { + body, + version: self.version, + headers: self.headers, + status: self.status, + reason: self.reason, + encoding: self.encoding, + connection_type: self.connection_type, + error: self.error, + } + } + + fn from_parts(parts: HttpResponseParts) -> InnerHttpResponse { + let body = if let Some(ref body) = parts.body { + Body::Binary(body.clone().into()) + } else { + Body::Empty + }; + + InnerHttpResponse { + body, + status: parts.status, + version: parts.version, + headers: parts.headers, + reason: parts.reason, + chunked: None, + encoding: parts.encoding, + connection_type: parts.connection_type, + response_size: 0, + write_capacity: MAX_WRITE_BUFFER_SIZE, + error: parts.error, } } }