mirror of
https://github.com/actix/actix-extras.git
synced 2024-11-28 01:32:57 +01:00
cleanup response
This commit is contained in:
parent
a8b2f1b821
commit
1daf50095a
@ -110,6 +110,7 @@ impl Responder for HttpResponse {
|
||||
type Item = Reply;
|
||||
type Error = Error;
|
||||
|
||||
#[inline]
|
||||
fn respond_to(self, _: HttpRequest) -> Result<Reply, Error> {
|
||||
Ok(Reply(ReplyItem::Message(self)))
|
||||
}
|
||||
@ -117,6 +118,7 @@ impl Responder for HttpResponse {
|
||||
|
||||
impl From<HttpResponse> for Reply {
|
||||
|
||||
#[inline]
|
||||
fn from(resp: HttpResponse) -> Reply {
|
||||
Reply(ReplyItem::Message(resp))
|
||||
}
|
||||
@ -152,6 +154,7 @@ impl<A: Actor<Context=HttpContext<A, S>>, S: 'static> Responder for HttpContext<
|
||||
type Item = Reply;
|
||||
type Error = Error;
|
||||
|
||||
#[inline]
|
||||
fn respond_to(self, _: HttpRequest) -> Result<Reply, Error> {
|
||||
Ok(Reply(ReplyItem::Actor(Box::new(self))))
|
||||
}
|
||||
@ -159,6 +162,7 @@ impl<A: Actor<Context=HttpContext<A, S>>, S: 'static> Responder for HttpContext<
|
||||
|
||||
impl<A: Actor<Context=HttpContext<A, S>>, S: 'static> From<HttpContext<A, S>> for Reply {
|
||||
|
||||
#[inline]
|
||||
fn from(ctx: HttpContext<A, S>) -> Reply {
|
||||
Reply(ReplyItem::Actor(Box::new(ctx)))
|
||||
}
|
||||
@ -169,6 +173,7 @@ impl Responder for Box<Future<Item=HttpResponse, Error=Error>>
|
||||
type Item = Reply;
|
||||
type Error = Error;
|
||||
|
||||
#[inline]
|
||||
fn respond_to(self, _: HttpRequest) -> Result<Reply, Error> {
|
||||
Ok(Reply(ReplyItem::Future(self)))
|
||||
}
|
||||
|
@ -29,86 +29,6 @@ pub enum ConnectionType {
|
||||
Upgrade,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct InnerHttpResponse {
|
||||
version: Option<Version>,
|
||||
headers: HeaderMap,
|
||||
status: StatusCode,
|
||||
reason: Option<&'static str>,
|
||||
body: Body,
|
||||
chunked: bool,
|
||||
encoding: ContentEncoding,
|
||||
connection_type: Option<ConnectionType>,
|
||||
response_size: u64,
|
||||
error: Option<Error>,
|
||||
}
|
||||
|
||||
impl InnerHttpResponse {
|
||||
|
||||
#[inline]
|
||||
fn new(status: StatusCode, body: Body) -> InnerHttpResponse {
|
||||
InnerHttpResponse {
|
||||
version: None,
|
||||
headers: HeaderMap::with_capacity(8),
|
||||
status: status,
|
||||
reason: None,
|
||||
body: body,
|
||||
chunked: false,
|
||||
encoding: ContentEncoding::Auto,
|
||||
connection_type: None,
|
||||
response_size: 0,
|
||||
error: None,
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl Default for InnerHttpResponse {
|
||||
|
||||
fn default() -> InnerHttpResponse {
|
||||
InnerHttpResponse::new(StatusCode::OK, Body::Empty)
|
||||
}
|
||||
}
|
||||
|
||||
/// Internal use only! unsafe
|
||||
struct Pool(VecDeque<Box<InnerHttpResponse>>);
|
||||
|
||||
thread_local!(static POOL: RefCell<Pool> = RefCell::new(Pool::new()));
|
||||
|
||||
impl Pool {
|
||||
fn new() -> Pool {
|
||||
Pool(VecDeque::with_capacity(128))
|
||||
}
|
||||
|
||||
fn get() -> Box<InnerHttpResponse> {
|
||||
POOL.with(|pool| {
|
||||
if let Some(resp) = pool.borrow_mut().0.pop_front() {
|
||||
resp
|
||||
} else {
|
||||
Box::new(InnerHttpResponse::default())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "cargo-clippy", allow(boxed_local))]
|
||||
fn release(mut inner: Box<InnerHttpResponse>) {
|
||||
POOL.with(|pool| {
|
||||
if pool.borrow().0.len() < 128 {
|
||||
inner.version.take();
|
||||
inner.headers.clear();
|
||||
inner.chunked = false;
|
||||
inner.reason.take();
|
||||
inner.body = Body::Empty;
|
||||
inner.encoding = ContentEncoding::Auto;
|
||||
inner.connection_type.take();
|
||||
inner.response_size = 0;
|
||||
inner.error.take();
|
||||
pool.borrow_mut().0.push_front(inner);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// An HTTP Response
|
||||
pub struct HttpResponse(Option<Box<InnerHttpResponse>>);
|
||||
|
||||
@ -123,27 +43,22 @@ impl Drop for HttpResponse {
|
||||
impl HttpResponse {
|
||||
|
||||
#[inline(always)]
|
||||
#[cfg_attr(feature = "cargo-clippy", allow(inline_always))]
|
||||
fn get_ref(&self) -> &InnerHttpResponse {
|
||||
self.0.as_ref().unwrap()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
#[cfg_attr(feature = "cargo-clippy", allow(inline_always))]
|
||||
fn get_mut(&mut self) -> &mut InnerHttpResponse {
|
||||
self.0.as_mut().unwrap()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_inner(inner: Box<InnerHttpResponse>) -> HttpResponse {
|
||||
HttpResponse(Some(inner))
|
||||
}
|
||||
|
||||
/// Create http response builder with specific status.
|
||||
#[inline]
|
||||
pub fn build(status: StatusCode) -> HttpResponseBuilder {
|
||||
let mut inner = Pool::get();
|
||||
inner.status = status;
|
||||
HttpResponseBuilder {
|
||||
response: Some(inner),
|
||||
response: Some(Pool::get(status)),
|
||||
err: None,
|
||||
cookies: None,
|
||||
}
|
||||
@ -152,10 +67,7 @@ impl HttpResponse {
|
||||
/// Constructs a response
|
||||
#[inline]
|
||||
pub fn new(status: StatusCode, body: Body) -> HttpResponse {
|
||||
let mut inner = Pool::get();
|
||||
inner.status = status;
|
||||
inner.body = body;
|
||||
HttpResponse(Some(inner))
|
||||
HttpResponse(Some(Pool::with_body(status, body)))
|
||||
}
|
||||
|
||||
/// Constructs a error response
|
||||
@ -470,7 +382,7 @@ impl HttpResponseBuilder {
|
||||
}
|
||||
}
|
||||
response.body = body.into();
|
||||
Ok(HttpResponse::from_inner(response))
|
||||
Ok(HttpResponse(Some(response)))
|
||||
}
|
||||
|
||||
/// Set a json body and generate `HttpResponse`
|
||||
@ -495,6 +407,7 @@ impl HttpResponseBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg_attr(feature = "cargo-clippy", allow(borrowed_box))]
|
||||
fn parts<'a>(parts: &'a mut Option<Box<InnerHttpResponse>>, err: &Option<HttpError>)
|
||||
-> Option<&'a mut Box<InnerHttpResponse>>
|
||||
@ -525,6 +438,7 @@ impl Responder for HttpResponseBuilder {
|
||||
type Item = HttpResponse;
|
||||
type Error = HttpError;
|
||||
|
||||
#[inline]
|
||||
fn respond_to(mut self, _: HttpRequest) -> Result<HttpResponse, HttpError> {
|
||||
self.finish()
|
||||
}
|
||||
@ -650,6 +564,93 @@ impl Responder for BytesMut {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct InnerHttpResponse {
|
||||
version: Option<Version>,
|
||||
headers: HeaderMap,
|
||||
status: StatusCode,
|
||||
reason: Option<&'static str>,
|
||||
body: Body,
|
||||
chunked: bool,
|
||||
encoding: ContentEncoding,
|
||||
connection_type: Option<ConnectionType>,
|
||||
response_size: u64,
|
||||
error: Option<Error>,
|
||||
}
|
||||
|
||||
impl InnerHttpResponse {
|
||||
|
||||
#[inline]
|
||||
fn new(status: StatusCode, body: Body) -> InnerHttpResponse {
|
||||
InnerHttpResponse {
|
||||
version: None,
|
||||
headers: HeaderMap::with_capacity(8),
|
||||
status: status,
|
||||
reason: None,
|
||||
body: body,
|
||||
chunked: false,
|
||||
encoding: ContentEncoding::Auto,
|
||||
connection_type: None,
|
||||
response_size: 0,
|
||||
error: None,
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// Internal use only! unsafe
|
||||
struct Pool(VecDeque<Box<InnerHttpResponse>>);
|
||||
|
||||
thread_local!(static POOL: RefCell<Pool> = RefCell::new(Pool::new()));
|
||||
|
||||
impl Pool {
|
||||
fn new() -> Pool {
|
||||
Pool(VecDeque::with_capacity(128))
|
||||
}
|
||||
|
||||
fn get(status: StatusCode) -> Box<InnerHttpResponse> {
|
||||
POOL.with(|pool| {
|
||||
if let Some(mut resp) = pool.borrow_mut().0.pop_front() {
|
||||
resp.body = Body::Empty;
|
||||
resp.status = status;
|
||||
resp
|
||||
} else {
|
||||
Box::new(InnerHttpResponse::new(status, Body::Empty))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn with_body(status: StatusCode, body: Body) -> Box<InnerHttpResponse> {
|
||||
POOL.with(|pool| {
|
||||
if let Some(mut resp) = pool.borrow_mut().0.pop_front() {
|
||||
resp.status = status;
|
||||
resp.body = Body::Empty;
|
||||
resp
|
||||
} else {
|
||||
Box::new(InnerHttpResponse::new(status, body))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "cargo-clippy", allow(boxed_local))]
|
||||
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 = false;
|
||||
inner.reason = None;
|
||||
inner.encoding = ContentEncoding::Auto;
|
||||
inner.connection_type = None;
|
||||
inner.response_size = 0;
|
||||
inner.error = None;
|
||||
v.push_front(inner);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -408,19 +408,19 @@ struct WaitingResponse<S> {
|
||||
|
||||
impl<S> WaitingResponse<S> {
|
||||
|
||||
#[inline]
|
||||
fn init(info: &mut PipelineInfo<S>, reply: Reply) -> PipelineState<S>
|
||||
{
|
||||
let stream = match reply.into() {
|
||||
match reply.into() {
|
||||
ReplyItem::Message(resp) =>
|
||||
return RunMiddlewares::init(info, resp),
|
||||
RunMiddlewares::init(info, resp),
|
||||
ReplyItem::Actor(ctx) =>
|
||||
PipelineResponse::Context(ctx),
|
||||
PipelineState::Handler(
|
||||
WaitingResponse { stream: PipelineResponse::Context(ctx), _s: PhantomData }),
|
||||
ReplyItem::Future(fut) =>
|
||||
PipelineResponse::Response(fut),
|
||||
};
|
||||
|
||||
PipelineState::Handler(
|
||||
WaitingResponse { stream: stream, _s: PhantomData })
|
||||
PipelineState::Handler(
|
||||
WaitingResponse { stream: PipelineResponse::Response(fut), _s: PhantomData }),
|
||||
}
|
||||
}
|
||||
|
||||
fn poll(mut self, info: &mut PipelineInfo<S>) -> Result<PipelineState<S>, PipelineState<S>> {
|
||||
@ -587,15 +587,6 @@ enum IOState {
|
||||
Done,
|
||||
}
|
||||
|
||||
impl IOState {
|
||||
fn is_done(&self) -> bool {
|
||||
match *self {
|
||||
IOState::Done => true,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct DrainVec(Vec<Rc<RefCell<DrainFut>>>);
|
||||
|
||||
impl Drop for DrainVec {
|
||||
@ -608,6 +599,7 @@ impl Drop for DrainVec {
|
||||
|
||||
impl<S> ProcessResponse<S> {
|
||||
|
||||
#[inline]
|
||||
fn init(resp: HttpResponse) -> PipelineState<S>
|
||||
{
|
||||
PipelineState::Response(
|
||||
@ -779,11 +771,12 @@ impl<S> ProcessResponse<S> {
|
||||
}
|
||||
|
||||
// response is completed
|
||||
if self.iostate.is_done() {
|
||||
self.resp.set_response_size(io.written());
|
||||
Ok(FinishingMiddlewares::init(info, self.resp))
|
||||
} else {
|
||||
Err(PipelineState::Response(self))
|
||||
match self.iostate {
|
||||
IOState::Done => {
|
||||
self.resp.set_response_size(io.written());
|
||||
Ok(FinishingMiddlewares::init(info, self.resp))
|
||||
}
|
||||
_ => Err(PipelineState::Response(self))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -850,6 +843,7 @@ struct Completed<S>(PhantomData<S>);
|
||||
|
||||
impl<S> Completed<S> {
|
||||
|
||||
#[inline]
|
||||
fn init(info: &mut PipelineInfo<S>) -> PipelineState<S> {
|
||||
if info.context.is_none() {
|
||||
PipelineState::None
|
||||
@ -858,6 +852,7 @@ impl<S> Completed<S> {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn poll(self, info: &mut PipelineInfo<S>) -> Result<PipelineState<S>, PipelineState<S>> {
|
||||
match info.poll_context() {
|
||||
Ok(Async::NotReady) => Ok(PipelineState::Completed(Completed(PhantomData))),
|
||||
|
Loading…
Reference in New Issue
Block a user