1
0
mirror of https://github.com/actix/actix-extras.git synced 2024-11-24 16:02:59 +01:00

simplify server response type

This commit is contained in:
Nikolay Kim 2018-11-17 08:56:40 -08:00
parent 3a4b16a6d5
commit f0bd4d868e
2 changed files with 53 additions and 68 deletions

View File

@ -74,6 +74,8 @@ impl Default for ResponseHead {
impl Head for ResponseHead { impl Head for ResponseHead {
fn clear(&mut self) { fn clear(&mut self) {
self.reason = None;
self.version = None;
self.headers.clear(); self.headers.clear();
self.flags = MessageFlags::empty(); self.flags = MessageFlags::empty();
} }

View File

@ -12,6 +12,7 @@ use http::{Error as HttpError, HeaderMap, HttpTryFrom, StatusCode, Version};
use serde::Serialize; use serde::Serialize;
use serde_json; use serde_json;
use message::{Head, ResponseHead, MessageFlags};
use body::Body; use body::Body;
use error::Error; use error::Error;
use header::{ContentEncoding, Header, IntoHeaderValue}; use header::{ContentEncoding, Header, IntoHeaderValue};
@ -31,7 +32,7 @@ pub enum ConnectionType {
} }
/// An HTTP Response /// An HTTP Response
pub struct Response(Box<InnerResponse>, &'static ResponsePool); pub struct Response(Box<InnerResponse>);
impl Response { impl Response {
#[inline] #[inline]
@ -92,7 +93,6 @@ impl Response {
} }
ResponseBuilder { ResponseBuilder {
pool: self.1,
response: Some(self.0), response: Some(self.0),
err: None, err: None,
cookies: jar, cookies: jar,
@ -108,33 +108,33 @@ impl Response {
/// Get the HTTP version of this response /// Get the HTTP version of this response
#[inline] #[inline]
pub fn version(&self) -> Option<Version> { pub fn version(&self) -> Option<Version> {
self.get_ref().version self.get_ref().head.version
} }
/// Get the headers from the response /// Get the headers from the response
#[inline] #[inline]
pub fn headers(&self) -> &HeaderMap { pub fn headers(&self) -> &HeaderMap {
&self.get_ref().headers &self.get_ref().head.headers
} }
/// Get a mutable reference to the headers /// Get a mutable reference to the headers
#[inline] #[inline]
pub fn headers_mut(&mut self) -> &mut HeaderMap { pub fn headers_mut(&mut self) -> &mut HeaderMap {
&mut self.get_mut().headers &mut self.get_mut().head.headers
} }
/// Get an iterator for the cookies set by this response /// Get an iterator for the cookies set by this response
#[inline] #[inline]
pub fn cookies(&self) -> CookieIter { pub fn cookies(&self) -> CookieIter {
CookieIter { CookieIter {
iter: self.get_ref().headers.get_all(header::SET_COOKIE).iter(), iter: self.get_ref().head.headers.get_all(header::SET_COOKIE).iter(),
} }
} }
/// Add a cookie to this response /// Add a cookie to this response
#[inline] #[inline]
pub fn add_cookie(&mut self, cookie: &Cookie) -> Result<(), HttpError> { pub fn add_cookie(&mut self, cookie: &Cookie) -> Result<(), HttpError> {
let h = &mut self.get_mut().headers; let h = &mut self.get_mut().head.headers;
HeaderValue::from_str(&cookie.to_string()) HeaderValue::from_str(&cookie.to_string())
.map(|c| { .map(|c| {
h.append(header::SET_COOKIE, c); h.append(header::SET_COOKIE, c);
@ -145,7 +145,7 @@ impl Response {
/// the number of cookies removed. /// the number of cookies removed.
#[inline] #[inline]
pub fn del_cookie(&mut self, name: &str) -> usize { pub fn del_cookie(&mut self, name: &str) -> usize {
let h = &mut self.get_mut().headers; let h = &mut self.get_mut().head.headers;
let vals: Vec<HeaderValue> = h let vals: Vec<HeaderValue> = h
.get_all(header::SET_COOKIE) .get_all(header::SET_COOKIE)
.iter() .iter()
@ -171,23 +171,23 @@ impl Response {
/// Get the response status code /// Get the response status code
#[inline] #[inline]
pub fn status(&self) -> StatusCode { pub fn status(&self) -> StatusCode {
self.get_ref().status self.get_ref().head.status
} }
/// Set the `StatusCode` for this response /// Set the `StatusCode` for this response
#[inline] #[inline]
pub fn status_mut(&mut self) -> &mut StatusCode { pub fn status_mut(&mut self) -> &mut StatusCode {
&mut self.get_mut().status &mut self.get_mut().head.status
} }
/// Get custom reason for the response /// Get custom reason for the response
#[inline] #[inline]
pub fn reason(&self) -> &str { pub fn reason(&self) -> &str {
if let Some(reason) = self.get_ref().reason { if let Some(reason) = self.get_ref().head.reason {
reason reason
} else { } else {
self.get_ref() self.get_ref()
.status .head.status
.canonical_reason() .canonical_reason()
.unwrap_or("<unknown status code>") .unwrap_or("<unknown status code>")
} }
@ -196,7 +196,7 @@ impl Response {
/// Set the custom reason for the response /// Set the custom reason for the response
#[inline] #[inline]
pub fn set_reason(&mut self, reason: &'static str) -> &mut Self { pub fn set_reason(&mut self, reason: &'static str) -> &mut Self {
self.get_mut().reason = Some(reason); self.get_mut().head.reason = Some(reason);
self self
} }
@ -279,7 +279,7 @@ impl Response {
} }
pub(crate) fn release(self) { pub(crate) fn release(self) {
self.1.release(self.0); ResponsePool::release(self.0);
} }
pub(crate) fn into_parts(self) -> ResponseParts { pub(crate) fn into_parts(self) -> ResponseParts {
@ -287,10 +287,7 @@ impl Response {
} }
pub(crate) fn from_parts(parts: ResponseParts) -> Response { pub(crate) fn from_parts(parts: ResponseParts) -> Response {
Response( Response(Box::new(InnerResponse::from_parts(parts)))
Box::new(InnerResponse::from_parts(parts)),
ResponsePool::get_pool(),
)
} }
} }
@ -299,13 +296,13 @@ impl fmt::Debug for Response {
let res = writeln!( let res = writeln!(
f, f,
"\nResponse {:?} {}{}", "\nResponse {:?} {}{}",
self.get_ref().version, self.get_ref().head.version,
self.get_ref().status, self.get_ref().head.status,
self.get_ref().reason.unwrap_or("") self.get_ref().head.reason.unwrap_or("")
); );
let _ = writeln!(f, " encoding: {:?}", self.get_ref().encoding); let _ = writeln!(f, " encoding: {:?}", self.get_ref().encoding);
let _ = writeln!(f, " headers:"); let _ = writeln!(f, " headers:");
for (key, val) in self.get_ref().headers.iter() { for (key, val) in self.get_ref().head.headers.iter() {
let _ = writeln!(f, " {:?}: {:?}", key, val); let _ = writeln!(f, " {:?}: {:?}", key, val);
} }
res res
@ -335,7 +332,6 @@ impl<'a> Iterator for CookieIter<'a> {
/// This type can be used to construct an instance of `Response` through a /// This type can be used to construct an instance of `Response` through a
/// builder-like pattern. /// builder-like pattern.
pub struct ResponseBuilder { pub struct ResponseBuilder {
pool: &'static ResponsePool,
response: Option<Box<InnerResponse>>, response: Option<Box<InnerResponse>>,
err: Option<HttpError>, err: Option<HttpError>,
cookies: Option<CookieJar>, cookies: Option<CookieJar>,
@ -346,7 +342,7 @@ impl ResponseBuilder {
#[inline] #[inline]
pub fn status(&mut self, status: StatusCode) -> &mut Self { pub fn status(&mut self, status: StatusCode) -> &mut Self {
if let Some(parts) = parts(&mut self.response, &self.err) { if let Some(parts) = parts(&mut self.response, &self.err) {
parts.status = status; parts.head.status = status;
} }
self self
} }
@ -357,7 +353,7 @@ impl ResponseBuilder {
#[inline] #[inline]
pub fn version(&mut self, version: Version) -> &mut Self { pub fn version(&mut self, version: Version) -> &mut Self {
if let Some(parts) = parts(&mut self.response, &self.err) { if let Some(parts) = parts(&mut self.response, &self.err) {
parts.version = Some(version); parts.head.version = Some(version);
} }
self self
} }
@ -382,7 +378,7 @@ impl ResponseBuilder {
if let Some(parts) = parts(&mut self.response, &self.err) { if let Some(parts) = parts(&mut self.response, &self.err) {
match hdr.try_into() { match hdr.try_into() {
Ok(value) => { Ok(value) => {
parts.headers.append(H::name(), value); parts.head.headers.append(H::name(), value);
} }
Err(e) => self.err = Some(e.into()), Err(e) => self.err = Some(e.into()),
} }
@ -413,7 +409,7 @@ impl ResponseBuilder {
match HeaderName::try_from(key) { match HeaderName::try_from(key) {
Ok(key) => match value.try_into() { Ok(key) => match value.try_into() {
Ok(value) => { Ok(value) => {
parts.headers.append(key, value); parts.head.headers.append(key, value);
} }
Err(e) => self.err = Some(e.into()), Err(e) => self.err = Some(e.into()),
}, },
@ -427,7 +423,7 @@ impl ResponseBuilder {
#[inline] #[inline]
pub fn reason(&mut self, reason: &'static str) -> &mut Self { pub fn reason(&mut self, reason: &'static str) -> &mut Self {
if let Some(parts) = parts(&mut self.response, &self.err) { if let Some(parts) = parts(&mut self.response, &self.err) {
parts.reason = Some(reason); parts.head.reason = Some(reason);
} }
self self
} }
@ -496,7 +492,7 @@ impl ResponseBuilder {
if let Some(parts) = parts(&mut self.response, &self.err) { if let Some(parts) = parts(&mut self.response, &self.err) {
match HeaderValue::try_from(value) { match HeaderValue::try_from(value) {
Ok(value) => { Ok(value) => {
parts.headers.insert(header::CONTENT_TYPE, value); parts.head.headers.insert(header::CONTENT_TYPE, value);
} }
Err(e) => self.err = Some(e.into()), Err(e) => self.err = Some(e.into()),
}; };
@ -620,13 +616,13 @@ impl ResponseBuilder {
if let Some(ref jar) = self.cookies { if let Some(ref jar) = self.cookies {
for cookie in jar.delta() { for cookie in jar.delta() {
match HeaderValue::from_str(&cookie.to_string()) { match HeaderValue::from_str(&cookie.to_string()) {
Ok(val) => response.headers.append(header::SET_COOKIE, val), Ok(val) => response.head.headers.append(header::SET_COOKIE, val),
Err(e) => return Error::from(e).into(), Err(e) => return Error::from(e).into(),
}; };
} }
} }
response.body = body.into(); response.body = body.into();
Response(response, self.pool) Response(response)
} }
#[inline] #[inline]
@ -656,7 +652,7 @@ impl ResponseBuilder {
Ok(body) => { Ok(body) => {
let contains = if let Some(parts) = parts(&mut self.response, &self.err) let contains = if let Some(parts) = parts(&mut self.response, &self.err)
{ {
parts.headers.contains_key(header::CONTENT_TYPE) parts.head.headers.contains_key(header::CONTENT_TYPE)
} else { } else {
true true
}; };
@ -681,7 +677,6 @@ impl ResponseBuilder {
/// This method construct new `ResponseBuilder` /// This method construct new `ResponseBuilder`
pub fn take(&mut self) -> ResponseBuilder { pub fn take(&mut self) -> ResponseBuilder {
ResponseBuilder { ResponseBuilder {
pool: self.pool,
response: self.response.take(), response: self.response.take(),
err: self.err.take(), err: self.err.take(),
cookies: self.cookies.take(), cookies: self.cookies.take(),
@ -765,12 +760,8 @@ impl From<BytesMut> for Response {
} }
} }
#[derive(Debug)]
struct InnerResponse { struct InnerResponse {
version: Option<Version>, head: ResponseHead,
headers: HeaderMap,
status: StatusCode,
reason: Option<&'static str>,
body: Body, body: Body,
chunked: Option<bool>, chunked: Option<bool>,
encoding: Option<ContentEncoding>, encoding: Option<ContentEncoding>,
@ -778,13 +769,11 @@ struct InnerResponse {
write_capacity: usize, write_capacity: usize,
response_size: u64, response_size: u64,
error: Option<Error>, error: Option<Error>,
pool: &'static ResponsePool,
} }
pub(crate) struct ResponseParts { pub(crate) struct ResponseParts {
version: Option<Version>, head: ResponseHead,
headers: HeaderMap,
status: StatusCode,
reason: Option<&'static str>,
body: Option<Bytes>, body: Option<Bytes>,
encoding: Option<ContentEncoding>, encoding: Option<ContentEncoding>,
connection_type: Option<ConnectionType>, connection_type: Option<ConnectionType>,
@ -793,13 +782,17 @@ pub(crate) struct ResponseParts {
impl InnerResponse { impl InnerResponse {
#[inline] #[inline]
fn new(status: StatusCode, body: Body) -> InnerResponse { fn new(status: StatusCode, body: Body, pool: &'static ResponsePool) -> InnerResponse {
InnerResponse { InnerResponse {
status, head: ResponseHead {
status,
version: None,
headers: HeaderMap::with_capacity(16),
reason: None,
flags: MessageFlags::empty(),
},
body, body,
version: None, pool,
headers: HeaderMap::with_capacity(16),
reason: None,
chunked: None, chunked: None,
encoding: None, encoding: None,
connection_type: None, connection_type: None,
@ -822,10 +815,7 @@ impl InnerResponse {
ResponseParts { ResponseParts {
body, body,
version: self.version, head: self.head,
headers: self.headers,
status: self.status,
reason: self.reason,
encoding: self.encoding, encoding: self.encoding,
connection_type: self.connection_type, connection_type: self.connection_type,
error: self.error, error: self.error,
@ -841,16 +831,14 @@ impl InnerResponse {
InnerResponse { InnerResponse {
body, body,
status: parts.status, head: parts.head,
version: parts.version,
headers: parts.headers,
reason: parts.reason,
chunked: None, chunked: None,
encoding: parts.encoding, encoding: parts.encoding,
connection_type: parts.connection_type, connection_type: parts.connection_type,
response_size: 0, response_size: 0,
write_capacity: MAX_WRITE_BUFFER_SIZE, write_capacity: MAX_WRITE_BUFFER_SIZE,
error: parts.error, error: parts.error,
pool: ResponsePool::pool(),
} }
} }
} }
@ -876,17 +864,15 @@ impl ResponsePool {
status: StatusCode, status: StatusCode,
) -> ResponseBuilder { ) -> ResponseBuilder {
if let Some(mut msg) = pool.0.borrow_mut().pop_front() { if let Some(mut msg) = pool.0.borrow_mut().pop_front() {
msg.status = status; msg.head.status = status;
ResponseBuilder { ResponseBuilder {
pool,
response: Some(msg), response: Some(msg),
err: None, err: None,
cookies: None, cookies: None,
} }
} else { } else {
let msg = Box::new(InnerResponse::new(status, Body::Empty)); let msg = Box::new(InnerResponse::new(status, Body::Empty, pool));
ResponseBuilder { ResponseBuilder {
pool,
response: Some(msg), response: Some(msg),
err: None, err: None,
cookies: None, cookies: None,
@ -901,12 +887,11 @@ impl ResponsePool {
body: Body, body: Body,
) -> Response { ) -> Response {
if let Some(mut msg) = pool.0.borrow_mut().pop_front() { if let Some(mut msg) = pool.0.borrow_mut().pop_front() {
msg.status = status; msg.head.status = status;
msg.body = body; msg.body = body;
Response(msg, pool) Response(msg)
} else { } else {
let msg = Box::new(InnerResponse::new(status, body)); Response(Box::new(InnerResponse::new(status, body, pool)))
Response(msg, pool)
} }
} }
@ -921,13 +906,11 @@ impl ResponsePool {
} }
#[inline] #[inline]
fn release(&self, mut inner: Box<InnerResponse>) { fn release(mut inner: Box<InnerResponse>) {
let mut p = self.0.borrow_mut(); let mut p = inner.pool.0.borrow_mut();
if p.len() < 128 { if p.len() < 128 {
inner.headers.clear(); inner.head.clear();
inner.version = None;
inner.chunked = None; inner.chunked = None;
inner.reason = None;
inner.encoding = None; inner.encoding = None;
inner.connection_type = None; inner.connection_type = None;
inner.response_size = 0; inner.response_size = 0;