mirror of
https://github.com/fafhrd91/actix-web
synced 2024-11-24 08:22:59 +01:00
simplify httpresponse release
This commit is contained in:
parent
ee7d58dd7f
commit
70caa2552b
@ -1,7 +1,8 @@
|
|||||||
//! Http response
|
//! Http response
|
||||||
use std::{mem, str, fmt};
|
use std::{mem, str, fmt};
|
||||||
|
use std::rc::Rc;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::cell::RefCell;
|
use std::cell::UnsafeCell;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
use cookie::{Cookie, CookieJar};
|
use cookie::{Cookie, CookieJar};
|
||||||
@ -34,12 +35,12 @@ pub enum ConnectionType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// An HTTP Response
|
/// An HTTP Response
|
||||||
pub struct HttpResponse(Option<Box<InnerHttpResponse>>);
|
pub struct HttpResponse(Option<Box<InnerHttpResponse>>, Rc<UnsafeCell<Pool>>);
|
||||||
|
|
||||||
impl Drop for HttpResponse {
|
impl Drop for HttpResponse {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if let Some(inner) = self.0.take() {
|
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.
|
/// Create http response builder with specific status.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn build(status: StatusCode) -> HttpResponseBuilder {
|
pub fn build(status: StatusCode) -> HttpResponseBuilder {
|
||||||
|
let (msg, pool) = Pool::get(status);
|
||||||
HttpResponseBuilder {
|
HttpResponseBuilder {
|
||||||
response: Some(Pool::get(status)),
|
response: Some(msg),
|
||||||
|
pool: Some(pool),
|
||||||
err: None,
|
err: None,
|
||||||
cookies: None,
|
cookies: None,
|
||||||
}
|
}
|
||||||
@ -71,7 +74,8 @@ 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 {
|
||||||
HttpResponse(Some(Pool::with_body(status, body)))
|
let (msg, pool) = Pool::with_body(status, body);
|
||||||
|
HttpResponse(Some(msg), pool)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs a error response
|
/// 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
|
/// This type can be used to construct an instance of `HttpResponse` through a
|
||||||
/// builder-like pattern.
|
/// builder-like pattern.
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct HttpResponseBuilder {
|
pub struct HttpResponseBuilder {
|
||||||
response: Option<Box<InnerHttpResponse>>,
|
response: Option<Box<InnerHttpResponse>>,
|
||||||
|
pool: Option<Rc<UnsafeCell<Pool>>>,
|
||||||
err: Option<HttpError>,
|
err: Option<HttpError>,
|
||||||
cookies: Option<CookieJar>,
|
cookies: Option<CookieJar>,
|
||||||
}
|
}
|
||||||
@ -506,7 +510,7 @@ impl HttpResponseBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
response.body = body.into();
|
response.body = body.into();
|
||||||
Ok(HttpResponse(Some(response)))
|
Ok(HttpResponse(Some(response), self.pool.take().unwrap()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a streaming body and generate `HttpResponse`.
|
/// Set a streaming body and generate `HttpResponse`.
|
||||||
@ -547,6 +551,7 @@ impl HttpResponseBuilder {
|
|||||||
pub fn take(&mut self) -> HttpResponseBuilder {
|
pub fn take(&mut self) -> HttpResponseBuilder {
|
||||||
HttpResponseBuilder {
|
HttpResponseBuilder {
|
||||||
response: self.response.take(),
|
response: self.response.take(),
|
||||||
|
pool: self.pool.take(),
|
||||||
err: self.err.take(),
|
err: self.err.take(),
|
||||||
cookies: self.cookies.take(),
|
cookies: self.cookies.take(),
|
||||||
}
|
}
|
||||||
@ -748,55 +753,56 @@ impl InnerHttpResponse {
|
|||||||
/// Internal use only! unsafe
|
/// Internal use only! unsafe
|
||||||
struct Pool(VecDeque<Box<InnerHttpResponse>>);
|
struct Pool(VecDeque<Box<InnerHttpResponse>>);
|
||||||
|
|
||||||
thread_local!(static POOL: RefCell<Pool> =
|
thread_local!(static POOL: Rc<UnsafeCell<Pool>> =
|
||||||
RefCell::new(Pool(VecDeque::with_capacity(128))));
|
Rc::new(UnsafeCell::new(Pool(VecDeque::with_capacity(128)))));
|
||||||
|
|
||||||
impl Pool {
|
impl Pool {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get(status: StatusCode) -> Box<InnerHttpResponse> {
|
fn get(status: StatusCode) -> (Box<InnerHttpResponse>, Rc<UnsafeCell<Pool>>) {
|
||||||
POOL.with(|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.body = Body::Empty;
|
||||||
resp.status = status;
|
resp.status = status;
|
||||||
resp
|
(resp, Rc::clone(pool))
|
||||||
} else {
|
} else {
|
||||||
Box::new(InnerHttpResponse::new(status, Body::Empty))
|
(Box::new(InnerHttpResponse::new(status, Body::Empty)), Rc::clone(pool))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[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| {
|
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.status = status;
|
||||||
resp.body = body;
|
resp.body = body;
|
||||||
resp
|
(resp, Rc::clone(pool))
|
||||||
} else {
|
} else {
|
||||||
Box::new(InnerHttpResponse::new(status, body))
|
(Box::new(InnerHttpResponse::new(status, body)), Rc::clone(pool))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[cfg_attr(feature = "cargo-clippy", allow(boxed_local, inline_always))]
|
#[cfg_attr(feature = "cargo-clippy", allow(boxed_local, inline_always))]
|
||||||
fn release(mut inner: Box<InnerHttpResponse>) {
|
fn release(pool: &Rc<UnsafeCell<Pool>>, mut inner: Box<InnerHttpResponse>) {
|
||||||
POOL.with(|pool| {
|
let pool = unsafe{&mut *pool.as_ref().get()};
|
||||||
let v = &mut pool.borrow_mut().0;
|
if pool.0.len() < 128 {
|
||||||
if v.len() < 128 {
|
inner.headers.clear();
|
||||||
inner.headers.clear();
|
inner.version = None;
|
||||||
inner.version = None;
|
inner.chunked = None;
|
||||||
inner.chunked = None;
|
inner.reason = None;
|
||||||
inner.reason = None;
|
inner.encoding = None;
|
||||||
inner.encoding = None;
|
inner.connection_type = None;
|
||||||
inner.connection_type = None;
|
inner.response_size = 0;
|
||||||
inner.response_size = 0;
|
inner.error = None;
|
||||||
inner.error = None;
|
inner.write_capacity = MAX_WRITE_BUFFER_SIZE;
|
||||||
inner.write_capacity = MAX_WRITE_BUFFER_SIZE;
|
pool.0.push_front(inner);
|
||||||
v.push_front(inner);
|
}
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -490,6 +490,8 @@ impl Reader {
|
|||||||
fn parse_message<H>(buf: &mut BytesMut, settings: &WorkerSettings<H>)
|
fn parse_message<H>(buf: &mut BytesMut, settings: &WorkerSettings<H>)
|
||||||
-> Poll<(HttpRequest, Option<PayloadInfo>), ParseError> {
|
-> Poll<(HttpRequest, Option<PayloadInfo>), ParseError> {
|
||||||
// Parse http message
|
// Parse http message
|
||||||
|
let mut has_te = false;
|
||||||
|
let mut has_upgrade = false;
|
||||||
let msg = {
|
let msg = {
|
||||||
let bytes_ptr = buf.as_ref().as_ptr() as usize;
|
let bytes_ptr = buf.as_ref().as_ptr() as usize;
|
||||||
let mut headers: [httparse::Header; MAX_HEADERS] =
|
let mut headers: [httparse::Header; MAX_HEADERS] =
|
||||||
@ -500,7 +502,7 @@ impl Reader {
|
|||||||
let mut req = httparse::Request::new(&mut headers);
|
let mut req = httparse::Request::new(&mut headers);
|
||||||
match req.parse(b)? {
|
match req.parse(b)? {
|
||||||
httparse::Status::Complete(len) => {
|
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)?;
|
.map_err(|_| ParseError::Method)?;
|
||||||
//let path = req.path.unwrap();
|
//let path = req.path.unwrap();
|
||||||
//let path_start = path.as_ptr() as usize - bytes_ptr;
|
//let path_start = path.as_ptr() as usize - bytes_ptr;
|
||||||
@ -527,7 +529,9 @@ impl Reader {
|
|||||||
{
|
{
|
||||||
let msg_mut = msg.get_mut();
|
let msg_mut = msg.get_mut();
|
||||||
for header in headers[..headers_len].iter() {
|
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_start = header.value.as_ptr() as usize - bytes_ptr;
|
||||||
let v_end = v_start + header.value.len();
|
let v_end = v_start + header.value.len();
|
||||||
let value = unsafe {
|
let value = unsafe {
|
||||||
@ -540,8 +544,6 @@ impl Reader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
msg_mut.uri = path;
|
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.method = method;
|
||||||
msg_mut.version = version;
|
msg_mut.version = version;
|
||||||
}
|
}
|
||||||
@ -563,12 +565,10 @@ impl Reader {
|
|||||||
debug!("illegal Content-Length: {:?}", len);
|
debug!("illegal Content-Length: {:?}", len);
|
||||||
return Err(ParseError::Header)
|
return Err(ParseError::Header)
|
||||||
}
|
}
|
||||||
} else if chunked(&msg.get_mut().headers)? {
|
} else if has_te && chunked(&msg.get_mut().headers)? {
|
||||||
// Chunked encoding
|
// Chunked encoding
|
||||||
Some(Decoder::chunked())
|
Some(Decoder::chunked())
|
||||||
} else if msg.get_ref().headers.contains_key(header::UPGRADE) ||
|
} else if has_upgrade || msg.get_ref().method == Method::CONNECT {
|
||||||
msg.get_ref().method == Method::CONNECT
|
|
||||||
{
|
|
||||||
Some(Decoder::eof())
|
Some(Decoder::eof())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
Loading…
Reference in New Issue
Block a user