diff --git a/src/httpresponse.rs b/src/httpresponse.rs index ad2f0016b..2e92fcaa1 100644 --- a/src/httpresponse.rs +++ b/src/httpresponse.rs @@ -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>); +pub struct HttpResponse(Option>, Rc>); 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>, + pool: Option>>, err: Option, cookies: Option, } @@ -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>); -thread_local!(static POOL: RefCell = - RefCell::new(Pool(VecDeque::with_capacity(128)))); +thread_local!(static POOL: Rc> = + Rc::new(UnsafeCell::new(Pool(VecDeque::with_capacity(128))))); impl Pool { #[inline] - fn get(status: StatusCode) -> Box { + fn get(status: StatusCode) -> (Box, Rc>) { 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 { + fn with_body(status: StatusCode, body: Body) + -> (Box, Rc>) { 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) { - 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>, mut inner: Box) { + 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); + } } } diff --git a/src/server/h1.rs b/src/server/h1.rs index 38d4d4345..86e0b73a2 100644 --- a/src/server/h1.rs +++ b/src/server/h1.rs @@ -490,6 +490,8 @@ impl Reader { fn parse_message(buf: &mut BytesMut, settings: &WorkerSettings) -> Poll<(HttpRequest, Option), 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