mirror of
https://github.com/actix/actix-web.git
synced 2024-12-30 03:50:42 +00:00
use objects pool for HttpRequest; optimize nested services call
This commit is contained in:
parent
75b213a6f0
commit
aa78565453
20 changed files with 343 additions and 295 deletions
|
@ -68,9 +68,9 @@ rust-tls = ["rustls", "actix-server/rust-tls"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix-codec = "0.1.1"
|
actix-codec = "0.1.1"
|
||||||
actix-service = "0.3.4"
|
actix-service = "0.3.6"
|
||||||
actix-utils = "0.3.4"
|
actix-utils = "0.3.4"
|
||||||
actix-router = "0.1.1"
|
actix-router = "0.1.2"
|
||||||
actix-rt = "0.2.2"
|
actix-rt = "0.2.2"
|
||||||
actix-web-codegen = "0.1.0-alpha.1"
|
actix-web-codegen = "0.1.0-alpha.1"
|
||||||
actix-http = { version = "0.1.0-alpha.3", features=["fail"] }
|
actix-http = { version = "0.1.0-alpha.3", features=["fail"] }
|
||||||
|
@ -124,4 +124,4 @@ actix-web-codegen = { path = "actix-web-codegen" }
|
||||||
actix-web-actors = { path = "actix-web-actors" }
|
actix-web-actors = { path = "actix-web-actors" }
|
||||||
actix-session = { path = "actix-session" }
|
actix-session = { path = "actix-session" }
|
||||||
actix-files = { path = "actix-files" }
|
actix-files = { path = "actix-files" }
|
||||||
awc = { path = "awc" }
|
awc = { path = "awc" }
|
|
@ -423,7 +423,7 @@ impl<P> FilesService<P> {
|
||||||
> {
|
> {
|
||||||
log::debug!("Files: Failed to handle {}: {}", req.path(), e);
|
log::debug!("Files: Failed to handle {}: {}", req.path(), e);
|
||||||
if let Some(ref mut default) = self.default {
|
if let Some(ref mut default) = self.default {
|
||||||
Either::B(default.call(ServiceRequest::from_parts(req, payload)))
|
default.call(ServiceRequest::from_parts(req, payload))
|
||||||
} else {
|
} else {
|
||||||
Either::A(ok(ServiceResponse::from_err(e, req.clone())))
|
Either::A(ok(ServiceResponse::from_err(e, req.clone())))
|
||||||
}
|
}
|
||||||
|
@ -955,6 +955,7 @@ mod tests {
|
||||||
.method(Method::POST)
|
.method(Method::POST)
|
||||||
.to_http_request();
|
.to_http_request();
|
||||||
let resp = file.respond_to(&req).unwrap();
|
let resp = file.respond_to(&req).unwrap();
|
||||||
|
println!("RES: {:?}", resp);
|
||||||
assert_eq!(resp.status(), StatusCode::METHOD_NOT_ALLOWED);
|
assert_eq!(resp.status(), StatusCode::METHOD_NOT_ALLOWED);
|
||||||
|
|
||||||
let file = NamedFile::open("Cargo.toml").unwrap();
|
let file = NamedFile::open("Cargo.toml").unwrap();
|
||||||
|
|
|
@ -104,9 +104,8 @@ where
|
||||||
let (parts, body) = resp.into_parts();
|
let (parts, body) = resp.into_parts();
|
||||||
let payload = if head_req { Payload::None } else { body.into() };
|
let payload = if head_req { Payload::None } else { body.into() };
|
||||||
|
|
||||||
let mut head = ResponseHead::default();
|
let mut head = ResponseHead::new(parts.status);
|
||||||
head.version = parts.version;
|
head.version = parts.version;
|
||||||
head.status = parts.status;
|
|
||||||
head.headers = parts.headers.into();
|
head.headers = parts.headers.into();
|
||||||
|
|
||||||
Ok((head, payload))
|
Ok((head, payload))
|
||||||
|
|
|
@ -21,6 +21,7 @@ use tokio_timer::{sleep, Delay};
|
||||||
use super::connection::{ConnectionType, IoConnection};
|
use super::connection::{ConnectionType, IoConnection};
|
||||||
use super::error::ConnectError;
|
use super::error::ConnectError;
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
#[derive(Clone, Copy, PartialEq)]
|
||||||
pub enum Protocol {
|
pub enum Protocol {
|
||||||
Http1,
|
Http1,
|
||||||
|
|
|
@ -73,78 +73,75 @@ pub(crate) trait MessageType: Sized {
|
||||||
let headers = self.headers_mut();
|
let headers = self.headers_mut();
|
||||||
|
|
||||||
for idx in raw_headers.iter() {
|
for idx in raw_headers.iter() {
|
||||||
if let Ok(name) = HeaderName::from_bytes(&slice[idx.name.0..idx.name.1])
|
let name =
|
||||||
{
|
HeaderName::from_bytes(&slice[idx.name.0..idx.name.1]).unwrap();
|
||||||
// Unsafe: httparse check header value for valid utf-8
|
|
||||||
let value = unsafe {
|
// Unsafe: httparse check header value for valid utf-8
|
||||||
HeaderValue::from_shared_unchecked(
|
let value = unsafe {
|
||||||
slice.slice(idx.value.0, idx.value.1),
|
HeaderValue::from_shared_unchecked(
|
||||||
)
|
slice.slice(idx.value.0, idx.value.1),
|
||||||
};
|
)
|
||||||
match name {
|
};
|
||||||
header::CONTENT_LENGTH => {
|
match name {
|
||||||
if let Ok(s) = value.to_str() {
|
header::CONTENT_LENGTH => {
|
||||||
if let Ok(len) = s.parse::<u64>() {
|
if let Ok(s) = value.to_str() {
|
||||||
if len != 0 {
|
if let Ok(len) = s.parse::<u64>() {
|
||||||
content_length = Some(len);
|
if len != 0 {
|
||||||
}
|
content_length = Some(len);
|
||||||
} else {
|
|
||||||
debug!("illegal Content-Length: {:?}", s);
|
|
||||||
return Err(ParseError::Header);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
debug!("illegal Content-Length: {:?}", value);
|
debug!("illegal Content-Length: {:?}", s);
|
||||||
return Err(ParseError::Header);
|
return Err(ParseError::Header);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
debug!("illegal Content-Length: {:?}", value);
|
||||||
|
return Err(ParseError::Header);
|
||||||
}
|
}
|
||||||
// transfer-encoding
|
}
|
||||||
header::TRANSFER_ENCODING => {
|
// transfer-encoding
|
||||||
if let Ok(s) = value.to_str().map(|s| s.trim()) {
|
header::TRANSFER_ENCODING => {
|
||||||
chunked = s.eq_ignore_ascii_case("chunked");
|
if let Ok(s) = value.to_str().map(|s| s.trim()) {
|
||||||
} else {
|
chunked = s.eq_ignore_ascii_case("chunked");
|
||||||
return Err(ParseError::Header);
|
} else {
|
||||||
}
|
return Err(ParseError::Header);
|
||||||
}
|
}
|
||||||
// connection keep-alive state
|
}
|
||||||
header::CONNECTION => {
|
// connection keep-alive state
|
||||||
ka = if let Ok(conn) = value.to_str().map(|conn| conn.trim())
|
header::CONNECTION => {
|
||||||
{
|
ka = if let Ok(conn) = value.to_str().map(|conn| conn.trim()) {
|
||||||
if conn.eq_ignore_ascii_case("keep-alive") {
|
if conn.eq_ignore_ascii_case("keep-alive") {
|
||||||
Some(ConnectionType::KeepAlive)
|
Some(ConnectionType::KeepAlive)
|
||||||
} else if conn.eq_ignore_ascii_case("close") {
|
} else if conn.eq_ignore_ascii_case("close") {
|
||||||
Some(ConnectionType::Close)
|
Some(ConnectionType::Close)
|
||||||
} else if conn.eq_ignore_ascii_case("upgrade") {
|
} else if conn.eq_ignore_ascii_case("upgrade") {
|
||||||
Some(ConnectionType::Upgrade)
|
Some(ConnectionType::Upgrade)
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
|
||||||
}
|
|
||||||
header::UPGRADE => {
|
|
||||||
has_upgrade = true;
|
|
||||||
// check content-length, some clients (dart)
|
|
||||||
// sends "content-length: 0" with websocket upgrade
|
|
||||||
if let Ok(val) = value.to_str().map(|val| val.trim()) {
|
|
||||||
if val.eq_ignore_ascii_case("websocket") {
|
|
||||||
content_length = None;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
header::EXPECT => {
|
None
|
||||||
let bytes = value.as_bytes();
|
};
|
||||||
if bytes.len() >= 4 && &bytes[0..4] == b"100-" {
|
|
||||||
expect = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
}
|
||||||
|
header::UPGRADE => {
|
||||||
headers.append(name, value);
|
has_upgrade = true;
|
||||||
} else {
|
// check content-length, some clients (dart)
|
||||||
return Err(ParseError::Header);
|
// sends "content-length: 0" with websocket upgrade
|
||||||
|
if let Ok(val) = value.to_str().map(|val| val.trim()) {
|
||||||
|
if val.eq_ignore_ascii_case("websocket") {
|
||||||
|
content_length = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
header::EXPECT => {
|
||||||
|
let bytes = value.as_bytes();
|
||||||
|
if bytes.len() >= 4 && &bytes[0..4] == b"100-" {
|
||||||
|
expect = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
headers.append(name, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.set_connection_type(ka);
|
self.set_connection_type(ka);
|
||||||
|
@ -217,10 +214,10 @@ impl MessageType for Request {
|
||||||
let mut msg = Request::new();
|
let mut msg = Request::new();
|
||||||
|
|
||||||
// convert headers
|
// convert headers
|
||||||
let len = msg.set_headers(&src.split_to(len).freeze(), &headers[..h_len])?;
|
let length = msg.set_headers(&src.split_to(len).freeze(), &headers[..h_len])?;
|
||||||
|
|
||||||
// payload decoder
|
// payload decoder
|
||||||
let decoder = match len {
|
let decoder = match length {
|
||||||
PayloadLength::Payload(pl) => pl,
|
PayloadLength::Payload(pl) => pl,
|
||||||
PayloadLength::Upgrade => {
|
PayloadLength::Upgrade => {
|
||||||
// upgrade(websocket)
|
// upgrade(websocket)
|
||||||
|
@ -287,13 +284,14 @@ impl MessageType for ResponseHead {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut msg = ResponseHead::default();
|
let mut msg = ResponseHead::new(status);
|
||||||
|
msg.version = ver;
|
||||||
|
|
||||||
// convert headers
|
// convert headers
|
||||||
let len = msg.set_headers(&src.split_to(len).freeze(), &headers[..h_len])?;
|
let length = msg.set_headers(&src.split_to(len).freeze(), &headers[..h_len])?;
|
||||||
|
|
||||||
// message payload
|
// message payload
|
||||||
let decoder = if let PayloadLength::Payload(pl) = len {
|
let decoder = if let PayloadLength::Payload(pl) = length {
|
||||||
pl
|
pl
|
||||||
} else if status == StatusCode::SWITCHING_PROTOCOLS {
|
} else if status == StatusCode::SWITCHING_PROTOCOLS {
|
||||||
// switching protocol or connect
|
// switching protocol or connect
|
||||||
|
@ -305,9 +303,6 @@ impl MessageType for ResponseHead {
|
||||||
PayloadType::None
|
PayloadType::None
|
||||||
};
|
};
|
||||||
|
|
||||||
msg.status = status;
|
|
||||||
msg.version = ver;
|
|
||||||
|
|
||||||
Ok(Some((msg, decoder)))
|
Ok(Some((msg, decoder)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -218,7 +218,7 @@ where
|
||||||
{
|
{
|
||||||
fn can_read(&self) -> bool {
|
fn can_read(&self) -> bool {
|
||||||
if self.flags.contains(Flags::READ_DISCONNECT) {
|
if self.flags.contains(Flags::READ_DISCONNECT) {
|
||||||
return false;
|
false
|
||||||
} else if let Some(ref info) = self.payload {
|
} else if let Some(ref info) = self.payload {
|
||||||
info.need_read() == PayloadStatus::Read
|
info.need_read() == PayloadStatus::Read
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -8,7 +8,7 @@ macro_rules! STATIC_RESP {
|
||||||
($name:ident, $status:expr) => {
|
($name:ident, $status:expr) => {
|
||||||
#[allow(non_snake_case, missing_docs)]
|
#[allow(non_snake_case, missing_docs)]
|
||||||
pub fn $name() -> ResponseBuilder {
|
pub fn $name() -> ResponseBuilder {
|
||||||
Response::build($status)
|
ResponseBuilder::new($status)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
//! Basic http primitives for actix-net framework.
|
//! Basic http primitives for actix-net framework.
|
||||||
#![allow(clippy::type_complexity, clippy::new_without_default)]
|
#![allow(
|
||||||
|
clippy::type_complexity,
|
||||||
|
clippy::new_without_default,
|
||||||
|
clippy::borrow_interior_mutable_const
|
||||||
|
)]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use std::cell::{Ref, RefCell, RefMut};
|
use std::cell::{Ref, RefCell, RefMut};
|
||||||
use std::collections::VecDeque;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
|
@ -171,20 +170,20 @@ pub struct ResponseHead {
|
||||||
flags: Flags,
|
flags: Flags,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ResponseHead {
|
impl ResponseHead {
|
||||||
fn default() -> ResponseHead {
|
/// Create new instance of `ResponseHead` type
|
||||||
|
#[inline]
|
||||||
|
pub fn new(status: StatusCode) -> ResponseHead {
|
||||||
ResponseHead {
|
ResponseHead {
|
||||||
|
status,
|
||||||
version: Version::default(),
|
version: Version::default(),
|
||||||
status: StatusCode::OK,
|
|
||||||
headers: HeaderMap::with_capacity(12),
|
headers: HeaderMap::with_capacity(12),
|
||||||
reason: None,
|
reason: None,
|
||||||
flags: Flags::empty(),
|
flags: Flags::empty(),
|
||||||
extensions: RefCell::new(Extensions::new()),
|
extensions: RefCell::new(Extensions::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl ResponseHead {
|
|
||||||
/// Message extensions
|
/// Message extensions
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn extensions(&self) -> Ref<Extensions> {
|
pub fn extensions(&self) -> Ref<Extensions> {
|
||||||
|
@ -335,8 +334,8 @@ pub(crate) struct BoxedResponseHead {
|
||||||
|
|
||||||
impl BoxedResponseHead {
|
impl BoxedResponseHead {
|
||||||
/// Get new message from the pool of objects
|
/// Get new message from the pool of objects
|
||||||
pub fn new() -> Self {
|
pub fn new(status: StatusCode) -> Self {
|
||||||
RESPONSE_POOL.with(|p| p.get_message())
|
RESPONSE_POOL.with(|p| p.get_message(status))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -362,25 +361,25 @@ impl Drop for BoxedResponseHead {
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
/// Request's objects pool
|
/// Request's objects pool
|
||||||
pub struct MessagePool<T: Head>(RefCell<VecDeque<Rc<T>>>);
|
pub struct MessagePool<T: Head>(RefCell<Vec<Rc<T>>>);
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
/// Request's objects pool
|
/// Request's objects pool
|
||||||
pub struct BoxedResponsePool(RefCell<VecDeque<Box<ResponseHead>>>);
|
pub struct BoxedResponsePool(RefCell<Vec<Box<ResponseHead>>>);
|
||||||
|
|
||||||
thread_local!(static REQUEST_POOL: &'static MessagePool<RequestHead> = MessagePool::<RequestHead>::create());
|
thread_local!(static REQUEST_POOL: &'static MessagePool<RequestHead> = MessagePool::<RequestHead>::create());
|
||||||
thread_local!(static RESPONSE_POOL: &'static BoxedResponsePool = BoxedResponsePool::create());
|
thread_local!(static RESPONSE_POOL: &'static BoxedResponsePool = BoxedResponsePool::create());
|
||||||
|
|
||||||
impl<T: Head> MessagePool<T> {
|
impl<T: Head> MessagePool<T> {
|
||||||
fn create() -> &'static MessagePool<T> {
|
fn create() -> &'static MessagePool<T> {
|
||||||
let pool = MessagePool(RefCell::new(VecDeque::with_capacity(128)));
|
let pool = MessagePool(RefCell::new(Vec::with_capacity(128)));
|
||||||
Box::leak(Box::new(pool))
|
Box::leak(Box::new(pool))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get message from the pool
|
/// Get message from the pool
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_message(&'static self) -> Message<T> {
|
fn get_message(&'static self) -> Message<T> {
|
||||||
if let Some(mut msg) = self.0.borrow_mut().pop_front() {
|
if let Some(mut msg) = self.0.borrow_mut().pop() {
|
||||||
if let Some(r) = Rc::get_mut(&mut msg) {
|
if let Some(r) = Rc::get_mut(&mut msg) {
|
||||||
r.clear();
|
r.clear();
|
||||||
}
|
}
|
||||||
|
@ -397,28 +396,29 @@ impl<T: Head> MessagePool<T> {
|
||||||
fn release(&self, msg: Rc<T>) {
|
fn release(&self, msg: Rc<T>) {
|
||||||
let v = &mut self.0.borrow_mut();
|
let v = &mut self.0.borrow_mut();
|
||||||
if v.len() < 128 {
|
if v.len() < 128 {
|
||||||
v.push_front(msg);
|
v.push(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BoxedResponsePool {
|
impl BoxedResponsePool {
|
||||||
fn create() -> &'static BoxedResponsePool {
|
fn create() -> &'static BoxedResponsePool {
|
||||||
let pool = BoxedResponsePool(RefCell::new(VecDeque::with_capacity(128)));
|
let pool = BoxedResponsePool(RefCell::new(Vec::with_capacity(128)));
|
||||||
Box::leak(Box::new(pool))
|
Box::leak(Box::new(pool))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get message from the pool
|
/// Get message from the pool
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_message(&'static self) -> BoxedResponseHead {
|
fn get_message(&'static self, status: StatusCode) -> BoxedResponseHead {
|
||||||
if let Some(mut head) = self.0.borrow_mut().pop_front() {
|
if let Some(mut head) = self.0.borrow_mut().pop() {
|
||||||
head.reason = None;
|
head.reason = None;
|
||||||
|
head.status = status;
|
||||||
head.headers.clear();
|
head.headers.clear();
|
||||||
head.flags = Flags::empty();
|
head.flags = Flags::empty();
|
||||||
BoxedResponseHead { head: Some(head) }
|
BoxedResponseHead { head: Some(head) }
|
||||||
} else {
|
} else {
|
||||||
BoxedResponseHead {
|
BoxedResponseHead {
|
||||||
head: Some(Box::alloc().init(ResponseHead::default())),
|
head: Some(Box::alloc().init(ResponseHead::new(status))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -428,7 +428,7 @@ impl BoxedResponsePool {
|
||||||
fn release(&self, msg: Box<ResponseHead>) {
|
fn release(&self, msg: Box<ResponseHead>) {
|
||||||
let v = &mut self.0.borrow_mut();
|
let v = &mut self.0.borrow_mut();
|
||||||
if v.len() < 128 {
|
if v.len() < 128 {
|
||||||
v.push_front(msg);
|
v.push(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,11 +41,8 @@ impl Response<Body> {
|
||||||
/// Constructs a response
|
/// Constructs a response
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(status: StatusCode) -> Response {
|
pub fn new(status: StatusCode) -> Response {
|
||||||
let mut head = BoxedResponseHead::new();
|
|
||||||
head.status = status;
|
|
||||||
|
|
||||||
Response {
|
Response {
|
||||||
head,
|
head: BoxedResponseHead::new(status),
|
||||||
body: ResponseBody::Body(Body::Empty),
|
body: ResponseBody::Body(Body::Empty),
|
||||||
error: None,
|
error: None,
|
||||||
}
|
}
|
||||||
|
@ -78,6 +75,16 @@ impl Response<Body> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B> Response<B> {
|
impl<B> Response<B> {
|
||||||
|
/// Constructs a response with body
|
||||||
|
#[inline]
|
||||||
|
pub fn with_body(status: StatusCode, body: B) -> Response<B> {
|
||||||
|
Response {
|
||||||
|
head: BoxedResponseHead::new(status),
|
||||||
|
body: ResponseBody::Body(body),
|
||||||
|
error: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
/// Http message part of the response
|
/// Http message part of the response
|
||||||
pub fn head(&self) -> &ResponseHead {
|
pub fn head(&self) -> &ResponseHead {
|
||||||
|
@ -90,18 +97,6 @@ impl<B> Response<B> {
|
||||||
&mut *self.head
|
&mut *self.head
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs a response with body
|
|
||||||
#[inline]
|
|
||||||
pub fn with_body(status: StatusCode, body: B) -> Response<B> {
|
|
||||||
let mut head = BoxedResponseHead::new();
|
|
||||||
head.status = status;
|
|
||||||
Response {
|
|
||||||
head,
|
|
||||||
body: ResponseBody::Body(body),
|
|
||||||
error: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The source `error` for this response
|
/// The source `error` for this response
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn error(&self) -> Option<&Error> {
|
pub fn error(&self) -> Option<&Error> {
|
||||||
|
@ -325,13 +320,11 @@ pub struct ResponseBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ResponseBuilder {
|
impl ResponseBuilder {
|
||||||
|
#[inline]
|
||||||
/// Create response builder
|
/// Create response builder
|
||||||
pub fn new(status: StatusCode) -> Self {
|
pub fn new(status: StatusCode) -> Self {
|
||||||
let mut head = BoxedResponseHead::new();
|
|
||||||
head.status = status;
|
|
||||||
|
|
||||||
ResponseBuilder {
|
ResponseBuilder {
|
||||||
head: Some(head),
|
head: Some(BoxedResponseHead::new(status)),
|
||||||
err: None,
|
err: None,
|
||||||
cookies: None,
|
cookies: None,
|
||||||
}
|
}
|
||||||
|
@ -555,15 +548,13 @@ impl ResponseBuilder {
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn del_cookie<'a>(&mut self, cookie: &Cookie<'a>) -> &mut Self {
|
pub fn del_cookie<'a>(&mut self, cookie: &Cookie<'a>) -> &mut Self {
|
||||||
{
|
if self.cookies.is_none() {
|
||||||
if self.cookies.is_none() {
|
self.cookies = Some(CookieJar::new())
|
||||||
self.cookies = Some(CookieJar::new())
|
|
||||||
}
|
|
||||||
let jar = self.cookies.as_mut().unwrap();
|
|
||||||
let cookie = cookie.clone().into_owned();
|
|
||||||
jar.add_original(cookie.clone());
|
|
||||||
jar.remove(cookie);
|
|
||||||
}
|
}
|
||||||
|
let jar = self.cookies.as_mut().unwrap();
|
||||||
|
let cookie = cookie.clone().into_owned();
|
||||||
|
jar.add_original(cookie.clone());
|
||||||
|
jar.remove(cookie);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -605,6 +596,7 @@ impl ResponseBuilder {
|
||||||
head.extensions.borrow_mut()
|
head.extensions.borrow_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
/// Set a body and generate `Response`.
|
/// Set a body and generate `Response`.
|
||||||
///
|
///
|
||||||
/// `ResponseBuilder` can not be used after this call.
|
/// `ResponseBuilder` can not be used after this call.
|
||||||
|
@ -625,9 +617,7 @@ impl ResponseBuilder {
|
||||||
if let Some(ref jar) = self.cookies {
|
if let Some(ref jar) = self.cookies {
|
||||||
for cookie in jar.delta() {
|
for cookie in jar.delta() {
|
||||||
match HeaderValue::from_str(&cookie.to_string()) {
|
match HeaderValue::from_str(&cookie.to_string()) {
|
||||||
Ok(val) => {
|
Ok(val) => response.headers.append(header::SET_COOKIE, val),
|
||||||
let _ = response.headers.append(header::SET_COOKIE, val);
|
|
||||||
}
|
|
||||||
Err(e) => return Response::from(Error::from(e)).into_body(),
|
Err(e) => return Response::from(Error::from(e)).into_body(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -652,6 +642,7 @@ impl ResponseBuilder {
|
||||||
self.body(Body::from_message(BodyStream::new(stream)))
|
self.body(Body::from_message(BodyStream::new(stream)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
/// Set a json body and generate `Response`
|
/// Set a json body and generate `Response`
|
||||||
///
|
///
|
||||||
/// `ResponseBuilder` can not be used after this call.
|
/// `ResponseBuilder` can not be used after this call.
|
||||||
|
@ -751,11 +742,12 @@ impl<'a> From<&'a ResponseHead> for ResponseBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut msg = BoxedResponseHead::new();
|
let mut msg = BoxedResponseHead::new(head.status);
|
||||||
msg.version = head.version;
|
msg.version = head.version;
|
||||||
msg.status = head.status;
|
|
||||||
msg.reason = head.reason;
|
msg.reason = head.reason;
|
||||||
// msg.headers = head.headers.clone();
|
for (k, v) in &head.headers {
|
||||||
|
msg.headers.append(k.clone(), v.clone());
|
||||||
|
}
|
||||||
msg.no_chunking(!head.chunked());
|
msg.no_chunking(!head.chunked());
|
||||||
|
|
||||||
ResponseBuilder {
|
ResponseBuilder {
|
||||||
|
|
|
@ -178,6 +178,6 @@ impl TestRequest {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn parts<'a>(parts: &'a mut Option<Inner>) -> &'a mut Inner {
|
fn parts(parts: &mut Option<Inner>) -> &mut Inner {
|
||||||
parts.as_mut().expect("cannot reuse test request builder")
|
parts.as_mut().expect("cannot reuse test request builder")
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::fmt::Write as FmtWrite;
|
||||||
|
|
||||||
use actix_http::cookie::{Cookie, CookieJar};
|
use actix_http::cookie::{Cookie, CookieJar};
|
||||||
use actix_http::http::header::{self, Header, HeaderValue, IntoHeaderValue};
|
use actix_http::http::header::{self, Header, HeaderValue, IntoHeaderValue};
|
||||||
use actix_http::http::{HeaderName, HttpTryFrom, Version};
|
use actix_http::http::{HeaderName, HttpTryFrom, StatusCode, Version};
|
||||||
use actix_http::{h1, Payload, ResponseHead};
|
use actix_http::{h1, Payload, ResponseHead};
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -49,7 +49,7 @@ pub struct TestResponse {
|
||||||
impl Default for TestResponse {
|
impl Default for TestResponse {
|
||||||
fn default() -> TestResponse {
|
fn default() -> TestResponse {
|
||||||
TestResponse {
|
TestResponse {
|
||||||
head: ResponseHead::default(),
|
head: ResponseHead::new(StatusCode::OK),
|
||||||
cookies: CookieJar::new(),
|
cookies: CookieJar::new(),
|
||||||
payload: None,
|
payload: None,
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ use crate::config::{AppConfig, ServiceConfig};
|
||||||
use crate::data::{DataFactory, DataFactoryResult};
|
use crate::data::{DataFactory, DataFactoryResult};
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use crate::guard::Guard;
|
use crate::guard::Guard;
|
||||||
|
use crate::request::{HttpRequest, HttpRequestPool};
|
||||||
use crate::rmap::ResourceMap;
|
use crate::rmap::ResourceMap;
|
||||||
use crate::service::{ServiceFactory, ServiceRequest, ServiceResponse};
|
use crate::service::{ServiceFactory, ServiceRequest, ServiceResponse};
|
||||||
|
|
||||||
|
@ -21,7 +22,10 @@ type Guards = Vec<Box<Guard>>;
|
||||||
type HttpService<P> = BoxedService<ServiceRequest<P>, ServiceResponse, Error>;
|
type HttpService<P> = BoxedService<ServiceRequest<P>, ServiceResponse, Error>;
|
||||||
type HttpNewService<P> =
|
type HttpNewService<P> =
|
||||||
BoxedNewService<(), ServiceRequest<P>, ServiceResponse, Error, ()>;
|
BoxedNewService<(), ServiceRequest<P>, ServiceResponse, Error, ()>;
|
||||||
type BoxedResponse = Box<Future<Item = ServiceResponse, Error = Error>>;
|
type BoxedResponse = Either<
|
||||||
|
FutureResult<ServiceResponse, Error>,
|
||||||
|
Box<Future<Item = ServiceResponse, Error = Error>>,
|
||||||
|
>;
|
||||||
|
|
||||||
/// Service factory to convert `Request` to a `ServiceRequest<S>`.
|
/// Service factory to convert `Request` to a `ServiceRequest<S>`.
|
||||||
/// It also executes data factories.
|
/// It also executes data factories.
|
||||||
|
@ -191,6 +195,7 @@ where
|
||||||
chain: self.chain.take().unwrap(),
|
chain: self.chain.take().unwrap(),
|
||||||
rmap: self.rmap.clone(),
|
rmap: self.rmap.clone(),
|
||||||
config: self.config.clone(),
|
config: self.config.clone(),
|
||||||
|
pool: HttpRequestPool::create(),
|
||||||
}
|
}
|
||||||
.and_then(self.endpoint.take().unwrap()),
|
.and_then(self.endpoint.take().unwrap()),
|
||||||
))
|
))
|
||||||
|
@ -208,6 +213,7 @@ where
|
||||||
chain: C,
|
chain: C,
|
||||||
rmap: Rc<ResourceMap>,
|
rmap: Rc<ResourceMap>,
|
||||||
config: AppConfig,
|
config: AppConfig,
|
||||||
|
pool: &'static HttpRequestPool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C, P> Service for AppInitService<C, P>
|
impl<C, P> Service for AppInitService<C, P>
|
||||||
|
@ -224,13 +230,24 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(&mut self, req: Request) -> Self::Future {
|
fn call(&mut self, req: Request) -> Self::Future {
|
||||||
let req = ServiceRequest::new(
|
let (head, payload) = req.into_parts();
|
||||||
Path::new(Url::new(req.uri().clone())),
|
|
||||||
req,
|
let req = if let Some(mut req) = self.pool.get_request() {
|
||||||
self.rmap.clone(),
|
let inner = Rc::get_mut(&mut req.0).unwrap();
|
||||||
self.config.clone(),
|
inner.path.get_mut().update(&head.uri);
|
||||||
);
|
inner.path.reset();
|
||||||
self.chain.call(req)
|
inner.head = head;
|
||||||
|
req
|
||||||
|
} else {
|
||||||
|
HttpRequest::new(
|
||||||
|
Path::new(Url::new(head.uri.clone())),
|
||||||
|
head,
|
||||||
|
self.rmap.clone(),
|
||||||
|
self.config.clone(),
|
||||||
|
self.pool,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
self.chain.call(ServiceRequest::from_parts(req, payload))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -353,7 +370,7 @@ impl<P> Service for AppRouting<P> {
|
||||||
type Request = ServiceRequest<P>;
|
type Request = ServiceRequest<P>;
|
||||||
type Response = ServiceResponse;
|
type Response = ServiceResponse;
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
type Future = Either<BoxedResponse, FutureResult<Self::Response, Self::Error>>;
|
type Future = BoxedResponse;
|
||||||
|
|
||||||
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||||
if self.ready.is_none() {
|
if self.ready.is_none() {
|
||||||
|
@ -376,12 +393,12 @@ impl<P> Service for AppRouting<P> {
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Some((srv, _info)) = res {
|
if let Some((srv, _info)) = res {
|
||||||
Either::A(srv.call(req))
|
srv.call(req)
|
||||||
} else if let Some(ref mut default) = self.default {
|
} else if let Some(ref mut default) = self.default {
|
||||||
Either::A(default.call(req))
|
default.call(req)
|
||||||
} else {
|
} else {
|
||||||
let req = req.into_parts().0;
|
let req = req.into_parts().0;
|
||||||
Either::B(ok(ServiceResponse::new(req, Response::NotFound().finish())))
|
Either::A(ok(ServiceResponse::new(req, Response::NotFound().finish())))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
114
src/handler.rs
114
src/handler.rs
|
@ -52,37 +52,21 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<F, T, R> NewService for Handler<F, T, R>
|
|
||||||
|
impl<F, T, R> Clone for Handler<F, T, R>
|
||||||
where
|
where
|
||||||
F: Factory<T, R>,
|
F: Factory<T, R>,
|
||||||
R: Responder,
|
R: Responder,
|
||||||
{
|
{
|
||||||
type Request = (T, HttpRequest);
|
fn clone(&self) -> Self {
|
||||||
type Response = ServiceResponse;
|
Self {
|
||||||
type Error = Void;
|
|
||||||
type InitError = ();
|
|
||||||
type Service = HandlerService<F, T, R>;
|
|
||||||
type Future = FutureResult<Self::Service, ()>;
|
|
||||||
|
|
||||||
fn new_service(&self, _: &()) -> Self::Future {
|
|
||||||
ok(HandlerService {
|
|
||||||
hnd: self.hnd.clone(),
|
hnd: self.hnd.clone(),
|
||||||
_t: PhantomData,
|
_t: PhantomData,
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
impl<F, T, R> Service for Handler<F, T, R>
|
||||||
pub struct HandlerService<F, T, R>
|
|
||||||
where
|
|
||||||
F: Factory<T, R>,
|
|
||||||
R: Responder,
|
|
||||||
{
|
|
||||||
hnd: F,
|
|
||||||
_t: PhantomData<(T, R)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<F, T, R> Service for HandlerService<F, T, R>
|
|
||||||
where
|
where
|
||||||
F: Factory<T, R>,
|
F: Factory<T, R>,
|
||||||
R: Responder,
|
R: Responder,
|
||||||
|
@ -184,41 +168,23 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<F, T, R> NewService for AsyncHandler<F, T, R>
|
|
||||||
|
impl<F, T, R> Clone for AsyncHandler<F, T, R>
|
||||||
where
|
where
|
||||||
F: AsyncFactory<T, R>,
|
F: AsyncFactory<T, R>,
|
||||||
R: IntoFuture,
|
R: IntoFuture,
|
||||||
R::Item: Into<Response>,
|
R::Item: Into<Response>,
|
||||||
R::Error: Into<Error>,
|
R::Error: Into<Error>,
|
||||||
{
|
{
|
||||||
type Request = (T, HttpRequest);
|
fn clone(&self) -> Self {
|
||||||
type Response = ServiceResponse;
|
AsyncHandler {
|
||||||
type Error = Error;
|
|
||||||
type InitError = ();
|
|
||||||
type Service = AsyncHandlerService<F, T, R>;
|
|
||||||
type Future = FutureResult<Self::Service, ()>;
|
|
||||||
|
|
||||||
fn new_service(&self, _: &()) -> Self::Future {
|
|
||||||
ok(AsyncHandlerService {
|
|
||||||
hnd: self.hnd.clone(),
|
hnd: self.hnd.clone(),
|
||||||
_t: PhantomData,
|
_t: PhantomData,
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
impl<F, T, R> Service for AsyncHandler<F, T, R>
|
||||||
pub struct AsyncHandlerService<F, T, R>
|
|
||||||
where
|
|
||||||
F: AsyncFactory<T, R>,
|
|
||||||
R: IntoFuture,
|
|
||||||
R::Item: Into<Response>,
|
|
||||||
R::Error: Into<Error>,
|
|
||||||
{
|
|
||||||
hnd: F,
|
|
||||||
_t: PhantomData<(T, R)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<F, T, R> Service for AsyncHandlerService<F, T, R>
|
|
||||||
where
|
where
|
||||||
F: AsyncFactory<T, R>,
|
F: AsyncFactory<T, R>,
|
||||||
R: IntoFuture,
|
R: IntoFuture,
|
||||||
|
@ -227,7 +193,7 @@ where
|
||||||
{
|
{
|
||||||
type Request = (T, HttpRequest);
|
type Request = (T, HttpRequest);
|
||||||
type Response = ServiceResponse;
|
type Response = ServiceResponse;
|
||||||
type Error = Error;
|
type Error = Void;
|
||||||
type Future = AsyncHandlerServiceResponse<R::Future>;
|
type Future = AsyncHandlerServiceResponse<R::Future>;
|
||||||
|
|
||||||
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||||
|
@ -255,7 +221,7 @@ where
|
||||||
T::Error: Into<Error>,
|
T::Error: Into<Error>,
|
||||||
{
|
{
|
||||||
type Item = ServiceResponse;
|
type Item = ServiceResponse;
|
||||||
type Error = Error;
|
type Error = Void;
|
||||||
|
|
||||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||||
match self.fut.poll() {
|
match self.fut.poll() {
|
||||||
|
@ -276,46 +242,58 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extract arguments from request
|
/// Extract arguments from request
|
||||||
pub struct Extract<P, T: FromRequest<P>> {
|
pub struct Extract<P, T: FromRequest<P>, S> {
|
||||||
config: Rc<RefCell<Option<Rc<Extensions>>>>,
|
config: Rc<RefCell<Option<Rc<Extensions>>>>,
|
||||||
|
service: S,
|
||||||
_t: PhantomData<(P, T)>,
|
_t: PhantomData<(P, T)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P, T: FromRequest<P>> Extract<P, T> {
|
impl<P, T: FromRequest<P>, S> Extract<P, T, S> {
|
||||||
pub fn new(config: Rc<RefCell<Option<Rc<Extensions>>>>) -> Self {
|
pub fn new(config: Rc<RefCell<Option<Rc<Extensions>>>>, service: S) -> Self {
|
||||||
Extract {
|
Extract {
|
||||||
config,
|
config,
|
||||||
|
service,
|
||||||
_t: PhantomData,
|
_t: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P, T: FromRequest<P>> NewService for Extract<P, T> {
|
impl<P, T: FromRequest<P>, S> NewService for Extract<P, T, S>
|
||||||
|
where
|
||||||
|
S: Service<Request = (T, HttpRequest), Response = ServiceResponse, Error = Void>
|
||||||
|
+ Clone,
|
||||||
|
{
|
||||||
type Request = ServiceRequest<P>;
|
type Request = ServiceRequest<P>;
|
||||||
type Response = (T, HttpRequest);
|
type Response = ServiceResponse;
|
||||||
type Error = (Error, ServiceRequest<P>);
|
type Error = (Error, ServiceRequest<P>);
|
||||||
type InitError = ();
|
type InitError = ();
|
||||||
type Service = ExtractService<P, T>;
|
type Service = ExtractService<P, T, S>;
|
||||||
type Future = FutureResult<Self::Service, ()>;
|
type Future = FutureResult<Self::Service, ()>;
|
||||||
|
|
||||||
fn new_service(&self, _: &()) -> Self::Future {
|
fn new_service(&self, _: &()) -> Self::Future {
|
||||||
ok(ExtractService {
|
ok(ExtractService {
|
||||||
_t: PhantomData,
|
_t: PhantomData,
|
||||||
config: self.config.borrow().clone(),
|
config: self.config.borrow().clone(),
|
||||||
|
service: self.service.clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ExtractService<P, T: FromRequest<P>> {
|
pub struct ExtractService<P, T: FromRequest<P>, S> {
|
||||||
config: Option<Rc<Extensions>>,
|
config: Option<Rc<Extensions>>,
|
||||||
|
service: S,
|
||||||
_t: PhantomData<(P, T)>,
|
_t: PhantomData<(P, T)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P, T: FromRequest<P>> Service for ExtractService<P, T> {
|
impl<P, T: FromRequest<P>, S> Service for ExtractService<P, T, S>
|
||||||
|
where
|
||||||
|
S: Service<Request = (T, HttpRequest), Response = ServiceResponse, Error = Void>
|
||||||
|
+ Clone,
|
||||||
|
{
|
||||||
type Request = ServiceRequest<P>;
|
type Request = ServiceRequest<P>;
|
||||||
type Response = (T, HttpRequest);
|
type Response = ServiceResponse;
|
||||||
type Error = (Error, ServiceRequest<P>);
|
type Error = (Error, ServiceRequest<P>);
|
||||||
type Future = ExtractResponse<P, T>;
|
type Future = ExtractResponse<P, T, S>;
|
||||||
|
|
||||||
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||||
Ok(Async::Ready(()))
|
Ok(Async::Ready(()))
|
||||||
|
@ -328,28 +306,40 @@ impl<P, T: FromRequest<P>> Service for ExtractService<P, T> {
|
||||||
|
|
||||||
ExtractResponse {
|
ExtractResponse {
|
||||||
fut,
|
fut,
|
||||||
|
fut_s: None,
|
||||||
req: Some((req, payload)),
|
req: Some((req, payload)),
|
||||||
|
service: self.service.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ExtractResponse<P, T: FromRequest<P>> {
|
pub struct ExtractResponse<P, T: FromRequest<P>, S: Service> {
|
||||||
req: Option<(HttpRequest, Payload<P>)>,
|
req: Option<(HttpRequest, Payload<P>)>,
|
||||||
|
service: S,
|
||||||
fut: <T::Future as IntoFuture>::Future,
|
fut: <T::Future as IntoFuture>::Future,
|
||||||
|
fut_s: Option<S::Future>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P, T: FromRequest<P>> Future for ExtractResponse<P, T> {
|
impl<P, T: FromRequest<P>, S> Future for ExtractResponse<P, T, S>
|
||||||
type Item = (T, HttpRequest);
|
where
|
||||||
|
S: Service<Request = (T, HttpRequest), Response = ServiceResponse, Error = Void>,
|
||||||
|
{
|
||||||
|
type Item = ServiceResponse;
|
||||||
type Error = (Error, ServiceRequest<P>);
|
type Error = (Error, ServiceRequest<P>);
|
||||||
|
|
||||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||||
|
if let Some(ref mut fut) = self.fut_s {
|
||||||
|
return fut.poll().map_err(|_| panic!());
|
||||||
|
}
|
||||||
|
|
||||||
let item = try_ready!(self.fut.poll().map_err(|e| {
|
let item = try_ready!(self.fut.poll().map_err(|e| {
|
||||||
let (req, payload) = self.req.take().unwrap();
|
let (req, payload) = self.req.take().unwrap();
|
||||||
let req = ServiceRequest::from_parts(req, payload);
|
let req = ServiceRequest::from_parts(req, payload);
|
||||||
(e.into(), req)
|
(e.into(), req)
|
||||||
}));
|
}));
|
||||||
|
|
||||||
Ok(Async::Ready((item, self.req.take().unwrap().0)))
|
self.fut_s = Some(self.service.call((item, self.req.take().unwrap().0)));
|
||||||
|
self.poll()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::cell::{Ref, RefMut};
|
use std::cell::{Ref, RefCell, RefMut};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
@ -15,29 +15,34 @@ use crate::rmap::ResourceMap;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
/// An HTTP Request
|
/// An HTTP Request
|
||||||
pub struct HttpRequest {
|
pub struct HttpRequest(pub(crate) Rc<HttpRequestInner>);
|
||||||
|
|
||||||
|
pub(crate) struct HttpRequestInner {
|
||||||
pub(crate) head: Message<RequestHead>,
|
pub(crate) head: Message<RequestHead>,
|
||||||
pub(crate) path: Path<Url>,
|
pub(crate) path: Path<Url>,
|
||||||
rmap: Rc<ResourceMap>,
|
rmap: Rc<ResourceMap>,
|
||||||
config: AppConfig,
|
config: AppConfig,
|
||||||
route_data: Option<Rc<Extensions>>,
|
route_data: Option<Rc<Extensions>>,
|
||||||
|
pool: &'static HttpRequestPool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HttpRequest {
|
impl HttpRequest {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
head: Message<RequestHead>,
|
|
||||||
path: Path<Url>,
|
path: Path<Url>,
|
||||||
|
head: Message<RequestHead>,
|
||||||
rmap: Rc<ResourceMap>,
|
rmap: Rc<ResourceMap>,
|
||||||
config: AppConfig,
|
config: AppConfig,
|
||||||
|
pool: &'static HttpRequestPool,
|
||||||
) -> HttpRequest {
|
) -> HttpRequest {
|
||||||
HttpRequest {
|
HttpRequest(Rc::new(HttpRequestInner {
|
||||||
head,
|
head,
|
||||||
path,
|
path,
|
||||||
rmap,
|
rmap,
|
||||||
config,
|
config,
|
||||||
|
pool,
|
||||||
route_data: None,
|
route_data: None,
|
||||||
}
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +50,14 @@ impl HttpRequest {
|
||||||
/// This method returns reference to the request head
|
/// This method returns reference to the request head
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn head(&self) -> &RequestHead {
|
pub fn head(&self) -> &RequestHead {
|
||||||
&self.head
|
&self.0.head
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This method returns muttable reference to the request head.
|
||||||
|
/// panics if multiple references of http request exists.
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn head_mut(&mut self) -> &mut RequestHead {
|
||||||
|
&mut Rc::get_mut(&mut self.0).unwrap().head
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Request's uri.
|
/// Request's uri.
|
||||||
|
@ -98,7 +110,12 @@ impl HttpRequest {
|
||||||
/// access the matched value for that segment.
|
/// access the matched value for that segment.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn match_info(&self) -> &Path<Url> {
|
pub fn match_info(&self) -> &Path<Url> {
|
||||||
&self.path
|
&self.0.path
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn match_info_mut(&mut self) -> &mut Path<Url> {
|
||||||
|
&mut Rc::get_mut(&mut self.0).unwrap().path
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Request extensions
|
/// Request extensions
|
||||||
|
@ -141,7 +158,7 @@ impl HttpRequest {
|
||||||
U: IntoIterator<Item = I>,
|
U: IntoIterator<Item = I>,
|
||||||
I: AsRef<str>,
|
I: AsRef<str>,
|
||||||
{
|
{
|
||||||
self.rmap.url_for(&self, name, elements)
|
self.0.rmap.url_for(&self, name, elements)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate url for named resource
|
/// Generate url for named resource
|
||||||
|
@ -162,13 +179,13 @@ impl HttpRequest {
|
||||||
/// App config
|
/// App config
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn app_config(&self) -> &AppConfig {
|
pub fn app_config(&self) -> &AppConfig {
|
||||||
&self.config
|
&self.0.config
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get an application data stored with `App::data()` method during
|
/// Get an application data stored with `App::data()` method during
|
||||||
/// application configuration.
|
/// application configuration.
|
||||||
pub fn app_data<T: 'static>(&self) -> Option<Data<T>> {
|
pub fn app_data<T: 'static>(&self) -> Option<Data<T>> {
|
||||||
if let Some(st) = self.config.extensions().get::<Data<T>>() {
|
if let Some(st) = self.0.config.extensions().get::<Data<T>>() {
|
||||||
Some(st.clone())
|
Some(st.clone())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -178,7 +195,7 @@ impl HttpRequest {
|
||||||
/// Load route data. Route data could be set during
|
/// Load route data. Route data could be set during
|
||||||
/// route configuration with `Route::data()` method.
|
/// route configuration with `Route::data()` method.
|
||||||
pub fn route_data<T: 'static>(&self) -> Option<&RouteData<T>> {
|
pub fn route_data<T: 'static>(&self) -> Option<&RouteData<T>> {
|
||||||
if let Some(ref ext) = self.route_data {
|
if let Some(ref ext) = self.0.route_data {
|
||||||
ext.get::<RouteData<T>>()
|
ext.get::<RouteData<T>>()
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -186,7 +203,7 @@ impl HttpRequest {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn set_route_data(&mut self, data: Option<Rc<Extensions>>) {
|
pub(crate) fn set_route_data(&mut self, data: Option<Rc<Extensions>>) {
|
||||||
self.route_data = data;
|
Rc::get_mut(&mut self.0).unwrap().route_data = data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,13 +219,13 @@ impl HttpMessage for HttpRequest {
|
||||||
/// Request extensions
|
/// Request extensions
|
||||||
#[inline]
|
#[inline]
|
||||||
fn extensions(&self) -> Ref<Extensions> {
|
fn extensions(&self) -> Ref<Extensions> {
|
||||||
self.head.extensions()
|
self.0.head.extensions()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mutable reference to a the request's extensions
|
/// Mutable reference to a the request's extensions
|
||||||
#[inline]
|
#[inline]
|
||||||
fn extensions_mut(&self) -> RefMut<Extensions> {
|
fn extensions_mut(&self) -> RefMut<Extensions> {
|
||||||
self.head.extensions_mut()
|
self.0.head.extensions_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -217,6 +234,17 @@ impl HttpMessage for HttpRequest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Drop for HttpRequest {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if Rc::strong_count(&self.0) == 1 {
|
||||||
|
let v = &mut self.0.pool.0.borrow_mut();
|
||||||
|
if v.len() < 128 {
|
||||||
|
v.push(self.0.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// It is possible to get `HttpRequest` as an extractor handler parameter
|
/// It is possible to get `HttpRequest` as an extractor handler parameter
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
|
@ -252,8 +280,8 @@ impl fmt::Debug for HttpRequest {
|
||||||
writeln!(
|
writeln!(
|
||||||
f,
|
f,
|
||||||
"\nHttpRequest {:?} {}:{}",
|
"\nHttpRequest {:?} {}:{}",
|
||||||
self.head.version,
|
self.0.head.version,
|
||||||
self.head.method,
|
self.0.head.method,
|
||||||
self.path()
|
self.path()
|
||||||
)?;
|
)?;
|
||||||
if !self.query_string().is_empty() {
|
if !self.query_string().is_empty() {
|
||||||
|
@ -270,6 +298,26 @@ impl fmt::Debug for HttpRequest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Request's objects pool
|
||||||
|
pub(crate) struct HttpRequestPool(RefCell<Vec<Rc<HttpRequestInner>>>);
|
||||||
|
|
||||||
|
impl HttpRequestPool {
|
||||||
|
pub(crate) fn create() -> &'static HttpRequestPool {
|
||||||
|
let pool = HttpRequestPool(RefCell::new(Vec::with_capacity(128)));
|
||||||
|
Box::leak(Box::new(pool))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get message from the pool
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn get_request(&self) -> Option<HttpRequest> {
|
||||||
|
if let Some(inner) = self.0.borrow_mut().pop() {
|
||||||
|
Some(HttpRequest(inner))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -487,11 +487,8 @@ impl<P> Service for ResourceService<P> {
|
||||||
type Response = ServiceResponse;
|
type Response = ServiceResponse;
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
type Future = Either<
|
type Future = Either<
|
||||||
|
FutureResult<ServiceResponse, Error>,
|
||||||
Box<Future<Item = ServiceResponse, Error = Error>>,
|
Box<Future<Item = ServiceResponse, Error = Error>>,
|
||||||
Either<
|
|
||||||
Box<Future<Item = Self::Response, Error = Self::Error>>,
|
|
||||||
FutureResult<Self::Response, Self::Error>,
|
|
||||||
>,
|
|
||||||
>;
|
>;
|
||||||
|
|
||||||
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||||
|
@ -501,17 +498,17 @@ impl<P> Service for ResourceService<P> {
|
||||||
fn call(&mut self, mut req: ServiceRequest<P>) -> Self::Future {
|
fn call(&mut self, mut req: ServiceRequest<P>) -> Self::Future {
|
||||||
for route in self.routes.iter_mut() {
|
for route in self.routes.iter_mut() {
|
||||||
if route.check(&mut req) {
|
if route.check(&mut req) {
|
||||||
return Either::A(route.call(req));
|
return route.call(req);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(ref mut default) = self.default {
|
if let Some(ref mut default) = self.default {
|
||||||
Either::B(Either::A(default.call(req)))
|
default.call(req)
|
||||||
} else {
|
} else {
|
||||||
let req = req.into_parts().0;
|
let req = req.into_parts().0;
|
||||||
Either::B(Either::B(ok(ServiceResponse::new(
|
Either::A(ok(ServiceResponse::new(
|
||||||
req,
|
req,
|
||||||
Response::MethodNotAllowed().finish(),
|
Response::MethodNotAllowed().finish(),
|
||||||
))))
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
54
src/route.rs
54
src/route.rs
|
@ -4,6 +4,7 @@ use std::rc::Rc;
|
||||||
|
|
||||||
use actix_http::{http::Method, Error, Extensions, Response};
|
use actix_http::{http::Method, Error, Extensions, Response};
|
||||||
use actix_service::{NewService, Service};
|
use actix_service::{NewService, Service};
|
||||||
|
use futures::future::{ok, Either, FutureResult};
|
||||||
use futures::{Async, Future, IntoFuture, Poll};
|
use futures::{Async, Future, IntoFuture, Poll};
|
||||||
|
|
||||||
use crate::data::RouteData;
|
use crate::data::RouteData;
|
||||||
|
@ -19,7 +20,10 @@ type BoxedRouteService<Req, Res> = Box<
|
||||||
Request = Req,
|
Request = Req,
|
||||||
Response = Res,
|
Response = Res,
|
||||||
Error = Error,
|
Error = Error,
|
||||||
Future = Box<Future<Item = Res, Error = Error>>,
|
Future = Either<
|
||||||
|
FutureResult<Res, Error>,
|
||||||
|
Box<Future<Item = Res, Error = Error>>,
|
||||||
|
>,
|
||||||
>,
|
>,
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
@ -50,11 +54,10 @@ impl<P: 'static> Route<P> {
|
||||||
pub fn new() -> Route<P> {
|
pub fn new() -> Route<P> {
|
||||||
let data_ref = Rc::new(RefCell::new(None));
|
let data_ref = Rc::new(RefCell::new(None));
|
||||||
Route {
|
Route {
|
||||||
service: Box::new(RouteNewService::new(
|
service: Box::new(RouteNewService::new(Extract::new(
|
||||||
Extract::new(data_ref.clone()).and_then(
|
data_ref.clone(),
|
||||||
Handler::new(HttpResponse::NotFound).map_err(|_| panic!()),
|
Handler::new(|| HttpResponse::NotFound()),
|
||||||
),
|
))),
|
||||||
)),
|
|
||||||
guards: Rc::new(Vec::new()),
|
guards: Rc::new(Vec::new()),
|
||||||
data: None,
|
data: None,
|
||||||
data_ref,
|
data_ref,
|
||||||
|
@ -131,7 +134,10 @@ impl<P> Service for RouteService<P> {
|
||||||
type Request = ServiceRequest<P>;
|
type Request = ServiceRequest<P>;
|
||||||
type Response = ServiceResponse;
|
type Response = ServiceResponse;
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
type Future = Box<Future<Item = Self::Response, Error = Self::Error>>;
|
type Future = Either<
|
||||||
|
FutureResult<Self::Response, Self::Error>,
|
||||||
|
Box<Future<Item = Self::Response, Error = Self::Error>>,
|
||||||
|
>;
|
||||||
|
|
||||||
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||||
self.service.poll_ready()
|
self.service.poll_ready()
|
||||||
|
@ -235,10 +241,10 @@ impl<P: 'static> Route<P> {
|
||||||
T: FromRequest<P> + 'static,
|
T: FromRequest<P> + 'static,
|
||||||
R: Responder + 'static,
|
R: Responder + 'static,
|
||||||
{
|
{
|
||||||
self.service = Box::new(RouteNewService::new(
|
self.service = Box::new(RouteNewService::new(Extract::new(
|
||||||
Extract::new(self.data_ref.clone())
|
self.data_ref.clone(),
|
||||||
.and_then(Handler::new(handler).map_err(|_| panic!())),
|
Handler::new(handler),
|
||||||
));
|
)));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,10 +283,10 @@ impl<P: 'static> Route<P> {
|
||||||
R::Item: Into<Response>,
|
R::Item: Into<Response>,
|
||||||
R::Error: Into<Error>,
|
R::Error: Into<Error>,
|
||||||
{
|
{
|
||||||
self.service = Box::new(RouteNewService::new(
|
self.service = Box::new(RouteNewService::new(Extract::new(
|
||||||
Extract::new(self.data_ref.clone())
|
self.data_ref.clone(),
|
||||||
.and_then(AsyncHandler::new(handler).map_err(|_| panic!())),
|
AsyncHandler::new(handler),
|
||||||
));
|
)));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -394,17 +400,25 @@ where
|
||||||
type Request = ServiceRequest<P>;
|
type Request = ServiceRequest<P>;
|
||||||
type Response = ServiceResponse;
|
type Response = ServiceResponse;
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
type Future = Box<Future<Item = Self::Response, Error = Self::Error>>;
|
type Future = Either<
|
||||||
|
FutureResult<Self::Response, Self::Error>,
|
||||||
|
Box<Future<Item = Self::Response, Error = Self::Error>>,
|
||||||
|
>;
|
||||||
|
|
||||||
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||||
self.service.poll_ready().map_err(|(e, _)| e)
|
self.service.poll_ready().map_err(|(e, _)| e)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(&mut self, req: ServiceRequest<P>) -> Self::Future {
|
fn call(&mut self, req: ServiceRequest<P>) -> Self::Future {
|
||||||
Box::new(self.service.call(req).then(|res| match res {
|
let mut fut = self.service.call(req);
|
||||||
Ok(res) => Ok(res),
|
match fut.poll() {
|
||||||
Err((err, req)) => Ok(req.error_response(err)),
|
Ok(Async::Ready(res)) => Either::A(ok(res)),
|
||||||
}))
|
Err((e, req)) => Either::A(ok(req.error_response(e))),
|
||||||
|
Ok(Async::NotReady) => Either::B(Box::new(fut.then(|res| match res {
|
||||||
|
Ok(res) => Ok(res),
|
||||||
|
Err((err, req)) => Ok(req.error_response(err)),
|
||||||
|
}))),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,10 @@ type Guards = Vec<Box<Guard>>;
|
||||||
type HttpService<P> = BoxedService<ServiceRequest<P>, ServiceResponse, Error>;
|
type HttpService<P> = BoxedService<ServiceRequest<P>, ServiceResponse, Error>;
|
||||||
type HttpNewService<P> =
|
type HttpNewService<P> =
|
||||||
BoxedNewService<(), ServiceRequest<P>, ServiceResponse, Error, ()>;
|
BoxedNewService<(), ServiceRequest<P>, ServiceResponse, Error, ()>;
|
||||||
type BoxedResponse = Box<Future<Item = ServiceResponse, Error = Error>>;
|
type BoxedResponse = Either<
|
||||||
|
FutureResult<ServiceResponse, Error>,
|
||||||
|
Box<Future<Item = ServiceResponse, Error = Error>>,
|
||||||
|
>;
|
||||||
|
|
||||||
/// Resources scope.
|
/// Resources scope.
|
||||||
///
|
///
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
use std::cell::{Ref, RefMut};
|
use std::cell::{Ref, RefMut};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
use actix_http::body::{Body, MessageBody, ResponseBody};
|
use actix_http::body::{Body, MessageBody, ResponseBody};
|
||||||
use actix_http::http::{HeaderMap, Method, StatusCode, Uri, Version};
|
use actix_http::http::{HeaderMap, Method, StatusCode, Uri, Version};
|
||||||
use actix_http::{
|
use actix_http::{
|
||||||
Error, Extensions, HttpMessage, Payload, PayloadStream, Request, RequestHead,
|
Error, Extensions, HttpMessage, Payload, PayloadStream, RequestHead, Response,
|
||||||
Response, ResponseHead,
|
ResponseHead,
|
||||||
};
|
};
|
||||||
use actix_router::{Path, Resource, Url};
|
use actix_router::{Path, Resource, Url};
|
||||||
use futures::future::{ok, FutureResult, IntoFuture};
|
use futures::future::{ok, FutureResult, IntoFuture};
|
||||||
|
@ -15,7 +14,6 @@ use futures::future::{ok, FutureResult, IntoFuture};
|
||||||
use crate::config::{AppConfig, ServiceConfig};
|
use crate::config::{AppConfig, ServiceConfig};
|
||||||
use crate::data::Data;
|
use crate::data::Data;
|
||||||
use crate::request::HttpRequest;
|
use crate::request::HttpRequest;
|
||||||
use crate::rmap::ResourceMap;
|
|
||||||
|
|
||||||
pub trait HttpServiceFactory<P> {
|
pub trait HttpServiceFactory<P> {
|
||||||
fn register(self, config: &mut ServiceConfig<P>);
|
fn register(self, config: &mut ServiceConfig<P>);
|
||||||
|
@ -56,19 +54,6 @@ pub struct ServiceRequest<P = PayloadStream> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P> ServiceRequest<P> {
|
impl<P> ServiceRequest<P> {
|
||||||
pub(crate) fn new(
|
|
||||||
path: Path<Url>,
|
|
||||||
request: Request<P>,
|
|
||||||
rmap: Rc<ResourceMap>,
|
|
||||||
config: AppConfig,
|
|
||||||
) -> Self {
|
|
||||||
let (head, payload) = request.into_parts();
|
|
||||||
ServiceRequest {
|
|
||||||
payload,
|
|
||||||
req: HttpRequest::new(head, path, rmap, config),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Construct service request from parts
|
/// Construct service request from parts
|
||||||
pub fn from_parts(req: HttpRequest, payload: Payload<P>) -> Self {
|
pub fn from_parts(req: HttpRequest, payload: Payload<P>) -> Self {
|
||||||
ServiceRequest { req, payload }
|
ServiceRequest { req, payload }
|
||||||
|
@ -95,13 +80,13 @@ impl<P> ServiceRequest<P> {
|
||||||
/// This method returns reference to the request head
|
/// This method returns reference to the request head
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn head(&self) -> &RequestHead {
|
pub fn head(&self) -> &RequestHead {
|
||||||
&self.req.head
|
&self.req.head()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This method returns reference to the request head
|
/// This method returns reference to the request head
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn head_mut(&mut self) -> &mut RequestHead {
|
pub fn head_mut(&mut self) -> &mut RequestHead {
|
||||||
&mut self.req.head
|
self.req.head_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Request's uri.
|
/// Request's uri.
|
||||||
|
@ -160,12 +145,12 @@ impl<P> ServiceRequest<P> {
|
||||||
/// access the matched value for that segment.
|
/// access the matched value for that segment.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn match_info(&self) -> &Path<Url> {
|
pub fn match_info(&self) -> &Path<Url> {
|
||||||
&self.req.path
|
self.req.match_info()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn match_info_mut(&mut self) -> &mut Path<Url> {
|
pub fn match_info_mut(&mut self) -> &mut Path<Url> {
|
||||||
&mut self.req.path
|
self.req.match_info_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Service configuration
|
/// Service configuration
|
||||||
|
@ -203,13 +188,13 @@ impl<P> HttpMessage for ServiceRequest<P> {
|
||||||
/// Request extensions
|
/// Request extensions
|
||||||
#[inline]
|
#[inline]
|
||||||
fn extensions(&self) -> Ref<Extensions> {
|
fn extensions(&self) -> Ref<Extensions> {
|
||||||
self.req.head.extensions()
|
self.req.extensions()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mutable reference to a the request's extensions
|
/// Mutable reference to a the request's extensions
|
||||||
#[inline]
|
#[inline]
|
||||||
fn extensions_mut(&self) -> RefMut<Extensions> {
|
fn extensions_mut(&self) -> RefMut<Extensions> {
|
||||||
self.req.head.extensions_mut()
|
self.req.extensions_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
42
src/test.rs
42
src/test.rs
|
@ -17,6 +17,7 @@ use futures::future::{lazy, Future};
|
||||||
use crate::config::{AppConfig, AppConfigInner};
|
use crate::config::{AppConfig, AppConfigInner};
|
||||||
use crate::data::RouteData;
|
use crate::data::RouteData;
|
||||||
use crate::dev::{Body, Payload};
|
use crate::dev::{Body, Payload};
|
||||||
|
use crate::request::HttpRequestPool;
|
||||||
use crate::rmap::ResourceMap;
|
use crate::rmap::ResourceMap;
|
||||||
use crate::service::{ServiceRequest, ServiceResponse};
|
use crate::service::{ServiceRequest, ServiceResponse};
|
||||||
use crate::{Error, HttpRequest, HttpResponse};
|
use crate::{Error, HttpRequest, HttpResponse};
|
||||||
|
@ -326,14 +327,17 @@ impl TestRequest {
|
||||||
|
|
||||||
/// Complete request creation and generate `ServiceRequest` instance
|
/// Complete request creation and generate `ServiceRequest` instance
|
||||||
pub fn to_srv_request(mut self) -> ServiceRequest<PayloadStream> {
|
pub fn to_srv_request(mut self) -> ServiceRequest<PayloadStream> {
|
||||||
let req = self.req.finish();
|
let (head, payload) = self.req.finish().into_parts();
|
||||||
|
|
||||||
ServiceRequest::new(
|
let req = HttpRequest::new(
|
||||||
Path::new(Url::new(req.uri().clone())),
|
Path::new(Url::new(head.uri.clone())),
|
||||||
req,
|
head,
|
||||||
Rc::new(self.rmap),
|
Rc::new(self.rmap),
|
||||||
AppConfig::new(self.config),
|
AppConfig::new(self.config),
|
||||||
)
|
HttpRequestPool::create(),
|
||||||
|
);
|
||||||
|
|
||||||
|
ServiceRequest::from_parts(req, payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Complete request creation and generate `ServiceResponse` instance
|
/// Complete request creation and generate `ServiceResponse` instance
|
||||||
|
@ -343,34 +347,32 @@ impl TestRequest {
|
||||||
|
|
||||||
/// Complete request creation and generate `HttpRequest` instance
|
/// Complete request creation and generate `HttpRequest` instance
|
||||||
pub fn to_http_request(mut self) -> HttpRequest {
|
pub fn to_http_request(mut self) -> HttpRequest {
|
||||||
let req = self.req.finish();
|
let (head, _) = self.req.finish().into_parts();
|
||||||
|
|
||||||
let mut req = ServiceRequest::new(
|
let mut req = HttpRequest::new(
|
||||||
Path::new(Url::new(req.uri().clone())),
|
Path::new(Url::new(head.uri.clone())),
|
||||||
req,
|
head,
|
||||||
Rc::new(self.rmap),
|
Rc::new(self.rmap),
|
||||||
AppConfig::new(self.config),
|
AppConfig::new(self.config),
|
||||||
)
|
HttpRequestPool::create(),
|
||||||
.into_parts()
|
);
|
||||||
.0;
|
|
||||||
req.set_route_data(Some(Rc::new(self.route_data)));
|
req.set_route_data(Some(Rc::new(self.route_data)));
|
||||||
req
|
req
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Complete request creation and generate `HttpRequest` and `Payload` instances
|
/// Complete request creation and generate `HttpRequest` and `Payload` instances
|
||||||
pub fn to_http_parts(mut self) -> (HttpRequest, Payload) {
|
pub fn to_http_parts(mut self) -> (HttpRequest, Payload) {
|
||||||
let req = self.req.finish();
|
let (head, payload) = self.req.finish().into_parts();
|
||||||
|
|
||||||
let (mut req, pl) = ServiceRequest::new(
|
let mut req = HttpRequest::new(
|
||||||
Path::new(Url::new(req.uri().clone())),
|
Path::new(Url::new(head.uri.clone())),
|
||||||
req,
|
head,
|
||||||
Rc::new(self.rmap),
|
Rc::new(self.rmap),
|
||||||
AppConfig::new(self.config),
|
AppConfig::new(self.config),
|
||||||
)
|
HttpRequestPool::create(),
|
||||||
.into_parts();
|
);
|
||||||
|
|
||||||
req.set_route_data(Some(Rc::new(self.route_data)));
|
req.set_route_data(Some(Rc::new(self.route_data)));
|
||||||
(req, pl)
|
(req, payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Runs the provided future, blocking the current thread until the future
|
/// Runs the provided future, blocking the current thread until the future
|
||||||
|
|
Loading…
Reference in a new issue