mirror of https://github.com/fafhrd91/actix-web
split request module
This commit is contained in:
parent
75873924a2
commit
6134cbe25c
|
@ -5,13 +5,15 @@ use bitflags::bitflags;
|
|||
use bytes::{Bytes, BytesMut};
|
||||
use http::{Method, Version};
|
||||
|
||||
use super::decoder::{PayloadDecoder, PayloadItem, PayloadType};
|
||||
use super::{decoder, encoder, reserve_readbuf};
|
||||
use super::{Message, MessageType};
|
||||
use crate::body::BodySize;
|
||||
use crate::config::ServiceConfig;
|
||||
use crate::error::{ParseError, PayloadError};
|
||||
use crate::message::{ConnectionType, RequestHeadType, ResponseHead};
|
||||
use super::{
|
||||
decoder::{self, PayloadDecoder, PayloadItem, PayloadType},
|
||||
encoder, reserve_readbuf, Message, MessageType,
|
||||
};
|
||||
use crate::{
|
||||
body::BodySize,
|
||||
error::{ParseError, PayloadError},
|
||||
ConnectionType, RequestHeadType, ResponseHead, ServiceConfig,
|
||||
};
|
||||
|
||||
bitflags! {
|
||||
struct Flags: u8 {
|
||||
|
|
|
@ -5,15 +5,13 @@ use bitflags::bitflags;
|
|||
use bytes::BytesMut;
|
||||
use http::{Method, Version};
|
||||
|
||||
use super::decoder::{PayloadDecoder, PayloadItem, PayloadType};
|
||||
use super::{decoder, encoder};
|
||||
use super::{Message, MessageType};
|
||||
use crate::body::BodySize;
|
||||
use crate::config::ServiceConfig;
|
||||
use crate::error::ParseError;
|
||||
use crate::message::ConnectionType;
|
||||
use crate::request::Request;
|
||||
use crate::response::Response;
|
||||
use super::{
|
||||
decoder::{self, PayloadDecoder, PayloadItem, PayloadType},
|
||||
encoder, Message, MessageType,
|
||||
};
|
||||
use crate::{
|
||||
body::BodySize, error::ParseError, ConnectionType, Request, Response, ServiceConfig,
|
||||
};
|
||||
|
||||
bitflags! {
|
||||
struct Flags: u8 {
|
||||
|
@ -199,7 +197,7 @@ mod tests {
|
|||
use http::Method;
|
||||
|
||||
use super::*;
|
||||
use crate::HttpMessage;
|
||||
use crate::HttpMessage as _;
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn test_http_request_chunked_payload_and_next_message() {
|
||||
|
|
|
@ -8,10 +8,7 @@ use log::{debug, error, trace};
|
|||
|
||||
use super::chunked::ChunkedState;
|
||||
use crate::{
|
||||
error::ParseError,
|
||||
header::HeaderMap,
|
||||
message::{ConnectionType, ResponseHead},
|
||||
request::Request,
|
||||
error::ParseError, header::HeaderMap, message::ResponseHead, ConnectionType, Request,
|
||||
};
|
||||
|
||||
pub(crate) const MAX_BUFFER_SIZE: usize = 131_072;
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
use std::io::Write;
|
||||
use std::marker::PhantomData;
|
||||
use std::ptr::copy_nonoverlapping;
|
||||
use std::slice::from_raw_parts_mut;
|
||||
use std::{cmp, io};
|
||||
use std::{
|
||||
cmp,
|
||||
io::{self, Write as _},
|
||||
marker::PhantomData,
|
||||
ptr::copy_nonoverlapping,
|
||||
slice::from_raw_parts_mut,
|
||||
};
|
||||
|
||||
use bytes::{BufMut, BytesMut};
|
||||
|
||||
use crate::{
|
||||
body::BodySize,
|
||||
config::ServiceConfig,
|
||||
header::{map::Value, HeaderMap, HeaderName},
|
||||
header::{CONNECTION, CONTENT_LENGTH, DATE, TRANSFER_ENCODING},
|
||||
helpers,
|
||||
message::{ConnectionType, RequestHeadType},
|
||||
Response, StatusCode, Version,
|
||||
header::{
|
||||
map::Value, HeaderMap, HeaderName, CONNECTION, CONTENT_LENGTH, DATE, TRANSFER_ENCODING,
|
||||
},
|
||||
helpers, ConnectionType, RequestHeadType, Response, ServiceConfig, StatusCode, Version,
|
||||
};
|
||||
|
||||
const AVERAGE_HEADER_SIZE: usize = 30;
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
use actix_service::{Service, ServiceFactory};
|
||||
use actix_utils::future::{ready, Ready};
|
||||
|
||||
use crate::error::Error;
|
||||
use crate::request::Request;
|
||||
use crate::{Error, Request};
|
||||
|
||||
pub struct ExpectHandler;
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ pub(crate) fn reserve_readbuf(src: &mut BytesMut) {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::request::Request;
|
||||
use crate::Request;
|
||||
|
||||
impl Message<Request> {
|
||||
pub fn message(self) -> Request {
|
||||
|
|
|
@ -2,9 +2,7 @@ use actix_codec::Framed;
|
|||
use actix_service::{Service, ServiceFactory};
|
||||
use futures_core::future::LocalBoxFuture;
|
||||
|
||||
use crate::error::Error;
|
||||
use crate::h1::Codec;
|
||||
use crate::request::Request;
|
||||
use crate::{h1::Codec, Error, Request};
|
||||
|
||||
pub struct UpgradeHandler;
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ mod helpers;
|
|||
mod http_message;
|
||||
mod message;
|
||||
mod payload;
|
||||
mod request;
|
||||
mod requests;
|
||||
mod response;
|
||||
mod response_builder;
|
||||
mod service;
|
||||
|
@ -58,9 +58,9 @@ pub use self::extensions::Extensions;
|
|||
pub use self::header::ContentEncoding;
|
||||
pub use self::http_message::HttpMessage;
|
||||
pub use self::message::ConnectionType;
|
||||
pub use self::message::{Message, RequestHead, RequestHeadType, ResponseHead};
|
||||
pub use self::message::{Message, ResponseHead};
|
||||
pub use self::payload::{Payload, PayloadStream};
|
||||
pub use self::request::Request;
|
||||
pub use self::requests::{Request, RequestHead, RequestHeadType};
|
||||
pub use self::response::Response;
|
||||
pub use self::response_builder::ResponseBuilder;
|
||||
pub use self::service::HttpService;
|
||||
|
|
|
@ -1,15 +1,11 @@
|
|||
use std::{
|
||||
cell::{Ref, RefCell, RefMut},
|
||||
net,
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
use bitflags::bitflags;
|
||||
|
||||
use crate::{
|
||||
header::{self, HeaderMap},
|
||||
Extensions, Method, StatusCode, Uri, Version,
|
||||
};
|
||||
use crate::{header::HeaderMap, Extensions, StatusCode, Version};
|
||||
|
||||
/// Represents various types of connection
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
|
@ -44,169 +40,6 @@ pub trait Head: Default + 'static {
|
|||
F: FnOnce(&MessagePool<Self>) -> R;
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RequestHead {
|
||||
pub method: Method,
|
||||
pub uri: Uri,
|
||||
pub version: Version,
|
||||
pub headers: HeaderMap,
|
||||
pub peer_addr: Option<net::SocketAddr>,
|
||||
flags: Flags,
|
||||
}
|
||||
|
||||
impl Default for RequestHead {
|
||||
fn default() -> RequestHead {
|
||||
RequestHead {
|
||||
method: Method::default(),
|
||||
uri: Uri::default(),
|
||||
version: Version::HTTP_11,
|
||||
headers: HeaderMap::with_capacity(16),
|
||||
peer_addr: None,
|
||||
flags: Flags::empty(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Head for RequestHead {
|
||||
fn clear(&mut self) {
|
||||
self.flags = Flags::empty();
|
||||
self.headers.clear();
|
||||
}
|
||||
|
||||
fn with_pool<F, R>(f: F) -> R
|
||||
where
|
||||
F: FnOnce(&MessagePool<Self>) -> R,
|
||||
{
|
||||
REQUEST_POOL.with(|p| f(p))
|
||||
}
|
||||
}
|
||||
|
||||
impl RequestHead {
|
||||
/// Read the message headers.
|
||||
pub fn headers(&self) -> &HeaderMap {
|
||||
&self.headers
|
||||
}
|
||||
|
||||
/// Mutable reference to the message headers.
|
||||
pub fn headers_mut(&mut self) -> &mut HeaderMap {
|
||||
&mut self.headers
|
||||
}
|
||||
|
||||
/// Is to uppercase headers with Camel-Case.
|
||||
/// Default is `false`
|
||||
#[inline]
|
||||
pub fn camel_case_headers(&self) -> bool {
|
||||
self.flags.contains(Flags::CAMEL_CASE)
|
||||
}
|
||||
|
||||
/// Set `true` to send headers which are formatted as Camel-Case.
|
||||
#[inline]
|
||||
pub fn set_camel_case_headers(&mut self, val: bool) {
|
||||
if val {
|
||||
self.flags.insert(Flags::CAMEL_CASE);
|
||||
} else {
|
||||
self.flags.remove(Flags::CAMEL_CASE);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Set connection type of the message
|
||||
pub fn set_connection_type(&mut self, ctype: ConnectionType) {
|
||||
match ctype {
|
||||
ConnectionType::Close => self.flags.insert(Flags::CLOSE),
|
||||
ConnectionType::KeepAlive => self.flags.insert(Flags::KEEP_ALIVE),
|
||||
ConnectionType::Upgrade => self.flags.insert(Flags::UPGRADE),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Connection type
|
||||
pub fn connection_type(&self) -> ConnectionType {
|
||||
if self.flags.contains(Flags::CLOSE) {
|
||||
ConnectionType::Close
|
||||
} else if self.flags.contains(Flags::KEEP_ALIVE) {
|
||||
ConnectionType::KeepAlive
|
||||
} else if self.flags.contains(Flags::UPGRADE) {
|
||||
ConnectionType::Upgrade
|
||||
} else if self.version < Version::HTTP_11 {
|
||||
ConnectionType::Close
|
||||
} else {
|
||||
ConnectionType::KeepAlive
|
||||
}
|
||||
}
|
||||
|
||||
/// Connection upgrade status
|
||||
pub fn upgrade(&self) -> bool {
|
||||
self.headers()
|
||||
.get(header::CONNECTION)
|
||||
.map(|hdr| {
|
||||
if let Ok(s) = hdr.to_str() {
|
||||
s.to_ascii_lowercase().contains("upgrade")
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Get response body chunking state
|
||||
pub fn chunked(&self) -> bool {
|
||||
!self.flags.contains(Flags::NO_CHUNKING)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn no_chunking(&mut self, val: bool) {
|
||||
if val {
|
||||
self.flags.insert(Flags::NO_CHUNKING);
|
||||
} else {
|
||||
self.flags.remove(Flags::NO_CHUNKING);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Request contains `EXPECT` header
|
||||
pub fn expect(&self) -> bool {
|
||||
self.flags.contains(Flags::EXPECT)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn set_expect(&mut self) {
|
||||
self.flags.insert(Flags::EXPECT);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum RequestHeadType {
|
||||
Owned(RequestHead),
|
||||
Rc(Rc<RequestHead>, Option<HeaderMap>),
|
||||
}
|
||||
|
||||
impl RequestHeadType {
|
||||
pub fn extra_headers(&self) -> Option<&HeaderMap> {
|
||||
match self {
|
||||
RequestHeadType::Owned(_) => None,
|
||||
RequestHeadType::Rc(_, headers) => headers.as_ref(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<RequestHead> for RequestHeadType {
|
||||
fn as_ref(&self) -> &RequestHead {
|
||||
match self {
|
||||
RequestHeadType::Owned(head) => head,
|
||||
RequestHeadType::Rc(head, _) => head.as_ref(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RequestHead> for RequestHeadType {
|
||||
fn from(head: RequestHead) -> Self {
|
||||
RequestHeadType::Owned(head)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ResponseHead {
|
||||
pub version: Version,
|
||||
|
@ -402,16 +235,8 @@ impl Drop for BoxedResponseHead {
|
|||
/// Request's objects pool
|
||||
pub struct MessagePool<T: Head>(RefCell<Vec<Rc<T>>>);
|
||||
|
||||
#[doc(hidden)]
|
||||
#[allow(clippy::vec_box)]
|
||||
/// Request's objects pool
|
||||
pub struct BoxedResponsePool(RefCell<Vec<Box<ResponseHead>>>);
|
||||
|
||||
thread_local!(static REQUEST_POOL: MessagePool<RequestHead> = MessagePool::<RequestHead>::create());
|
||||
thread_local!(static RESPONSE_POOL: BoxedResponsePool = BoxedResponsePool::create());
|
||||
|
||||
impl<T: Head> MessagePool<T> {
|
||||
fn create() -> MessagePool<T> {
|
||||
pub(crate) fn create() -> MessagePool<T> {
|
||||
MessagePool(RefCell::new(Vec::with_capacity(128)))
|
||||
}
|
||||
|
||||
|
@ -433,15 +258,21 @@ impl<T: Head> MessagePool<T> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
/// Release request instance
|
||||
/// Release message instance
|
||||
fn release(&self, msg: Rc<T>) {
|
||||
let v = &mut self.0.borrow_mut();
|
||||
if v.len() < 128 {
|
||||
v.push(msg);
|
||||
let pool = &mut self.0.borrow_mut();
|
||||
if pool.len() < 128 {
|
||||
pool.push(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Response object caching pool.
|
||||
#[doc(hidden)]
|
||||
pub struct BoxedResponsePool(#[allow(clippy::vec_box)] RefCell<Vec<Box<ResponseHead>>>);
|
||||
|
||||
thread_local!(static RESPONSE_POOL: BoxedResponsePool = BoxedResponsePool::create());
|
||||
|
||||
impl BoxedResponsePool {
|
||||
fn create() -> BoxedResponsePool {
|
||||
BoxedResponsePool(RefCell::new(Vec::with_capacity(128)))
|
||||
|
|
|
@ -7,6 +7,7 @@ use h2::RecvStream;
|
|||
|
||||
use crate::error::PayloadError;
|
||||
|
||||
// TODO: rename to boxed payload
|
||||
/// A boxed payload.
|
||||
pub type PayloadStream = Pin<Box<dyn Stream<Item = Result<Bytes, PayloadError>>>>;
|
||||
|
||||
|
|
|
@ -0,0 +1,174 @@
|
|||
use std::{net, rc::Rc};
|
||||
|
||||
use crate::{
|
||||
header::{self, HeaderMap},
|
||||
message::{Flags, Head, MessagePool},
|
||||
ConnectionType, Method, Uri, Version,
|
||||
};
|
||||
|
||||
thread_local! {
|
||||
static REQUEST_POOL: MessagePool<RequestHead> = MessagePool::<RequestHead>::create()
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RequestHead {
|
||||
pub method: Method,
|
||||
pub uri: Uri,
|
||||
pub version: Version,
|
||||
pub headers: HeaderMap,
|
||||
pub peer_addr: Option<net::SocketAddr>,
|
||||
flags: Flags,
|
||||
}
|
||||
|
||||
impl Default for RequestHead {
|
||||
fn default() -> RequestHead {
|
||||
RequestHead {
|
||||
method: Method::default(),
|
||||
uri: Uri::default(),
|
||||
version: Version::HTTP_11,
|
||||
headers: HeaderMap::with_capacity(16),
|
||||
peer_addr: None,
|
||||
flags: Flags::empty(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Head for RequestHead {
|
||||
fn clear(&mut self) {
|
||||
self.flags = Flags::empty();
|
||||
self.headers.clear();
|
||||
}
|
||||
|
||||
fn with_pool<F, R>(f: F) -> R
|
||||
where
|
||||
F: FnOnce(&MessagePool<Self>) -> R,
|
||||
{
|
||||
REQUEST_POOL.with(|p| f(p))
|
||||
}
|
||||
}
|
||||
|
||||
impl RequestHead {
|
||||
/// Read the message headers.
|
||||
pub fn headers(&self) -> &HeaderMap {
|
||||
&self.headers
|
||||
}
|
||||
|
||||
/// Mutable reference to the message headers.
|
||||
pub fn headers_mut(&mut self) -> &mut HeaderMap {
|
||||
&mut self.headers
|
||||
}
|
||||
|
||||
/// Is to uppercase headers with Camel-Case.
|
||||
/// Default is `false`
|
||||
#[inline]
|
||||
pub fn camel_case_headers(&self) -> bool {
|
||||
self.flags.contains(Flags::CAMEL_CASE)
|
||||
}
|
||||
|
||||
/// Set `true` to send headers which are formatted as Camel-Case.
|
||||
#[inline]
|
||||
pub fn set_camel_case_headers(&mut self, val: bool) {
|
||||
if val {
|
||||
self.flags.insert(Flags::CAMEL_CASE);
|
||||
} else {
|
||||
self.flags.remove(Flags::CAMEL_CASE);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Set connection type of the message
|
||||
pub fn set_connection_type(&mut self, ctype: ConnectionType) {
|
||||
match ctype {
|
||||
ConnectionType::Close => self.flags.insert(Flags::CLOSE),
|
||||
ConnectionType::KeepAlive => self.flags.insert(Flags::KEEP_ALIVE),
|
||||
ConnectionType::Upgrade => self.flags.insert(Flags::UPGRADE),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Connection type
|
||||
pub fn connection_type(&self) -> ConnectionType {
|
||||
if self.flags.contains(Flags::CLOSE) {
|
||||
ConnectionType::Close
|
||||
} else if self.flags.contains(Flags::KEEP_ALIVE) {
|
||||
ConnectionType::KeepAlive
|
||||
} else if self.flags.contains(Flags::UPGRADE) {
|
||||
ConnectionType::Upgrade
|
||||
} else if self.version < Version::HTTP_11 {
|
||||
ConnectionType::Close
|
||||
} else {
|
||||
ConnectionType::KeepAlive
|
||||
}
|
||||
}
|
||||
|
||||
/// Connection upgrade status
|
||||
pub fn upgrade(&self) -> bool {
|
||||
self.headers()
|
||||
.get(header::CONNECTION)
|
||||
.map(|hdr| {
|
||||
if let Ok(s) = hdr.to_str() {
|
||||
s.to_ascii_lowercase().contains("upgrade")
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Get response body chunking state
|
||||
pub fn chunked(&self) -> bool {
|
||||
!self.flags.contains(Flags::NO_CHUNKING)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn no_chunking(&mut self, val: bool) {
|
||||
if val {
|
||||
self.flags.insert(Flags::NO_CHUNKING);
|
||||
} else {
|
||||
self.flags.remove(Flags::NO_CHUNKING);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Request contains `EXPECT` header
|
||||
pub fn expect(&self) -> bool {
|
||||
self.flags.contains(Flags::EXPECT)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn set_expect(&mut self) {
|
||||
self.flags.insert(Flags::EXPECT);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum RequestHeadType {
|
||||
Owned(RequestHead),
|
||||
Rc(Rc<RequestHead>, Option<HeaderMap>),
|
||||
}
|
||||
|
||||
impl RequestHeadType {
|
||||
pub fn extra_headers(&self) -> Option<&HeaderMap> {
|
||||
match self {
|
||||
RequestHeadType::Owned(_) => None,
|
||||
RequestHeadType::Rc(_, headers) => headers.as_ref(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<RequestHead> for RequestHeadType {
|
||||
fn as_ref(&self) -> &RequestHead {
|
||||
match self {
|
||||
RequestHeadType::Owned(head) => head,
|
||||
RequestHeadType::Rc(head, _) => head.as_ref(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RequestHead> for RequestHeadType {
|
||||
fn from(head: RequestHead) -> Self {
|
||||
RequestHeadType::Owned(head)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
//! HTTP requests.
|
||||
|
||||
mod head;
|
||||
mod request;
|
||||
|
||||
pub use self::head::{RequestHead, RequestHeadType};
|
||||
pub use self::request::Request;
|
|
@ -10,11 +10,7 @@ use std::{
|
|||
use http::{header, Method, Uri, Version};
|
||||
|
||||
use crate::{
|
||||
extensions::Extensions,
|
||||
header::HeaderMap,
|
||||
message::{Message, RequestHead},
|
||||
payload::{Payload, PayloadStream},
|
||||
HttpMessage,
|
||||
header::HeaderMap, Extensions, HttpMessage, Message, Payload, PayloadStream, RequestHead,
|
||||
};
|
||||
|
||||
/// An HTTP request.
|
||||
|
@ -206,7 +202,7 @@ impl<P> Request<P> {
|
|||
|
||||
/// Returns the request data container, leaving an empty one in it's place.
|
||||
pub fn take_req_data(&mut self) -> Extensions {
|
||||
mem::take(&mut self.req_data.get_mut())
|
||||
mem::take(self.req_data.get_mut())
|
||||
}
|
||||
}
|
||||
|
|
@ -9,7 +9,7 @@ use derive_more::{Display, Error, From};
|
|||
use http::{header, Method, StatusCode};
|
||||
|
||||
use crate::body::BoxBody;
|
||||
use crate::{header::HeaderValue, message::RequestHead, response::Response, ResponseBuilder};
|
||||
use crate::{header::HeaderValue, RequestHead, Response, ResponseBuilder};
|
||||
|
||||
mod codec;
|
||||
mod dispatcher;
|
||||
|
|
Loading…
Reference in New Issue