mirror of
https://github.com/fafhrd91/actix-web
synced 2024-11-28 01:52:57 +01:00
simplify httpresponse release
This commit is contained in:
parent
ee7d58dd7f
commit
70caa2552b
@ -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,43 +753,45 @@ 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 {
|
||||
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;
|
||||
@ -794,9 +801,8 @@ impl Pool {
|
||||
inner.response_size = 0;
|
||||
inner.error = None;
|
||||
inner.write_capacity = MAX_WRITE_BUFFER_SIZE;
|
||||
v.push_front(inner);
|
||||
pool.0.push_front(inner);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user