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

explicit response release

This commit is contained in:
Nikolay Kim 2018-06-25 10:10:02 +06:00
parent 32212bad1f
commit 800c404c72
2 changed files with 45 additions and 42 deletions

View File

@ -35,7 +35,7 @@ pub enum ConnectionType {
}
/// An HTTP Response
pub struct HttpResponse(Box<InnerHttpResponse>);
pub struct HttpResponse(Box<InnerHttpResponse>, &'static HttpResponsePool);
impl HttpResponse {
#[inline]
@ -96,6 +96,7 @@ impl HttpResponse {
}
HttpResponseBuilder {
pool: self.1,
response: Some(self.0),
err: None,
cookies: jar,
@ -282,12 +283,19 @@ impl HttpResponse {
self.get_mut().write_capacity = cap;
}
pub(crate) fn release(self) {
self.1.release(self.0);
}
pub(crate) fn into_parts(self) -> HttpResponseParts {
self.0.into_parts()
}
pub(crate) fn from_parts(parts: HttpResponseParts) -> HttpResponse {
HttpResponse(Box::new(InnerHttpResponse::from_parts(parts)))
HttpResponse(
Box::new(InnerHttpResponse::from_parts(parts)),
HttpResponsePool::get_pool(),
)
}
}
@ -332,6 +340,7 @@ impl<'a> Iterator for CookieIter<'a> {
/// This type can be used to construct an instance of `HttpResponse` through a
/// builder-like pattern.
pub struct HttpResponseBuilder {
pool: &'static HttpResponsePool,
response: Option<Box<InnerHttpResponse>>,
err: Option<HttpError>,
cookies: Option<CookieJar>,
@ -622,7 +631,7 @@ impl HttpResponseBuilder {
}
}
response.body = body.into();
HttpResponse(response)
HttpResponse(response, self.pool)
}
#[inline]
@ -670,6 +679,7 @@ impl HttpResponseBuilder {
/// This method construct new `HttpResponseBuilder`
pub fn take(&mut self) -> HttpResponseBuilder {
HttpResponseBuilder {
pool: self.pool,
response: self.response.take(),
err: self.err.take(),
cookies: self.cookies.take(),
@ -972,6 +982,7 @@ impl HttpResponsePool {
if let Some(mut msg) = pool.0.borrow_mut().pop_front() {
msg.status = status;
HttpResponseBuilder {
pool,
response: Some(msg),
err: None,
cookies: None,
@ -979,6 +990,7 @@ impl HttpResponsePool {
} else {
let msg = Box::new(InnerHttpResponse::new(status, Body::Empty));
HttpResponseBuilder {
pool,
response: Some(msg),
err: None,
cookies: None,
@ -993,10 +1005,10 @@ impl HttpResponsePool {
if let Some(mut msg) = pool.0.borrow_mut().pop_front() {
msg.status = status;
msg.body = body;
HttpResponse(msg)
HttpResponse(msg, pool)
} else {
let msg = Box::new(InnerHttpResponse::new(status, body));
HttpResponse(msg)
HttpResponse(msg, pool)
}
}
@ -1011,23 +1023,20 @@ impl HttpResponsePool {
}
#[inline]
pub(crate) fn release(resp: HttpResponse) {
let mut inner = resp.0;
POOL.with(|pool| {
let mut p = pool.0.borrow_mut();
if p.len() < 128 {
inner.headers.clear();
inner.version = None;
inner.chunked = None;
inner.reason = None;
inner.encoding = None;
inner.connection_type = None;
inner.response_size = 0;
inner.error = None;
inner.write_capacity = MAX_WRITE_BUFFER_SIZE;
p.push_front(inner);
}
});
fn release(&self, mut inner: Box<InnerHttpResponse>) {
let mut p = self.0.borrow_mut();
if p.len() < 128 {
inner.headers.clear();
inner.version = None;
inner.chunked = None;
inner.reason = None;
inner.encoding = None;
inner.connection_type = None;
inner.response_size = 0;
inner.error = None;
inner.write_capacity = MAX_WRITE_BUFFER_SIZE;
p.push_front(inner);
}
}
}

View File

@ -13,7 +13,7 @@ use error::Error;
use handler::{AsyncResult, AsyncResultItem};
use header::ContentEncoding;
use httprequest::HttpRequest;
use httpresponse::{HttpResponse, HttpResponsePool};
use httpresponse::HttpResponse;
use middleware::{Finished, Middleware, Response, Started};
use server::{HttpHandlerTask, Writer, WriterState};
@ -703,7 +703,8 @@ impl<S: 'static, H> FinishingMiddlewares<S, H> {
info: &mut PipelineInfo<S>, mws: &[Box<Middleware<S>>], resp: HttpResponse,
) -> PipelineState<S, H> {
if info.count == 0 {
Completed::init(info, resp)
resp.release();
Completed::init(info)
} else {
let mut state = FinishingMiddlewares {
resp: Some(resp),
@ -741,7 +742,8 @@ impl<S: 'static, H> FinishingMiddlewares<S, H> {
}
self.fut = None;
if info.count == 0 {
return Some(Completed::init(info, self.resp.take().unwrap()));
self.resp.take().unwrap().release();
return Some(Completed::init(info));
}
info.count -= 1;
@ -750,7 +752,8 @@ impl<S: 'static, H> FinishingMiddlewares<S, H> {
match state {
Finished::Done => {
if info.count == 0 {
return Some(Completed::init(info, self.resp.take().unwrap()));
self.resp.take().unwrap().release();
return Some(Completed::init(info));
}
}
Finished::Future(fut) => {
@ -762,20 +765,19 @@ impl<S: 'static, H> FinishingMiddlewares<S, H> {
}
#[derive(Debug)]
struct Completed<S, H>(PhantomData<S>, PhantomData<H>, Option<HttpResponse>);
struct Completed<S, H>(PhantomData<S>, PhantomData<H>);
impl<S, H> Completed<S, H> {
#[inline]
fn init(info: &mut PipelineInfo<S>, resp: HttpResponse) -> PipelineState<S, H> {
fn init(info: &mut PipelineInfo<S>) -> PipelineState<S, H> {
if let Some(ref err) = info.error {
error!("Error occurred during request handling: {}", err);
}
if info.context.is_none() {
HttpResponsePool::release(resp);
PipelineState::None
} else {
PipelineState::Completed(Completed(PhantomData, PhantomData, Some(resp)))
PipelineState::Completed(Completed(PhantomData, PhantomData))
}
}
@ -783,14 +785,8 @@ impl<S, H> Completed<S, H> {
fn poll(&mut self, info: &mut PipelineInfo<S>) -> Option<PipelineState<S, H>> {
match info.poll_context() {
Ok(Async::NotReady) => None,
Ok(Async::Ready(())) => {
HttpResponsePool::release(self.2.take().unwrap());
Some(PipelineState::None)
}
Err(_) => {
HttpResponsePool::release(self.2.take().unwrap());
Some(PipelineState::Error)
}
Ok(Async::Ready(())) => Some(PipelineState::None),
Err(_) => Some(PipelineState::Error),
}
}
}
@ -832,18 +828,16 @@ mod tests {
.unwrap()
.block_on(lazy(|| {
let mut info = PipelineInfo::new(HttpRequest::default());
let resp = HttpResponse::new(StatusCode::OK);
Completed::<(), Inner<()>>::init(&mut info, resp)
Completed::<(), Inner<()>>::init(&mut info)
.is_none()
.unwrap();
let req = HttpRequest::default();
let ctx = HttpContext::new(req.clone(), MyActor);
let addr = ctx.address();
let resp = HttpResponse::new(StatusCode::OK);
let mut info = PipelineInfo::new(req);
info.context = Some(Box::new(ctx));
let mut state = Completed::<(), Inner<()>>::init(&mut info, resp)
let mut state = Completed::<(), Inner<()>>::init(&mut info)
.completed()
.unwrap();