mirror of
https://github.com/actix/actix-web.git
synced 2024-12-22 08:07:18 +00:00
explicit response release
This commit is contained in:
parent
32212bad1f
commit
800c404c72
2 changed files with 45 additions and 42 deletions
|
@ -35,7 +35,7 @@ pub enum ConnectionType {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An HTTP Response
|
/// An HTTP Response
|
||||||
pub struct HttpResponse(Box<InnerHttpResponse>);
|
pub struct HttpResponse(Box<InnerHttpResponse>, &'static HttpResponsePool);
|
||||||
|
|
||||||
impl HttpResponse {
|
impl HttpResponse {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -96,6 +96,7 @@ impl HttpResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
HttpResponseBuilder {
|
HttpResponseBuilder {
|
||||||
|
pool: self.1,
|
||||||
response: Some(self.0),
|
response: Some(self.0),
|
||||||
err: None,
|
err: None,
|
||||||
cookies: jar,
|
cookies: jar,
|
||||||
|
@ -282,12 +283,19 @@ impl HttpResponse {
|
||||||
self.get_mut().write_capacity = cap;
|
self.get_mut().write_capacity = cap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn release(self) {
|
||||||
|
self.1.release(self.0);
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn into_parts(self) -> HttpResponseParts {
|
pub(crate) fn into_parts(self) -> HttpResponseParts {
|
||||||
self.0.into_parts()
|
self.0.into_parts()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn from_parts(parts: HttpResponseParts) -> HttpResponse {
|
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
|
/// This type can be used to construct an instance of `HttpResponse` through a
|
||||||
/// builder-like pattern.
|
/// builder-like pattern.
|
||||||
pub struct HttpResponseBuilder {
|
pub struct HttpResponseBuilder {
|
||||||
|
pool: &'static HttpResponsePool,
|
||||||
response: Option<Box<InnerHttpResponse>>,
|
response: Option<Box<InnerHttpResponse>>,
|
||||||
err: Option<HttpError>,
|
err: Option<HttpError>,
|
||||||
cookies: Option<CookieJar>,
|
cookies: Option<CookieJar>,
|
||||||
|
@ -622,7 +631,7 @@ impl HttpResponseBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
response.body = body.into();
|
response.body = body.into();
|
||||||
HttpResponse(response)
|
HttpResponse(response, self.pool)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -670,6 +679,7 @@ impl HttpResponseBuilder {
|
||||||
/// This method construct new `HttpResponseBuilder`
|
/// This method construct new `HttpResponseBuilder`
|
||||||
pub fn take(&mut self) -> HttpResponseBuilder {
|
pub fn take(&mut self) -> HttpResponseBuilder {
|
||||||
HttpResponseBuilder {
|
HttpResponseBuilder {
|
||||||
|
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(),
|
||||||
|
@ -972,6 +982,7 @@ impl HttpResponsePool {
|
||||||
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.status = status;
|
||||||
HttpResponseBuilder {
|
HttpResponseBuilder {
|
||||||
|
pool,
|
||||||
response: Some(msg),
|
response: Some(msg),
|
||||||
err: None,
|
err: None,
|
||||||
cookies: None,
|
cookies: None,
|
||||||
|
@ -979,6 +990,7 @@ impl HttpResponsePool {
|
||||||
} else {
|
} else {
|
||||||
let msg = Box::new(InnerHttpResponse::new(status, Body::Empty));
|
let msg = Box::new(InnerHttpResponse::new(status, Body::Empty));
|
||||||
HttpResponseBuilder {
|
HttpResponseBuilder {
|
||||||
|
pool,
|
||||||
response: Some(msg),
|
response: Some(msg),
|
||||||
err: None,
|
err: None,
|
||||||
cookies: None,
|
cookies: None,
|
||||||
|
@ -993,10 +1005,10 @@ impl HttpResponsePool {
|
||||||
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.status = status;
|
||||||
msg.body = body;
|
msg.body = body;
|
||||||
HttpResponse(msg)
|
HttpResponse(msg, pool)
|
||||||
} else {
|
} else {
|
||||||
let msg = Box::new(InnerHttpResponse::new(status, body));
|
let msg = Box::new(InnerHttpResponse::new(status, body));
|
||||||
HttpResponse(msg)
|
HttpResponse(msg, pool)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1011,10 +1023,8 @@ impl HttpResponsePool {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn release(resp: HttpResponse) {
|
fn release(&self, mut inner: Box<InnerHttpResponse>) {
|
||||||
let mut inner = resp.0;
|
let mut p = self.0.borrow_mut();
|
||||||
POOL.with(|pool| {
|
|
||||||
let mut p = pool.0.borrow_mut();
|
|
||||||
if p.len() < 128 {
|
if p.len() < 128 {
|
||||||
inner.headers.clear();
|
inner.headers.clear();
|
||||||
inner.version = None;
|
inner.version = None;
|
||||||
|
@ -1027,7 +1037,6 @@ impl HttpResponsePool {
|
||||||
inner.write_capacity = MAX_WRITE_BUFFER_SIZE;
|
inner.write_capacity = MAX_WRITE_BUFFER_SIZE;
|
||||||
p.push_front(inner);
|
p.push_front(inner);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ use error::Error;
|
||||||
use handler::{AsyncResult, AsyncResultItem};
|
use handler::{AsyncResult, AsyncResultItem};
|
||||||
use header::ContentEncoding;
|
use header::ContentEncoding;
|
||||||
use httprequest::HttpRequest;
|
use httprequest::HttpRequest;
|
||||||
use httpresponse::{HttpResponse, HttpResponsePool};
|
use httpresponse::HttpResponse;
|
||||||
use middleware::{Finished, Middleware, Response, Started};
|
use middleware::{Finished, Middleware, Response, Started};
|
||||||
use server::{HttpHandlerTask, Writer, WriterState};
|
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,
|
info: &mut PipelineInfo<S>, mws: &[Box<Middleware<S>>], resp: HttpResponse,
|
||||||
) -> PipelineState<S, H> {
|
) -> PipelineState<S, H> {
|
||||||
if info.count == 0 {
|
if info.count == 0 {
|
||||||
Completed::init(info, resp)
|
resp.release();
|
||||||
|
Completed::init(info)
|
||||||
} else {
|
} else {
|
||||||
let mut state = FinishingMiddlewares {
|
let mut state = FinishingMiddlewares {
|
||||||
resp: Some(resp),
|
resp: Some(resp),
|
||||||
|
@ -741,7 +742,8 @@ impl<S: 'static, H> FinishingMiddlewares<S, H> {
|
||||||
}
|
}
|
||||||
self.fut = None;
|
self.fut = None;
|
||||||
if info.count == 0 {
|
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;
|
info.count -= 1;
|
||||||
|
@ -750,7 +752,8 @@ impl<S: 'static, H> FinishingMiddlewares<S, H> {
|
||||||
match state {
|
match state {
|
||||||
Finished::Done => {
|
Finished::Done => {
|
||||||
if info.count == 0 {
|
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) => {
|
Finished::Future(fut) => {
|
||||||
|
@ -762,20 +765,19 @@ impl<S: 'static, H> FinishingMiddlewares<S, H> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[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> {
|
impl<S, H> Completed<S, H> {
|
||||||
#[inline]
|
#[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 {
|
if let Some(ref err) = info.error {
|
||||||
error!("Error occurred during request handling: {}", err);
|
error!("Error occurred during request handling: {}", err);
|
||||||
}
|
}
|
||||||
|
|
||||||
if info.context.is_none() {
|
if info.context.is_none() {
|
||||||
HttpResponsePool::release(resp);
|
|
||||||
PipelineState::None
|
PipelineState::None
|
||||||
} else {
|
} 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>> {
|
fn poll(&mut self, info: &mut PipelineInfo<S>) -> Option<PipelineState<S, H>> {
|
||||||
match info.poll_context() {
|
match info.poll_context() {
|
||||||
Ok(Async::NotReady) => None,
|
Ok(Async::NotReady) => None,
|
||||||
Ok(Async::Ready(())) => {
|
Ok(Async::Ready(())) => Some(PipelineState::None),
|
||||||
HttpResponsePool::release(self.2.take().unwrap());
|
Err(_) => Some(PipelineState::Error),
|
||||||
Some(PipelineState::None)
|
|
||||||
}
|
|
||||||
Err(_) => {
|
|
||||||
HttpResponsePool::release(self.2.take().unwrap());
|
|
||||||
Some(PipelineState::Error)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -832,18 +828,16 @@ mod tests {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.block_on(lazy(|| {
|
.block_on(lazy(|| {
|
||||||
let mut info = PipelineInfo::new(HttpRequest::default());
|
let mut info = PipelineInfo::new(HttpRequest::default());
|
||||||
let resp = HttpResponse::new(StatusCode::OK);
|
Completed::<(), Inner<()>>::init(&mut info)
|
||||||
Completed::<(), Inner<()>>::init(&mut info, resp)
|
|
||||||
.is_none()
|
.is_none()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let req = HttpRequest::default();
|
let req = HttpRequest::default();
|
||||||
let ctx = HttpContext::new(req.clone(), MyActor);
|
let ctx = HttpContext::new(req.clone(), MyActor);
|
||||||
let addr = ctx.address();
|
let addr = ctx.address();
|
||||||
let resp = HttpResponse::new(StatusCode::OK);
|
|
||||||
let mut info = PipelineInfo::new(req);
|
let mut info = PipelineInfo::new(req);
|
||||||
info.context = Some(Box::new(ctx));
|
info.context = Some(Box::new(ctx));
|
||||||
let mut state = Completed::<(), Inner<()>>::init(&mut info, resp)
|
let mut state = Completed::<(), Inner<()>>::init(&mut info)
|
||||||
.completed()
|
.completed()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue