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

cleanup response

This commit is contained in:
Nikolay Kim 2017-12-15 20:00:12 -08:00
parent a8b2f1b821
commit 1daf50095a
3 changed files with 116 additions and 115 deletions

View File

@ -110,6 +110,7 @@ impl Responder for HttpResponse {
type Item = Reply; type Item = Reply;
type Error = Error; type Error = Error;
#[inline]
fn respond_to(self, _: HttpRequest) -> Result<Reply, Error> { fn respond_to(self, _: HttpRequest) -> Result<Reply, Error> {
Ok(Reply(ReplyItem::Message(self))) Ok(Reply(ReplyItem::Message(self)))
} }
@ -117,6 +118,7 @@ impl Responder for HttpResponse {
impl From<HttpResponse> for Reply { impl From<HttpResponse> for Reply {
#[inline]
fn from(resp: HttpResponse) -> Reply { fn from(resp: HttpResponse) -> Reply {
Reply(ReplyItem::Message(resp)) Reply(ReplyItem::Message(resp))
} }
@ -152,6 +154,7 @@ impl<A: Actor<Context=HttpContext<A, S>>, S: 'static> Responder for HttpContext<
type Item = Reply; type Item = Reply;
type Error = Error; type Error = Error;
#[inline]
fn respond_to(self, _: HttpRequest) -> Result<Reply, Error> { fn respond_to(self, _: HttpRequest) -> Result<Reply, Error> {
Ok(Reply(ReplyItem::Actor(Box::new(self)))) Ok(Reply(ReplyItem::Actor(Box::new(self))))
} }
@ -159,6 +162,7 @@ impl<A: Actor<Context=HttpContext<A, S>>, S: 'static> Responder for HttpContext<
impl<A: Actor<Context=HttpContext<A, S>>, S: 'static> From<HttpContext<A, S>> for Reply { impl<A: Actor<Context=HttpContext<A, S>>, S: 'static> From<HttpContext<A, S>> for Reply {
#[inline]
fn from(ctx: HttpContext<A, S>) -> Reply { fn from(ctx: HttpContext<A, S>) -> Reply {
Reply(ReplyItem::Actor(Box::new(ctx))) Reply(ReplyItem::Actor(Box::new(ctx)))
} }
@ -169,6 +173,7 @@ impl Responder for Box<Future<Item=HttpResponse, Error=Error>>
type Item = Reply; type Item = Reply;
type Error = Error; type Error = Error;
#[inline]
fn respond_to(self, _: HttpRequest) -> Result<Reply, Error> { fn respond_to(self, _: HttpRequest) -> Result<Reply, Error> {
Ok(Reply(ReplyItem::Future(self))) Ok(Reply(ReplyItem::Future(self)))
} }

View File

@ -29,86 +29,6 @@ pub enum ConnectionType {
Upgrade, Upgrade,
} }
#[derive(Debug)]
struct InnerHttpResponse {
version: Option<Version>,
headers: HeaderMap,
status: StatusCode,
reason: Option<&'static str>,
body: Body,
chunked: bool,
encoding: ContentEncoding,
connection_type: Option<ConnectionType>,
response_size: u64,
error: Option<Error>,
}
impl InnerHttpResponse {
#[inline]
fn new(status: StatusCode, body: Body) -> InnerHttpResponse {
InnerHttpResponse {
version: None,
headers: HeaderMap::with_capacity(8),
status: status,
reason: None,
body: body,
chunked: false,
encoding: ContentEncoding::Auto,
connection_type: None,
response_size: 0,
error: None,
}
}
}
impl Default for InnerHttpResponse {
fn default() -> InnerHttpResponse {
InnerHttpResponse::new(StatusCode::OK, Body::Empty)
}
}
/// Internal use only! unsafe
struct Pool(VecDeque<Box<InnerHttpResponse>>);
thread_local!(static POOL: RefCell<Pool> = RefCell::new(Pool::new()));
impl Pool {
fn new() -> Pool {
Pool(VecDeque::with_capacity(128))
}
fn get() -> Box<InnerHttpResponse> {
POOL.with(|pool| {
if let Some(resp) = pool.borrow_mut().0.pop_front() {
resp
} else {
Box::new(InnerHttpResponse::default())
}
})
}
#[cfg_attr(feature = "cargo-clippy", allow(boxed_local))]
fn release(mut inner: Box<InnerHttpResponse>) {
POOL.with(|pool| {
if pool.borrow().0.len() < 128 {
inner.version.take();
inner.headers.clear();
inner.chunked = false;
inner.reason.take();
inner.body = Body::Empty;
inner.encoding = ContentEncoding::Auto;
inner.connection_type.take();
inner.response_size = 0;
inner.error.take();
pool.borrow_mut().0.push_front(inner);
}
})
}
}
/// An HTTP Response /// An HTTP Response
pub struct HttpResponse(Option<Box<InnerHttpResponse>>); pub struct HttpResponse(Option<Box<InnerHttpResponse>>);
@ -123,27 +43,22 @@ impl Drop for HttpResponse {
impl HttpResponse { impl HttpResponse {
#[inline(always)] #[inline(always)]
#[cfg_attr(feature = "cargo-clippy", allow(inline_always))]
fn get_ref(&self) -> &InnerHttpResponse { fn get_ref(&self) -> &InnerHttpResponse {
self.0.as_ref().unwrap() self.0.as_ref().unwrap()
} }
#[inline(always)] #[inline(always)]
#[cfg_attr(feature = "cargo-clippy", allow(inline_always))]
fn get_mut(&mut self) -> &mut InnerHttpResponse { fn get_mut(&mut self) -> &mut InnerHttpResponse {
self.0.as_mut().unwrap() self.0.as_mut().unwrap()
} }
#[inline]
fn from_inner(inner: Box<InnerHttpResponse>) -> HttpResponse {
HttpResponse(Some(inner))
}
/// Create http response builder with specific status. /// Create http response builder with specific status.
#[inline] #[inline]
pub fn build(status: StatusCode) -> HttpResponseBuilder { pub fn build(status: StatusCode) -> HttpResponseBuilder {
let mut inner = Pool::get();
inner.status = status;
HttpResponseBuilder { HttpResponseBuilder {
response: Some(inner), response: Some(Pool::get(status)),
err: None, err: None,
cookies: None, cookies: None,
} }
@ -152,10 +67,7 @@ impl HttpResponse {
/// Constructs a response /// Constructs a response
#[inline] #[inline]
pub fn new(status: StatusCode, body: Body) -> HttpResponse { pub fn new(status: StatusCode, body: Body) -> HttpResponse {
let mut inner = Pool::get(); HttpResponse(Some(Pool::with_body(status, body)))
inner.status = status;
inner.body = body;
HttpResponse(Some(inner))
} }
/// Constructs a error response /// Constructs a error response
@ -470,7 +382,7 @@ impl HttpResponseBuilder {
} }
} }
response.body = body.into(); response.body = body.into();
Ok(HttpResponse::from_inner(response)) Ok(HttpResponse(Some(response)))
} }
/// Set a json body and generate `HttpResponse` /// Set a json body and generate `HttpResponse`
@ -495,6 +407,7 @@ impl HttpResponseBuilder {
} }
} }
#[inline]
#[cfg_attr(feature = "cargo-clippy", allow(borrowed_box))] #[cfg_attr(feature = "cargo-clippy", allow(borrowed_box))]
fn parts<'a>(parts: &'a mut Option<Box<InnerHttpResponse>>, err: &Option<HttpError>) fn parts<'a>(parts: &'a mut Option<Box<InnerHttpResponse>>, err: &Option<HttpError>)
-> Option<&'a mut Box<InnerHttpResponse>> -> Option<&'a mut Box<InnerHttpResponse>>
@ -525,6 +438,7 @@ impl Responder for HttpResponseBuilder {
type Item = HttpResponse; type Item = HttpResponse;
type Error = HttpError; type Error = HttpError;
#[inline]
fn respond_to(mut self, _: HttpRequest) -> Result<HttpResponse, HttpError> { fn respond_to(mut self, _: HttpRequest) -> Result<HttpResponse, HttpError> {
self.finish() self.finish()
} }
@ -650,6 +564,93 @@ impl Responder for BytesMut {
} }
} }
#[derive(Debug)]
struct InnerHttpResponse {
version: Option<Version>,
headers: HeaderMap,
status: StatusCode,
reason: Option<&'static str>,
body: Body,
chunked: bool,
encoding: ContentEncoding,
connection_type: Option<ConnectionType>,
response_size: u64,
error: Option<Error>,
}
impl InnerHttpResponse {
#[inline]
fn new(status: StatusCode, body: Body) -> InnerHttpResponse {
InnerHttpResponse {
version: None,
headers: HeaderMap::with_capacity(8),
status: status,
reason: None,
body: body,
chunked: false,
encoding: ContentEncoding::Auto,
connection_type: None,
response_size: 0,
error: None,
}
}
}
/// Internal use only! unsafe
struct Pool(VecDeque<Box<InnerHttpResponse>>);
thread_local!(static POOL: RefCell<Pool> = RefCell::new(Pool::new()));
impl Pool {
fn new() -> Pool {
Pool(VecDeque::with_capacity(128))
}
fn get(status: StatusCode) -> Box<InnerHttpResponse> {
POOL.with(|pool| {
if let Some(mut resp) = pool.borrow_mut().0.pop_front() {
resp.body = Body::Empty;
resp.status = status;
resp
} else {
Box::new(InnerHttpResponse::new(status, Body::Empty))
}
})
}
fn with_body(status: StatusCode, body: Body) -> Box<InnerHttpResponse> {
POOL.with(|pool| {
if let Some(mut resp) = pool.borrow_mut().0.pop_front() {
resp.status = status;
resp.body = Body::Empty;
resp
} else {
Box::new(InnerHttpResponse::new(status, body))
}
})
}
#[cfg_attr(feature = "cargo-clippy", allow(boxed_local))]
fn release(mut inner: Box<InnerHttpResponse>) {
POOL.with(|pool| {
let v = &mut pool.borrow_mut().0;
if v.len() < 128 {
inner.headers.clear();
inner.version = None;
inner.chunked = false;
inner.reason = None;
inner.encoding = ContentEncoding::Auto;
inner.connection_type = None;
inner.response_size = 0;
inner.error = None;
v.push_front(inner);
}
})
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View File

@ -408,19 +408,19 @@ struct WaitingResponse<S> {
impl<S> WaitingResponse<S> { impl<S> WaitingResponse<S> {
#[inline]
fn init(info: &mut PipelineInfo<S>, reply: Reply) -> PipelineState<S> fn init(info: &mut PipelineInfo<S>, reply: Reply) -> PipelineState<S>
{ {
let stream = match reply.into() { match reply.into() {
ReplyItem::Message(resp) => ReplyItem::Message(resp) =>
return RunMiddlewares::init(info, resp), RunMiddlewares::init(info, resp),
ReplyItem::Actor(ctx) => ReplyItem::Actor(ctx) =>
PipelineResponse::Context(ctx),
ReplyItem::Future(fut) =>
PipelineResponse::Response(fut),
};
PipelineState::Handler( PipelineState::Handler(
WaitingResponse { stream: stream, _s: PhantomData }) WaitingResponse { stream: PipelineResponse::Context(ctx), _s: PhantomData }),
ReplyItem::Future(fut) =>
PipelineState::Handler(
WaitingResponse { stream: PipelineResponse::Response(fut), _s: PhantomData }),
}
} }
fn poll(mut self, info: &mut PipelineInfo<S>) -> Result<PipelineState<S>, PipelineState<S>> { fn poll(mut self, info: &mut PipelineInfo<S>) -> Result<PipelineState<S>, PipelineState<S>> {
@ -587,15 +587,6 @@ enum IOState {
Done, Done,
} }
impl IOState {
fn is_done(&self) -> bool {
match *self {
IOState::Done => true,
_ => false
}
}
}
struct DrainVec(Vec<Rc<RefCell<DrainFut>>>); struct DrainVec(Vec<Rc<RefCell<DrainFut>>>);
impl Drop for DrainVec { impl Drop for DrainVec {
@ -608,6 +599,7 @@ impl Drop for DrainVec {
impl<S> ProcessResponse<S> { impl<S> ProcessResponse<S> {
#[inline]
fn init(resp: HttpResponse) -> PipelineState<S> fn init(resp: HttpResponse) -> PipelineState<S>
{ {
PipelineState::Response( PipelineState::Response(
@ -779,11 +771,12 @@ impl<S> ProcessResponse<S> {
} }
// response is completed // response is completed
if self.iostate.is_done() { match self.iostate {
IOState::Done => {
self.resp.set_response_size(io.written()); self.resp.set_response_size(io.written());
Ok(FinishingMiddlewares::init(info, self.resp)) Ok(FinishingMiddlewares::init(info, self.resp))
} else { }
Err(PipelineState::Response(self)) _ => Err(PipelineState::Response(self))
} }
} }
} }
@ -850,6 +843,7 @@ struct Completed<S>(PhantomData<S>);
impl<S> Completed<S> { impl<S> Completed<S> {
#[inline]
fn init(info: &mut PipelineInfo<S>) -> PipelineState<S> { fn init(info: &mut PipelineInfo<S>) -> PipelineState<S> {
if info.context.is_none() { if info.context.is_none() {
PipelineState::None PipelineState::None
@ -858,6 +852,7 @@ impl<S> Completed<S> {
} }
} }
#[inline]
fn poll(self, info: &mut PipelineInfo<S>) -> Result<PipelineState<S>, PipelineState<S>> { fn poll(self, info: &mut PipelineInfo<S>) -> Result<PipelineState<S>, PipelineState<S>> {
match info.poll_context() { match info.poll_context() {
Ok(Async::NotReady) => Ok(PipelineState::Completed(Completed(PhantomData))), Ok(Async::NotReady) => Ok(PipelineState::Completed(Completed(PhantomData))),