1
0
Fork 0
mirror of https://github.com/actix/actix-web.git synced 2024-10-21 09:23:54 +00:00

simplify httpresponse release

This commit is contained in:
Nikolay Kim 2018-03-20 15:51:19 -07:00
parent ee7d58dd7f
commit 70caa2552b
2 changed files with 47 additions and 41 deletions

View file

@ -1,7 +1,8 @@
//! Http response
use std::{mem, str, fmt};
use std::rc::Rc;
use std::io::Write;
use std::cell::RefCell;
use std::cell::UnsafeCell;
use std::collections::VecDeque;
use cookie::{Cookie, CookieJar};
@ -34,12 +35,12 @@ pub enum ConnectionType {
}
/// An HTTP Response
pub struct HttpResponse(Option<Box<InnerHttpResponse>>);
pub struct HttpResponse(Option<Box<InnerHttpResponse>>, Rc<UnsafeCell<Pool>>);
impl Drop for HttpResponse {
fn drop(&mut self) {
if let Some(inner) = self.0.take() {
Pool::release(inner)
Pool::release(&self.1, inner)
}
}
}
@ -61,8 +62,10 @@ impl HttpResponse {
/// Create http response builder with specific status.
#[inline]
pub fn build(status: StatusCode) -> HttpResponseBuilder {
let (msg, pool) = Pool::get(status);
HttpResponseBuilder {
response: Some(Pool::get(status)),
response: Some(msg),
pool: Some(pool),
err: None,
cookies: None,
}
@ -71,7 +74,8 @@ impl HttpResponse {
/// Constructs a response
#[inline]
pub fn new(status: StatusCode, body: Body) -> HttpResponse {
HttpResponse(Some(Pool::with_body(status, body)))
let (msg, pool) = Pool::with_body(status, body);
HttpResponse(Some(msg), pool)
}
/// Constructs a error response
@ -232,9 +236,9 @@ impl fmt::Debug for HttpResponse {
///
/// This type can be used to construct an instance of `HttpResponse` through a
/// builder-like pattern.
#[derive(Debug)]
pub struct HttpResponseBuilder {
response: Option<Box<InnerHttpResponse>>,
pool: Option<Rc<UnsafeCell<Pool>>>,
err: Option<HttpError>,
cookies: Option<CookieJar>,
}
@ -506,7 +510,7 @@ impl HttpResponseBuilder {
}
}
response.body = body.into();
Ok(HttpResponse(Some(response)))
Ok(HttpResponse(Some(response), self.pool.take().unwrap()))
}
/// Set a streaming body and generate `HttpResponse`.
@ -547,6 +551,7 @@ impl HttpResponseBuilder {
pub fn take(&mut self) -> HttpResponseBuilder {
HttpResponseBuilder {
response: self.response.take(),
pool: self.pool.take(),
err: self.err.take(),
cookies: self.cookies.take(),
}
@ -748,55 +753,56 @@ impl InnerHttpResponse {
/// Internal use only! unsafe
struct Pool(VecDeque<Box<InnerHttpResponse>>);
thread_local!(static POOL: RefCell<Pool> =
RefCell::new(Pool(VecDeque::with_capacity(128))));
thread_local!(static POOL: Rc<UnsafeCell<Pool>> =
Rc::new(UnsafeCell::new(Pool(VecDeque::with_capacity(128)))));
impl Pool {
#[inline]
fn get(status: StatusCode) -> Box<InnerHttpResponse> {
fn get(status: StatusCode) -> (Box<InnerHttpResponse>, Rc<UnsafeCell<Pool>>) {
POOL.with(|pool| {
if let Some(mut resp) = pool.borrow_mut().0.pop_front() {
let p = unsafe{&mut *pool.as_ref().get()};
if let Some(mut resp) = p.0.pop_front() {
resp.body = Body::Empty;
resp.status = status;
resp
(resp, Rc::clone(pool))
} else {
Box::new(InnerHttpResponse::new(status, Body::Empty))
(Box::new(InnerHttpResponse::new(status, Body::Empty)), Rc::clone(pool))
}
})
}
#[inline]
fn with_body(status: StatusCode, body: Body) -> Box<InnerHttpResponse> {
fn with_body(status: StatusCode, body: Body)
-> (Box<InnerHttpResponse>, Rc<UnsafeCell<Pool>>) {
POOL.with(|pool| {
if let Some(mut resp) = pool.borrow_mut().0.pop_front() {
let p = unsafe{&mut *pool.as_ref().get()};
if let Some(mut resp) = p.0.pop_front() {
resp.status = status;
resp.body = body;
resp
(resp, Rc::clone(pool))
} else {
Box::new(InnerHttpResponse::new(status, body))
(Box::new(InnerHttpResponse::new(status, body)), Rc::clone(pool))
}
})
}
#[inline(always)]
#[cfg_attr(feature = "cargo-clippy", allow(boxed_local, inline_always))]
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 = 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;
v.push_front(inner);
}
})
fn release(pool: &Rc<UnsafeCell<Pool>>, mut inner: Box<InnerHttpResponse>) {
let pool = unsafe{&mut *pool.as_ref().get()};
if pool.0.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;
pool.0.push_front(inner);
}
}
}

View file

@ -490,6 +490,8 @@ impl Reader {
fn parse_message<H>(buf: &mut BytesMut, settings: &WorkerSettings<H>)
-> Poll<(HttpRequest, Option<PayloadInfo>), ParseError> {
// Parse http message
let mut has_te = false;
let mut has_upgrade = false;
let msg = {
let bytes_ptr = buf.as_ref().as_ptr() as usize;
let mut headers: [httparse::Header; MAX_HEADERS] =
@ -500,7 +502,7 @@ impl Reader {
let mut req = httparse::Request::new(&mut headers);
match req.parse(b)? {
httparse::Status::Complete(len) => {
let method = Method::try_from(req.method.unwrap())
let method = Method::from_bytes(req.method.unwrap().as_bytes())
.map_err(|_| ParseError::Method)?;
//let path = req.path.unwrap();
//let path_start = path.as_ptr() as usize - bytes_ptr;
@ -527,7 +529,9 @@ impl Reader {
{
let msg_mut = msg.get_mut();
for header in headers[..headers_len].iter() {
if let Ok(name) = HeaderName::try_from(header.name) {
if let Ok(name) = HeaderName::from_bytes(header.name.as_bytes()) {
has_te = has_te || name == header::TRANSFER_ENCODING;
has_upgrade = has_upgrade || name == header::UPGRADE;
let v_start = header.value.as_ptr() as usize - bytes_ptr;
let v_end = v_start + header.value.len();
let value = unsafe {
@ -540,8 +544,6 @@ impl Reader {
}
msg_mut.uri = path;
//msg_mut.uri = Uri::from_shared(
//slice.slice(path.0, path.1)).map_err(ParseError::Uri)?;
msg_mut.method = method;
msg_mut.version = version;
}
@ -563,12 +565,10 @@ impl Reader {
debug!("illegal Content-Length: {:?}", len);
return Err(ParseError::Header)
}
} else if chunked(&msg.get_mut().headers)? {
} else if has_te && chunked(&msg.get_mut().headers)? {
// Chunked encoding
Some(Decoder::chunked())
} else if msg.get_ref().headers.contains_key(header::UPGRADE) ||
msg.get_ref().method == Method::CONNECT
{
} else if has_upgrade || msg.get_ref().method == Method::CONNECT {
Some(Decoder::eof())
} else {
None