mirror of
https://github.com/fafhrd91/actix-web
synced 2024-11-24 08:22:59 +01:00
split request and response modules (#2530)
This commit is contained in:
parent
2e00776d5e
commit
17f636a183
@ -1,8 +1,8 @@
|
|||||||
# Changes
|
# Changes
|
||||||
|
|
||||||
## Unreleased - 2021-xx-xx
|
## Unreleased - 2021-xx-xx
|
||||||
### Removed
|
### Changes
|
||||||
* `header::map::GetAll` iterator, its `Iterator::size_hint` method was wrongly implemented. Replaced with `std::slice::Iter`. [#2527]
|
* `HeaderMap::get_all` now returns a `std::slice::Iter`. [#2527]
|
||||||
|
|
||||||
[#2527]: https://github.com/actix/actix-web/pull/2527
|
[#2527]: https://github.com/actix/actix-web/pull/2527
|
||||||
|
|
||||||
|
@ -5,13 +5,15 @@ use bitflags::bitflags;
|
|||||||
use bytes::{Bytes, BytesMut};
|
use bytes::{Bytes, BytesMut};
|
||||||
use http::{Method, Version};
|
use http::{Method, Version};
|
||||||
|
|
||||||
use super::decoder::{PayloadDecoder, PayloadItem, PayloadType};
|
use super::{
|
||||||
use super::{decoder, encoder, reserve_readbuf};
|
decoder::{self, PayloadDecoder, PayloadItem, PayloadType},
|
||||||
use super::{Message, MessageType};
|
encoder, reserve_readbuf, Message, MessageType,
|
||||||
use crate::body::BodySize;
|
};
|
||||||
use crate::config::ServiceConfig;
|
use crate::{
|
||||||
use crate::error::{ParseError, PayloadError};
|
body::BodySize,
|
||||||
use crate::message::{ConnectionType, RequestHeadType, ResponseHead};
|
error::{ParseError, PayloadError},
|
||||||
|
ConnectionType, RequestHeadType, ResponseHead, ServiceConfig,
|
||||||
|
};
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
struct Flags: u8 {
|
struct Flags: u8 {
|
||||||
|
@ -5,15 +5,13 @@ use bitflags::bitflags;
|
|||||||
use bytes::BytesMut;
|
use bytes::BytesMut;
|
||||||
use http::{Method, Version};
|
use http::{Method, Version};
|
||||||
|
|
||||||
use super::decoder::{PayloadDecoder, PayloadItem, PayloadType};
|
use super::{
|
||||||
use super::{decoder, encoder};
|
decoder::{self, PayloadDecoder, PayloadItem, PayloadType},
|
||||||
use super::{Message, MessageType};
|
encoder, Message, MessageType,
|
||||||
use crate::body::BodySize;
|
};
|
||||||
use crate::config::ServiceConfig;
|
use crate::{
|
||||||
use crate::error::ParseError;
|
body::BodySize, error::ParseError, ConnectionType, Request, Response, ServiceConfig,
|
||||||
use crate::message::ConnectionType;
|
};
|
||||||
use crate::request::Request;
|
|
||||||
use crate::response::Response;
|
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
struct Flags: u8 {
|
struct Flags: u8 {
|
||||||
@ -199,7 +197,7 @@ mod tests {
|
|||||||
use http::Method;
|
use http::Method;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::HttpMessage;
|
use crate::HttpMessage as _;
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_http_request_chunked_payload_and_next_message() {
|
async fn test_http_request_chunked_payload_and_next_message() {
|
||||||
|
@ -2,17 +2,14 @@ use std::{convert::TryFrom, io, marker::PhantomData, mem::MaybeUninit, task::Pol
|
|||||||
|
|
||||||
use actix_codec::Decoder;
|
use actix_codec::Decoder;
|
||||||
use bytes::{Bytes, BytesMut};
|
use bytes::{Bytes, BytesMut};
|
||||||
use http::header::{HeaderName, HeaderValue};
|
use http::{
|
||||||
use http::{header, Method, StatusCode, Uri, Version};
|
header::{self, HeaderName, HeaderValue},
|
||||||
|
Method, StatusCode, Uri, Version,
|
||||||
|
};
|
||||||
use log::{debug, error, trace};
|
use log::{debug, error, trace};
|
||||||
|
|
||||||
use super::chunked::ChunkedState;
|
use super::chunked::ChunkedState;
|
||||||
use crate::{
|
use crate::{error::ParseError, header::HeaderMap, ConnectionType, Request, ResponseHead};
|
||||||
error::ParseError,
|
|
||||||
header::HeaderMap,
|
|
||||||
message::{ConnectionType, ResponseHead},
|
|
||||||
request::Request,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub(crate) const MAX_BUFFER_SIZE: usize = 131_072;
|
pub(crate) const MAX_BUFFER_SIZE: usize = 131_072;
|
||||||
const MAX_HEADERS: usize = 96;
|
const MAX_HEADERS: usize = 96;
|
||||||
@ -50,7 +47,7 @@ pub(crate) enum PayloadLength {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) trait MessageType: Sized {
|
pub(crate) trait MessageType: Sized {
|
||||||
fn set_connection_type(&mut self, ctype: Option<ConnectionType>);
|
fn set_connection_type(&mut self, conn_type: Option<ConnectionType>);
|
||||||
|
|
||||||
fn set_expect(&mut self);
|
fn set_expect(&mut self);
|
||||||
|
|
||||||
@ -193,8 +190,8 @@ pub(crate) trait MessageType: Sized {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl MessageType for Request {
|
impl MessageType for Request {
|
||||||
fn set_connection_type(&mut self, ctype: Option<ConnectionType>) {
|
fn set_connection_type(&mut self, conn_type: Option<ConnectionType>) {
|
||||||
if let Some(ctype) = ctype {
|
if let Some(ctype) = conn_type {
|
||||||
self.head_mut().set_connection_type(ctype);
|
self.head_mut().set_connection_type(ctype);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -278,8 +275,8 @@ impl MessageType for Request {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl MessageType for ResponseHead {
|
impl MessageType for ResponseHead {
|
||||||
fn set_connection_type(&mut self, ctype: Option<ConnectionType>) {
|
fn set_connection_type(&mut self, conn_type: Option<ConnectionType>) {
|
||||||
if let Some(ctype) = ctype {
|
if let Some(ctype) = conn_type {
|
||||||
ResponseHead::set_connection_type(self, ctype);
|
ResponseHead::set_connection_type(self, ctype);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
use std::io::Write;
|
use std::{
|
||||||
use std::marker::PhantomData;
|
cmp,
|
||||||
use std::ptr::copy_nonoverlapping;
|
io::{self, Write as _},
|
||||||
use std::slice::from_raw_parts_mut;
|
marker::PhantomData,
|
||||||
use std::{cmp, io};
|
ptr::copy_nonoverlapping,
|
||||||
|
slice::from_raw_parts_mut,
|
||||||
|
};
|
||||||
|
|
||||||
use bytes::{BufMut, BytesMut};
|
use bytes::{BufMut, BytesMut};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
body::BodySize,
|
body::BodySize,
|
||||||
config::ServiceConfig,
|
header::{
|
||||||
header::{map::Value, HeaderMap, HeaderName},
|
map::Value, HeaderMap, HeaderName, CONNECTION, CONTENT_LENGTH, DATE, TRANSFER_ENCODING,
|
||||||
header::{CONNECTION, CONTENT_LENGTH, DATE, TRANSFER_ENCODING},
|
},
|
||||||
helpers,
|
helpers, ConnectionType, RequestHeadType, Response, ServiceConfig, StatusCode, Version,
|
||||||
message::{ConnectionType, RequestHeadType},
|
|
||||||
Response, StatusCode, Version,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const AVERAGE_HEADER_SIZE: usize = 30;
|
const AVERAGE_HEADER_SIZE: usize = 30;
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
use actix_service::{Service, ServiceFactory};
|
use actix_service::{Service, ServiceFactory};
|
||||||
use actix_utils::future::{ready, Ready};
|
use actix_utils::future::{ready, Ready};
|
||||||
|
|
||||||
use crate::error::Error;
|
use crate::{Error, Request};
|
||||||
use crate::request::Request;
|
|
||||||
|
|
||||||
pub struct ExpectHandler;
|
pub struct ExpectHandler;
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ pub(crate) fn reserve_readbuf(src: &mut BytesMut) {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::request::Request;
|
use crate::Request;
|
||||||
|
|
||||||
impl Message<Request> {
|
impl Message<Request> {
|
||||||
pub fn message(self) -> Request {
|
pub fn message(self) -> Request {
|
||||||
|
@ -2,9 +2,7 @@ use actix_codec::Framed;
|
|||||||
use actix_service::{Service, ServiceFactory};
|
use actix_service::{Service, ServiceFactory};
|
||||||
use futures_core::future::LocalBoxFuture;
|
use futures_core::future::LocalBoxFuture;
|
||||||
|
|
||||||
use crate::error::Error;
|
use crate::{h1::Codec, Error, Request};
|
||||||
use crate::h1::Codec;
|
|
||||||
use crate::request::Request;
|
|
||||||
|
|
||||||
pub struct UpgradeHandler;
|
pub struct UpgradeHandler;
|
||||||
|
|
||||||
|
@ -9,9 +9,8 @@ use pin_project_lite::pin_project;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
body::{BodySize, MessageBody},
|
body::{BodySize, MessageBody},
|
||||||
error::Error,
|
|
||||||
h1::{Codec, Message},
|
h1::{Codec, Message},
|
||||||
response::Response,
|
Error, Response,
|
||||||
};
|
};
|
||||||
|
|
||||||
pin_project! {
|
pin_project! {
|
||||||
|
@ -31,23 +31,20 @@ extern crate log;
|
|||||||
pub mod body;
|
pub mod body;
|
||||||
mod builder;
|
mod builder;
|
||||||
mod config;
|
mod config;
|
||||||
|
|
||||||
#[cfg(feature = "__compress")]
|
#[cfg(feature = "__compress")]
|
||||||
pub mod encoding;
|
pub mod encoding;
|
||||||
|
pub mod error;
|
||||||
mod extensions;
|
mod extensions;
|
||||||
|
pub mod h1;
|
||||||
|
pub mod h2;
|
||||||
pub mod header;
|
pub mod header;
|
||||||
mod helpers;
|
mod helpers;
|
||||||
mod http_message;
|
mod http_message;
|
||||||
mod message;
|
mod message;
|
||||||
mod payload;
|
mod payload;
|
||||||
mod request;
|
mod requests;
|
||||||
mod response;
|
mod responses;
|
||||||
mod response_builder;
|
|
||||||
mod service;
|
mod service;
|
||||||
|
|
||||||
pub mod error;
|
|
||||||
pub mod h1;
|
|
||||||
pub mod h2;
|
|
||||||
pub mod test;
|
pub mod test;
|
||||||
pub mod ws;
|
pub mod ws;
|
||||||
|
|
||||||
@ -58,11 +55,10 @@ pub use self::extensions::Extensions;
|
|||||||
pub use self::header::ContentEncoding;
|
pub use self::header::ContentEncoding;
|
||||||
pub use self::http_message::HttpMessage;
|
pub use self::http_message::HttpMessage;
|
||||||
pub use self::message::ConnectionType;
|
pub use self::message::ConnectionType;
|
||||||
pub use self::message::{Message, RequestHead, RequestHeadType, ResponseHead};
|
pub use self::message::Message;
|
||||||
pub use self::payload::{Payload, PayloadStream};
|
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::responses::{Response, ResponseBuilder, ResponseHead};
|
||||||
pub use self::response_builder::ResponseBuilder;
|
|
||||||
pub use self::service::HttpService;
|
pub use self::service::HttpService;
|
||||||
|
|
||||||
pub use ::http::{uri, uri::Uri};
|
pub use ::http::{uri, uri::Uri};
|
||||||
|
@ -1,16 +1,7 @@
|
|||||||
use std::{
|
use std::{cell::RefCell, rc::Rc};
|
||||||
cell::{Ref, RefCell, RefMut},
|
|
||||||
net,
|
|
||||||
rc::Rc,
|
|
||||||
};
|
|
||||||
|
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
|
|
||||||
use crate::{
|
|
||||||
header::{self, HeaderMap},
|
|
||||||
Extensions, Method, StatusCode, Uri, Version,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Represents various types of connection
|
/// Represents various types of connection
|
||||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||||
pub enum ConnectionType {
|
pub enum ConnectionType {
|
||||||
@ -44,294 +35,6 @@ pub trait Head: Default + 'static {
|
|||||||
F: FnOnce(&MessagePool<Self>) -> R;
|
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,
|
|
||||||
pub status: StatusCode,
|
|
||||||
pub headers: HeaderMap,
|
|
||||||
pub reason: Option<&'static str>,
|
|
||||||
pub(crate) extensions: RefCell<Extensions>,
|
|
||||||
flags: Flags,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ResponseHead {
|
|
||||||
/// Create new instance of `ResponseHead` type
|
|
||||||
#[inline]
|
|
||||||
pub fn new(status: StatusCode) -> ResponseHead {
|
|
||||||
ResponseHead {
|
|
||||||
status,
|
|
||||||
version: Version::default(),
|
|
||||||
headers: HeaderMap::with_capacity(12),
|
|
||||||
reason: None,
|
|
||||||
flags: Flags::empty(),
|
|
||||||
extensions: RefCell::new(Extensions::new()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Message extensions
|
|
||||||
#[inline]
|
|
||||||
pub fn extensions(&self) -> Ref<'_, Extensions> {
|
|
||||||
self.extensions.borrow()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Mutable reference to a the message's extensions
|
|
||||||
#[inline]
|
|
||||||
pub fn extensions_mut(&self) -> RefMut<'_, Extensions> {
|
|
||||||
self.extensions.borrow_mut()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Read the message headers.
|
|
||||||
pub fn headers(&self) -> &HeaderMap {
|
|
||||||
&self.headers
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Mutable reference to the message headers.
|
|
||||||
pub fn headers_mut(&mut self) -> &mut HeaderMap {
|
|
||||||
&mut self.headers
|
|
||||||
}
|
|
||||||
|
|
||||||
#[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]
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check if keep-alive is enabled
|
|
||||||
#[inline]
|
|
||||||
pub fn keep_alive(&self) -> bool {
|
|
||||||
self.connection_type() == ConnectionType::KeepAlive
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check upgrade status of this message
|
|
||||||
#[inline]
|
|
||||||
pub fn upgrade(&self) -> bool {
|
|
||||||
self.connection_type() == ConnectionType::Upgrade
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get custom reason for the response
|
|
||||||
#[inline]
|
|
||||||
pub fn reason(&self) -> &str {
|
|
||||||
self.reason.unwrap_or_else(|| {
|
|
||||||
self.status
|
|
||||||
.canonical_reason()
|
|
||||||
.unwrap_or("<unknown status code>")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub(crate) fn conn_type(&self) -> Option<ConnectionType> {
|
|
||||||
if self.flags.contains(Flags::CLOSE) {
|
|
||||||
Some(ConnectionType::Close)
|
|
||||||
} else if self.flags.contains(Flags::KEEP_ALIVE) {
|
|
||||||
Some(ConnectionType::KeepAlive)
|
|
||||||
} else if self.flags.contains(Flags::UPGRADE) {
|
|
||||||
Some(ConnectionType::Upgrade)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Get response body chunking state
|
|
||||||
pub fn chunked(&self) -> bool {
|
|
||||||
!self.flags.contains(Flags::NO_CHUNKING)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Set no chunking for payload
|
|
||||||
pub fn no_chunking(&mut self, val: bool) {
|
|
||||||
if val {
|
|
||||||
self.flags.insert(Flags::NO_CHUNKING);
|
|
||||||
} else {
|
|
||||||
self.flags.remove(Flags::NO_CHUNKING);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Message<T: Head> {
|
pub struct Message<T: Head> {
|
||||||
/// Rc here should not be cloned by anyone.
|
/// Rc here should not be cloned by anyone.
|
||||||
/// It's used to reuse allocation of T and no shared ownership is allowed.
|
/// It's used to reuse allocation of T and no shared ownership is allowed.
|
||||||
@ -365,53 +68,12 @@ impl<T: Head> Drop for Message<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct BoxedResponseHead {
|
|
||||||
head: Option<Box<ResponseHead>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BoxedResponseHead {
|
|
||||||
/// Get new message from the pool of objects
|
|
||||||
pub fn new(status: StatusCode) -> Self {
|
|
||||||
RESPONSE_POOL.with(|p| p.get_message(status))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::ops::Deref for BoxedResponseHead {
|
|
||||||
type Target = ResponseHead;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
self.head.as_ref().unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::ops::DerefMut for BoxedResponseHead {
|
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
||||||
self.head.as_mut().unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for BoxedResponseHead {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
if let Some(head) = self.head.take() {
|
|
||||||
RESPONSE_POOL.with(move |p| p.release(head))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
/// Request's objects pool
|
/// Request's objects pool
|
||||||
pub struct MessagePool<T: Head>(RefCell<Vec<Rc<T>>>);
|
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> {
|
impl<T: Head> MessagePool<T> {
|
||||||
fn create() -> MessagePool<T> {
|
pub(crate) fn create() -> MessagePool<T> {
|
||||||
MessagePool(RefCell::new(Vec::with_capacity(128)))
|
MessagePool(RefCell::new(Vec::with_capacity(128)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -433,43 +95,11 @@ impl<T: Head> MessagePool<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
/// Release request instance
|
/// Release message instance
|
||||||
fn release(&self, msg: Rc<T>) {
|
fn release(&self, msg: Rc<T>) {
|
||||||
let v = &mut self.0.borrow_mut();
|
let pool = &mut self.0.borrow_mut();
|
||||||
if v.len() < 128 {
|
if pool.len() < 128 {
|
||||||
v.push(msg);
|
pool.push(msg);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BoxedResponsePool {
|
|
||||||
fn create() -> BoxedResponsePool {
|
|
||||||
BoxedResponsePool(RefCell::new(Vec::with_capacity(128)))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get message from the pool
|
|
||||||
#[inline]
|
|
||||||
fn get_message(&self, status: StatusCode) -> BoxedResponseHead {
|
|
||||||
if let Some(mut head) = self.0.borrow_mut().pop() {
|
|
||||||
head.reason = None;
|
|
||||||
head.status = status;
|
|
||||||
head.headers.clear();
|
|
||||||
head.flags = Flags::empty();
|
|
||||||
BoxedResponseHead { head: Some(head) }
|
|
||||||
} else {
|
|
||||||
BoxedResponseHead {
|
|
||||||
head: Some(Box::new(ResponseHead::new(status))),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Release request instance
|
|
||||||
fn release(&self, mut msg: Box<ResponseHead>) {
|
|
||||||
let v = &mut self.0.borrow_mut();
|
|
||||||
if v.len() < 128 {
|
|
||||||
msg.extensions.get_mut().clear();
|
|
||||||
v.push(msg);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ use h2::RecvStream;
|
|||||||
|
|
||||||
use crate::error::PayloadError;
|
use crate::error::PayloadError;
|
||||||
|
|
||||||
|
// TODO: rename to boxed payload
|
||||||
/// A boxed payload.
|
/// A boxed payload.
|
||||||
pub type PayloadStream = Pin<Box<dyn Stream<Item = Result<Bytes, PayloadError>>>>;
|
pub type PayloadStream = Pin<Box<dyn Stream<Item = Result<Bytes, PayloadError>>>>;
|
||||||
|
|
||||||
|
174
actix-http/src/requests/head.rs
Normal file
174
actix-http/src/requests/head.rs
Normal file
@ -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)
|
||||||
|
}
|
||||||
|
}
|
7
actix-http/src/requests/mod.rs
Normal file
7
actix-http/src/requests/mod.rs
Normal file
@ -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 http::{header, Method, Uri, Version};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
extensions::Extensions,
|
header::HeaderMap, Extensions, HttpMessage, Message, Payload, PayloadStream, RequestHead,
|
||||||
header::HeaderMap,
|
|
||||||
message::{Message, RequestHead},
|
|
||||||
payload::{Payload, PayloadStream},
|
|
||||||
HttpMessage,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// An HTTP request.
|
/// An HTTP request.
|
||||||
@ -206,7 +202,7 @@ impl<P> Request<P> {
|
|||||||
|
|
||||||
/// Returns the request data container, leaving an empty one in it's place.
|
/// Returns the request data container, leaving an empty one in it's place.
|
||||||
pub fn take_req_data(&mut self) -> Extensions {
|
pub fn take_req_data(&mut self) -> Extensions {
|
||||||
mem::take(&mut self.req_data.get_mut())
|
mem::take(self.req_data.get_mut())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -9,8 +9,8 @@ use crate::{
|
|||||||
body::{EitherBody, MessageBody},
|
body::{EitherBody, MessageBody},
|
||||||
error::{Error, HttpError},
|
error::{Error, HttpError},
|
||||||
header::{self, TryIntoHeaderPair, TryIntoHeaderValue},
|
header::{self, TryIntoHeaderPair, TryIntoHeaderValue},
|
||||||
message::{BoxedResponseHead, ConnectionType, ResponseHead},
|
responses::{BoxedResponseHead, ResponseHead},
|
||||||
Extensions, Response, StatusCode,
|
ConnectionType, Extensions, Response, StatusCode,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// An HTTP response builder.
|
/// An HTTP response builder.
|
208
actix-http/src/responses/head.rs
Normal file
208
actix-http/src/responses/head.rs
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
//! Response head type and caching pool.
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
cell::{Ref, RefCell, RefMut},
|
||||||
|
ops,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
header::HeaderMap, message::Flags, ConnectionType, Extensions, StatusCode, Version,
|
||||||
|
};
|
||||||
|
|
||||||
|
thread_local! {
|
||||||
|
static RESPONSE_POOL: BoxedResponsePool = BoxedResponsePool::create();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ResponseHead {
|
||||||
|
pub version: Version,
|
||||||
|
pub status: StatusCode,
|
||||||
|
pub headers: HeaderMap,
|
||||||
|
pub reason: Option<&'static str>,
|
||||||
|
pub(crate) extensions: RefCell<Extensions>,
|
||||||
|
flags: Flags,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ResponseHead {
|
||||||
|
/// Create new instance of `ResponseHead` type
|
||||||
|
#[inline]
|
||||||
|
pub fn new(status: StatusCode) -> ResponseHead {
|
||||||
|
ResponseHead {
|
||||||
|
status,
|
||||||
|
version: Version::HTTP_11,
|
||||||
|
headers: HeaderMap::with_capacity(12),
|
||||||
|
reason: None,
|
||||||
|
flags: Flags::empty(),
|
||||||
|
extensions: RefCell::new(Extensions::new()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
/// Read the message headers.
|
||||||
|
pub fn headers(&self) -> &HeaderMap {
|
||||||
|
&self.headers
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
/// Mutable reference to the message headers.
|
||||||
|
pub fn headers_mut(&mut self) -> &mut HeaderMap {
|
||||||
|
&mut self.headers
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Message extensions
|
||||||
|
#[inline]
|
||||||
|
pub fn extensions(&self) -> Ref<'_, Extensions> {
|
||||||
|
self.extensions.borrow()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Mutable reference to a the message's extensions
|
||||||
|
#[inline]
|
||||||
|
pub fn extensions_mut(&self) -> RefMut<'_, Extensions> {
|
||||||
|
self.extensions.borrow_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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]
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if keep-alive is enabled
|
||||||
|
#[inline]
|
||||||
|
pub fn keep_alive(&self) -> bool {
|
||||||
|
self.connection_type() == ConnectionType::KeepAlive
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check upgrade status of this message
|
||||||
|
#[inline]
|
||||||
|
pub fn upgrade(&self) -> bool {
|
||||||
|
self.connection_type() == ConnectionType::Upgrade
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get custom reason for the response
|
||||||
|
#[inline]
|
||||||
|
pub fn reason(&self) -> &str {
|
||||||
|
self.reason.unwrap_or_else(|| {
|
||||||
|
self.status
|
||||||
|
.canonical_reason()
|
||||||
|
.unwrap_or("<unknown status code>")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn conn_type(&self) -> Option<ConnectionType> {
|
||||||
|
if self.flags.contains(Flags::CLOSE) {
|
||||||
|
Some(ConnectionType::Close)
|
||||||
|
} else if self.flags.contains(Flags::KEEP_ALIVE) {
|
||||||
|
Some(ConnectionType::KeepAlive)
|
||||||
|
} else if self.flags.contains(Flags::UPGRADE) {
|
||||||
|
Some(ConnectionType::Upgrade)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
/// Get response body chunking state
|
||||||
|
pub fn chunked(&self) -> bool {
|
||||||
|
!self.flags.contains(Flags::NO_CHUNKING)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
/// Set no chunking for payload
|
||||||
|
pub fn no_chunking(&mut self, val: bool) {
|
||||||
|
if val {
|
||||||
|
self.flags.insert(Flags::NO_CHUNKING);
|
||||||
|
} else {
|
||||||
|
self.flags.remove(Flags::NO_CHUNKING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct BoxedResponseHead {
|
||||||
|
head: Option<Box<ResponseHead>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BoxedResponseHead {
|
||||||
|
/// Get new message from the pool of objects
|
||||||
|
pub fn new(status: StatusCode) -> Self {
|
||||||
|
RESPONSE_POOL.with(|p| p.get_message(status))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Deref for BoxedResponseHead {
|
||||||
|
type Target = ResponseHead;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
self.head.as_ref().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::DerefMut for BoxedResponseHead {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
self.head.as_mut().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for BoxedResponseHead {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if let Some(head) = self.head.take() {
|
||||||
|
RESPONSE_POOL.with(move |p| p.release(head))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Request's objects pool
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub struct BoxedResponsePool(#[allow(clippy::vec_box)] RefCell<Vec<Box<ResponseHead>>>);
|
||||||
|
|
||||||
|
impl BoxedResponsePool {
|
||||||
|
fn create() -> BoxedResponsePool {
|
||||||
|
BoxedResponsePool(RefCell::new(Vec::with_capacity(128)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get message from the pool
|
||||||
|
#[inline]
|
||||||
|
fn get_message(&self, status: StatusCode) -> BoxedResponseHead {
|
||||||
|
if let Some(mut head) = self.0.borrow_mut().pop() {
|
||||||
|
head.reason = None;
|
||||||
|
head.status = status;
|
||||||
|
head.headers.clear();
|
||||||
|
head.flags = Flags::empty();
|
||||||
|
BoxedResponseHead { head: Some(head) }
|
||||||
|
} else {
|
||||||
|
BoxedResponseHead {
|
||||||
|
head: Some(Box::new(ResponseHead::new(status))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Release request instance
|
||||||
|
#[inline]
|
||||||
|
fn release(&self, mut msg: Box<ResponseHead>) {
|
||||||
|
let pool = &mut self.0.borrow_mut();
|
||||||
|
if pool.len() < 128 {
|
||||||
|
msg.extensions.get_mut().clear();
|
||||||
|
pool.push(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
actix-http/src/responses/mod.rs
Normal file
11
actix-http/src/responses/mod.rs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
//! HTTP response.
|
||||||
|
|
||||||
|
mod builder;
|
||||||
|
mod head;
|
||||||
|
#[allow(clippy::module_inception)]
|
||||||
|
mod response;
|
||||||
|
|
||||||
|
pub use self::builder::ResponseBuilder;
|
||||||
|
pub(crate) use self::head::BoxedResponseHead;
|
||||||
|
pub use self::head::ResponseHead;
|
||||||
|
pub use self::response::Response;
|
@ -12,8 +12,8 @@ use crate::{
|
|||||||
body::{BoxBody, MessageBody},
|
body::{BoxBody, MessageBody},
|
||||||
extensions::Extensions,
|
extensions::Extensions,
|
||||||
header::{self, HeaderMap, TryIntoHeaderValue},
|
header::{self, HeaderMap, TryIntoHeaderValue},
|
||||||
message::{BoxedResponseHead, ResponseHead},
|
responses::{BoxedResponseHead, ResponseBuilder, ResponseHead},
|
||||||
Error, ResponseBuilder, StatusCode,
|
Error, StatusCode,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// An HTTP response.
|
/// An HTTP response.
|
@ -9,7 +9,7 @@ use derive_more::{Display, Error, From};
|
|||||||
use http::{header, Method, StatusCode};
|
use http::{header, Method, StatusCode};
|
||||||
|
|
||||||
use crate::body::BoxBody;
|
use crate::body::BoxBody;
|
||||||
use crate::{header::HeaderValue, message::RequestHead, response::Response, ResponseBuilder};
|
use crate::{header::HeaderValue, RequestHead, Response, ResponseBuilder};
|
||||||
|
|
||||||
mod codec;
|
mod codec;
|
||||||
mod dispatcher;
|
mod dispatcher;
|
||||||
|
@ -221,6 +221,7 @@ where
|
|||||||
req_data,
|
req_data,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
self.service.call(ServiceRequest::new(req, payload))
|
self.service.call(ServiceRequest::new(req, payload))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user