mirror of
https://github.com/actix/actix-extras.git
synced 2024-11-28 09:42:40 +01:00
add helper method for response creation
This commit is contained in:
parent
449709dd7e
commit
47f836cd1b
@ -186,6 +186,9 @@ impl StaticResponse {
|
||||
pub fn build(&self) -> HttpResponseBuilder {
|
||||
HttpResponse::build(self.0)
|
||||
}
|
||||
pub fn build_from<S>(&self, req: &HttpRequest<S>) -> HttpResponseBuilder {
|
||||
req.build_response(self.0)
|
||||
}
|
||||
pub fn with_reason(self, reason: &'static str) -> HttpResponse {
|
||||
let mut resp = HttpResponse::new(self.0, Body::Empty);
|
||||
resp.set_reason(reason);
|
||||
|
@ -8,14 +8,16 @@ use futures::{Async, Stream, Poll};
|
||||
use futures_cpupool::CpuPool;
|
||||
use failure;
|
||||
use url::{Url, form_urlencoded};
|
||||
use http::{header, Uri, Method, Version, HeaderMap, Extensions};
|
||||
use http::{header, Uri, Method, Version, HeaderMap, Extensions, StatusCode};
|
||||
use tokio_io::AsyncRead;
|
||||
|
||||
use body::Body;
|
||||
use info::ConnectionInfo;
|
||||
use param::Params;
|
||||
use router::Router;
|
||||
use payload::Payload;
|
||||
use httpmessage::HttpMessage;
|
||||
use httpresponse::{HttpResponse, HttpResponseBuilder};
|
||||
use helpers::SharedHttpInnerMessage;
|
||||
use error::{UrlGenerationError, CookieParseError, PayloadError};
|
||||
|
||||
@ -194,6 +196,24 @@ impl<S> HttpRequest<S> {
|
||||
.server_settings().cpu_pool()
|
||||
}
|
||||
|
||||
/// Create http response
|
||||
pub fn response(&self, status: StatusCode, body: Body) -> HttpResponse {
|
||||
if let Some(router) = self.router() {
|
||||
router.server_settings().get_response(status, body)
|
||||
} else {
|
||||
HttpResponse::new(status, body)
|
||||
}
|
||||
}
|
||||
|
||||
/// Create http response builder
|
||||
pub fn build_response(&self, status: StatusCode) -> HttpResponseBuilder {
|
||||
if let Some(router) = self.router() {
|
||||
router.server_settings().get_response_builder(status)
|
||||
} else {
|
||||
HttpResponse::build(status)
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn prefix_len(&self) -> usize {
|
||||
if let Some(router) = self.router() { router.prefix().len() } else { 0 }
|
||||
|
@ -37,12 +37,12 @@ pub enum ConnectionType {
|
||||
}
|
||||
|
||||
/// An HTTP Response
|
||||
pub struct HttpResponse(Option<Box<InnerHttpResponse>>, Rc<UnsafeCell<Pool>>);
|
||||
pub struct HttpResponse(Option<Box<InnerHttpResponse>>, Rc<UnsafeCell<HttpResponsePool>>);
|
||||
|
||||
impl Drop for HttpResponse {
|
||||
fn drop(&mut self) {
|
||||
if let Some(inner) = self.0.take() {
|
||||
Pool::release(&self.1, inner)
|
||||
HttpResponsePool::release(&self.1, inner)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -64,13 +64,7 @@ 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(msg),
|
||||
pool: Some(pool),
|
||||
err: None,
|
||||
cookies: None,
|
||||
}
|
||||
HttpResponsePool::get(status)
|
||||
}
|
||||
|
||||
/// Create http response builder
|
||||
@ -82,8 +76,7 @@ impl HttpResponse {
|
||||
/// Constructs a response
|
||||
#[inline]
|
||||
pub fn new(status: StatusCode, body: Body) -> HttpResponse {
|
||||
let (msg, pool) = Pool::with_body(status, body);
|
||||
HttpResponse(Some(msg), pool)
|
||||
HttpResponsePool::with_body(status, body)
|
||||
}
|
||||
|
||||
/// Constructs a error response
|
||||
@ -246,7 +239,7 @@ impl fmt::Debug for HttpResponse {
|
||||
/// builder-like pattern.
|
||||
pub struct HttpResponseBuilder {
|
||||
response: Option<Box<InnerHttpResponse>>,
|
||||
pool: Option<Rc<UnsafeCell<Pool>>>,
|
||||
pool: Option<Rc<UnsafeCell<HttpResponsePool>>>,
|
||||
err: Option<HttpError>,
|
||||
cookies: Option<CookieJar>,
|
||||
}
|
||||
@ -738,6 +731,16 @@ impl<'a> From<&'a ClientResponse> for HttpResponseBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, S> From<&'a HttpRequest<S>> for HttpResponseBuilder {
|
||||
fn from(req: &'a HttpRequest<S>) -> HttpResponseBuilder {
|
||||
if let Some(router) = req.router() {
|
||||
router.server_settings().get_response_builder(StatusCode::OK)
|
||||
} else {
|
||||
HttpResponse::build(StatusCode::OK)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct InnerHttpResponse {
|
||||
version: Option<Version>,
|
||||
@ -774,45 +777,67 @@ impl InnerHttpResponse {
|
||||
}
|
||||
|
||||
/// Internal use only! unsafe
|
||||
struct Pool(VecDeque<Box<InnerHttpResponse>>);
|
||||
pub(crate) struct HttpResponsePool(VecDeque<Box<InnerHttpResponse>>);
|
||||
|
||||
thread_local!(static POOL: Rc<UnsafeCell<Pool>> =
|
||||
Rc::new(UnsafeCell::new(Pool(VecDeque::with_capacity(128)))));
|
||||
thread_local!(static POOL: Rc<UnsafeCell<HttpResponsePool>> = HttpResponsePool::pool());
|
||||
|
||||
impl Pool {
|
||||
impl HttpResponsePool {
|
||||
|
||||
#[inline]
|
||||
fn get(status: StatusCode) -> (Box<InnerHttpResponse>, Rc<UnsafeCell<Pool>>) {
|
||||
POOL.with(|pool| {
|
||||
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, Rc::clone(pool))
|
||||
} else {
|
||||
(Box::new(InnerHttpResponse::new(status, Body::Empty)), Rc::clone(pool))
|
||||
}
|
||||
})
|
||||
pub fn pool() -> Rc<UnsafeCell<HttpResponsePool>> {
|
||||
Rc::new(UnsafeCell::new(HttpResponsePool(VecDeque::with_capacity(128))))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn with_body(status: StatusCode, body: Body)
|
||||
-> (Box<InnerHttpResponse>, Rc<UnsafeCell<Pool>>) {
|
||||
POOL.with(|pool| {
|
||||
let p = unsafe{&mut *pool.as_ref().get()};
|
||||
if let Some(mut resp) = p.0.pop_front() {
|
||||
resp.status = status;
|
||||
resp.body = body;
|
||||
(resp, Rc::clone(pool))
|
||||
} else {
|
||||
(Box::new(InnerHttpResponse::new(status, body)), Rc::clone(pool))
|
||||
}
|
||||
})
|
||||
pub fn get_builder(pool: &Rc<UnsafeCell<HttpResponsePool>>, status: StatusCode)
|
||||
-> HttpResponseBuilder
|
||||
{
|
||||
let p = unsafe{&mut *pool.as_ref().get()};
|
||||
if let Some(mut msg) = p.0.pop_front() {
|
||||
msg.status = status;
|
||||
HttpResponseBuilder {
|
||||
response: Some(msg),
|
||||
pool: Some(Rc::clone(pool)),
|
||||
err: None,
|
||||
cookies: None }
|
||||
} else {
|
||||
let msg = Box::new(InnerHttpResponse::new(status, Body::Empty));
|
||||
HttpResponseBuilder {
|
||||
response: Some(msg),
|
||||
pool: Some(Rc::clone(pool)),
|
||||
err: None,
|
||||
cookies: None }
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_response(pool: &Rc<UnsafeCell<HttpResponsePool>>,
|
||||
status: StatusCode, body: Body) -> HttpResponse
|
||||
{
|
||||
let p = unsafe{&mut *pool.as_ref().get()};
|
||||
if let Some(mut msg) = p.0.pop_front() {
|
||||
msg.status = status;
|
||||
msg.body = body;
|
||||
HttpResponse(Some(msg), Rc::clone(pool))
|
||||
} else {
|
||||
let msg = Box::new(InnerHttpResponse::new(status, body));
|
||||
HttpResponse(Some(msg), Rc::clone(pool))
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get(status: StatusCode) -> HttpResponseBuilder {
|
||||
POOL.with(|pool| HttpResponsePool::get_builder(pool, status))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn with_body(status: StatusCode, body: Body) -> HttpResponse {
|
||||
POOL.with(|pool| HttpResponsePool::get_response(pool, status, body))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
#[cfg_attr(feature = "cargo-clippy", allow(boxed_local, inline_always))]
|
||||
fn release(pool: &Rc<UnsafeCell<Pool>>, mut inner: Box<InnerHttpResponse>) {
|
||||
fn release(pool: &Rc<UnsafeCell<HttpResponsePool>>, mut inner: Box<InnerHttpResponse>)
|
||||
{
|
||||
let pool = unsafe{&mut *pool.as_ref().get()};
|
||||
if pool.0.len() < 128 {
|
||||
inner.headers.clear();
|
||||
|
@ -5,22 +5,29 @@ use std::sync::Arc;
|
||||
use std::cell::{Cell, RefCell, RefMut, UnsafeCell};
|
||||
use time;
|
||||
use bytes::BytesMut;
|
||||
use http::StatusCode;
|
||||
use futures_cpupool::{Builder, CpuPool};
|
||||
|
||||
use helpers;
|
||||
use super::KeepAlive;
|
||||
use super::channel::Node;
|
||||
use super::shared::{SharedBytes, SharedBytesPool};
|
||||
use body::Body;
|
||||
use httpresponse::{HttpResponse, HttpResponsePool, HttpResponseBuilder};
|
||||
|
||||
/// Various server settings
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Clone)]
|
||||
pub struct ServerSettings {
|
||||
addr: Option<net::SocketAddr>,
|
||||
secure: bool,
|
||||
host: String,
|
||||
cpu_pool: Arc<InnerCpuPool>,
|
||||
responses: Rc<UnsafeCell<HttpResponsePool>>,
|
||||
}
|
||||
|
||||
unsafe impl Sync for ServerSettings {}
|
||||
unsafe impl Send for ServerSettings {}
|
||||
|
||||
struct InnerCpuPool {
|
||||
cpu_pool: UnsafeCell<Option<CpuPool>>,
|
||||
}
|
||||
@ -56,6 +63,7 @@ impl Default for ServerSettings {
|
||||
addr: None,
|
||||
secure: false,
|
||||
host: "localhost:8080".to_owned(),
|
||||
responses: HttpResponsePool::pool(),
|
||||
cpu_pool: Arc::new(InnerCpuPool::new()),
|
||||
}
|
||||
}
|
||||
@ -74,7 +82,8 @@ impl ServerSettings {
|
||||
"localhost".to_owned()
|
||||
};
|
||||
let cpu_pool = Arc::new(InnerCpuPool::new());
|
||||
ServerSettings { addr, secure, host, cpu_pool }
|
||||
let responses = HttpResponsePool::pool();
|
||||
ServerSettings { addr, secure, host, cpu_pool, responses }
|
||||
}
|
||||
|
||||
/// Returns the socket address of the local half of this TCP connection
|
||||
@ -96,8 +105,19 @@ impl ServerSettings {
|
||||
pub fn cpu_pool(&self) -> &CpuPool {
|
||||
self.cpu_pool.cpu_pool()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn get_response(&self, status: StatusCode, body: Body) -> HttpResponse {
|
||||
HttpResponsePool::get_response(&self.responses, status, body)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn get_response_builder(&self, status: StatusCode) -> HttpResponseBuilder {
|
||||
HttpResponsePool::get_builder(&self.responses, status)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// "Sun, 06 Nov 1994 08:49:37 GMT".len()
|
||||
const DATE_VALUE_LENGTH: usize = 29;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user