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