mirror of
https://github.com/actix/actix-web.git
synced 2024-11-26 03:21:08 +00:00
move response extensions out of head (#2585)
This commit is contained in:
parent
7b8a392ef5
commit
2ffc21dd4f
21 changed files with 205 additions and 226 deletions
|
@ -1,6 +1,10 @@
|
||||||
# Changes
|
# Changes
|
||||||
|
|
||||||
## Unreleased - 2021-xx-xx
|
## Unreleased - 2021-xx-xx
|
||||||
|
### Removed
|
||||||
|
- `HttpRequest::req_data[_mut]()`; request-local data is still available through `.extensions()`. [#2585]
|
||||||
|
|
||||||
|
[#2585]: https://github.com/actix/actix-web/pull/2585
|
||||||
|
|
||||||
|
|
||||||
## 4.0.0-beta.20 - 2022-01-14
|
## 4.0.0-beta.20 - 2022-01-14
|
||||||
|
|
|
@ -3,11 +3,17 @@
|
||||||
## Unreleased - 2021-xx-xx
|
## Unreleased - 2021-xx-xx
|
||||||
### Added
|
### Added
|
||||||
- Response headers can be sent as camel case using `res.head_mut().set_camel_case_headers(true)`. [#2587]
|
- Response headers can be sent as camel case using `res.head_mut().set_camel_case_headers(true)`. [#2587]
|
||||||
|
- `ResponseHead` now implements `Clone`. [#2585]
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Brotli (de)compression support is now provided by the `brotli` crate. [#2538]
|
- Brotli (de)compression support is now provided by the `brotli` crate. [#2538]
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
- `ResponseHead::extensions[_mut]()`. [#2585]
|
||||||
|
- `ResponseBuilder::extensions[_mut]()`. [#2585]
|
||||||
|
|
||||||
[#2538]: https://github.com/actix/actix-web/pull/2538
|
[#2538]: https://github.com/actix/actix-web/pull/2538
|
||||||
|
[#2585]: https://github.com/actix/actix-web/pull/2585
|
||||||
[#2587]: https://github.com/actix/actix-web/pull/2587
|
[#2587]: https://github.com/actix/actix-web/pull/2587
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ async fn main() -> io::Result<()> {
|
||||||
HttpService::build()
|
HttpService::build()
|
||||||
.client_timeout(1000)
|
.client_timeout(1000)
|
||||||
.client_disconnect(1000)
|
.client_disconnect(1000)
|
||||||
|
// handles HTTP/1.1 and HTTP/2
|
||||||
.finish(|mut req: Request| async move {
|
.finish(|mut req: Request| async move {
|
||||||
let mut body = BytesMut::new();
|
let mut body = BytesMut::new();
|
||||||
while let Some(item) = req.payload().next().await {
|
while let Some(item) = req.payload().next().await {
|
||||||
|
@ -23,12 +24,13 @@ async fn main() -> io::Result<()> {
|
||||||
|
|
||||||
log::info!("request body: {:?}", body);
|
log::info!("request body: {:?}", body);
|
||||||
|
|
||||||
Ok::<_, Error>(
|
let res = Response::build(StatusCode::OK)
|
||||||
Response::build(StatusCode::OK)
|
|
||||||
.insert_header(("x-head", HeaderValue::from_static("dummy value!")))
|
.insert_header(("x-head", HeaderValue::from_static("dummy value!")))
|
||||||
.body(body),
|
.body(body);
|
||||||
)
|
|
||||||
|
Ok::<_, Error>(res)
|
||||||
})
|
})
|
||||||
|
// No TLS
|
||||||
.tcp()
|
.tcp()
|
||||||
})?
|
})?
|
||||||
.run()
|
.run()
|
||||||
|
|
|
@ -1,32 +1,34 @@
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
use actix_http::{
|
use actix_http::{
|
||||||
body::MessageBody, header::HeaderValue, Error, HttpService, Request, Response, StatusCode,
|
body::{BodyStream, MessageBody},
|
||||||
|
header, Error, HttpMessage, HttpService, Request, Response, StatusCode,
|
||||||
};
|
};
|
||||||
use actix_server::Server;
|
|
||||||
use bytes::BytesMut;
|
|
||||||
use futures_util::StreamExt as _;
|
|
||||||
|
|
||||||
async fn handle_request(mut req: Request) -> Result<Response<impl MessageBody>, Error> {
|
async fn handle_request(mut req: Request) -> Result<Response<impl MessageBody>, Error> {
|
||||||
let mut body = BytesMut::new();
|
let mut res = Response::build(StatusCode::OK);
|
||||||
while let Some(item) = req.payload().next().await {
|
|
||||||
body.extend_from_slice(&item?)
|
if let Some(ct) = req.headers().get(header::CONTENT_TYPE) {
|
||||||
|
res.insert_header((header::CONTENT_TYPE, ct));
|
||||||
}
|
}
|
||||||
|
|
||||||
log::info!("request body: {:?}", body);
|
// echo request payload stream as (chunked) response body
|
||||||
|
let res = res.message_body(BodyStream::new(req.payload().take()))?;
|
||||||
|
|
||||||
Ok(Response::build(StatusCode::OK)
|
Ok(res)
|
||||||
.insert_header(("x-head", HeaderValue::from_static("dummy value!")))
|
|
||||||
.body(body))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[actix_rt::main]
|
#[actix_rt::main]
|
||||||
async fn main() -> io::Result<()> {
|
async fn main() -> io::Result<()> {
|
||||||
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
|
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
|
||||||
|
|
||||||
Server::build()
|
actix_server::Server::build()
|
||||||
.bind("echo", ("127.0.0.1", 8080), || {
|
.bind("echo", ("127.0.0.1", 8080), || {
|
||||||
HttpService::build().finish(handle_request).tcp()
|
HttpService::build()
|
||||||
|
// handles HTTP/1.1 only
|
||||||
|
.h1(handle_request)
|
||||||
|
// No TLS
|
||||||
|
.tcp()
|
||||||
})?
|
})?
|
||||||
.run()
|
.run()
|
||||||
.await
|
.await
|
||||||
|
|
|
@ -387,6 +387,7 @@ impl StdError for DispatchError {
|
||||||
|
|
||||||
/// A set of error that can occur during parsing content type.
|
/// A set of error that can occur during parsing content type.
|
||||||
#[derive(Debug, Display, Error)]
|
#[derive(Debug, Display, Error)]
|
||||||
|
#[cfg_attr(test, derive(PartialEq))]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum ContentTypeError {
|
pub enum ContentTypeError {
|
||||||
/// Can not parse content type
|
/// Can not parse content type
|
||||||
|
@ -398,28 +399,14 @@ pub enum ContentTypeError {
|
||||||
UnknownEncoding,
|
UnknownEncoding,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod content_type_test_impls {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
impl std::cmp::PartialEq for ContentTypeError {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
match self {
|
|
||||||
Self::ParseError => matches!(other, ContentTypeError::ParseError),
|
|
||||||
Self::UnknownEncoding => {
|
|
||||||
matches!(other, ContentTypeError::UnknownEncoding)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
|
||||||
use http::{Error as HttpError, StatusCode};
|
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
|
use http::{Error as HttpError, StatusCode};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_into_response() {
|
fn test_into_response() {
|
||||||
let resp: Response<BoxBody> = ParseError::Incomplete.into();
|
let resp: Response<BoxBody> = ParseError::Incomplete.into();
|
||||||
|
|
|
@ -25,10 +25,10 @@ pub trait HttpMessage: Sized {
|
||||||
/// Message payload stream
|
/// Message payload stream
|
||||||
fn take_payload(&mut self) -> Payload<Self::Stream>;
|
fn take_payload(&mut self) -> Payload<Self::Stream>;
|
||||||
|
|
||||||
/// Request's extensions container
|
/// Returns a reference to the request-local data/extensions container.
|
||||||
fn extensions(&self) -> Ref<'_, Extensions>;
|
fn extensions(&self) -> Ref<'_, Extensions>;
|
||||||
|
|
||||||
/// Mutable reference to a the request's extensions container
|
/// Returns a mutable reference to the request-local data/extensions container.
|
||||||
fn extensions_mut(&self) -> RefMut<'_, Extensions>;
|
fn extensions_mut(&self) -> RefMut<'_, Extensions>;
|
||||||
|
|
||||||
/// Get a header.
|
/// Get a header.
|
||||||
|
|
|
@ -5,13 +5,13 @@ use bitflags::bitflags;
|
||||||
/// 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 {
|
||||||
/// Close connection after response
|
/// Close connection after response.
|
||||||
Close,
|
Close,
|
||||||
|
|
||||||
/// Keep connection alive after response
|
/// Keep connection alive after response.
|
||||||
KeepAlive,
|
KeepAlive,
|
||||||
|
|
||||||
/// Connection is upgraded to different type
|
/// Connection is upgraded to different type.
|
||||||
Upgrade,
|
Upgrade,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,8 +69,8 @@ impl<T: Head> Drop for Message<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generic `Head` object pool.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
/// Request's objects pool
|
|
||||||
pub struct MessagePool<T: Head>(RefCell<Vec<Rc<T>>>);
|
pub struct MessagePool<T: Head>(RefCell<Vec<Rc<T>>>);
|
||||||
|
|
||||||
impl<T: Head> MessagePool<T> {
|
impl<T: Head> MessagePool<T> {
|
||||||
|
|
|
@ -142,8 +142,8 @@ impl RequestHead {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
#[allow(clippy::large_enum_variant)]
|
#[allow(clippy::large_enum_variant)]
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum RequestHeadType {
|
pub enum RequestHeadType {
|
||||||
Owned(RequestHead),
|
Owned(RequestHead),
|
||||||
Rc(Rc<RequestHead>, Option<HeaderMap>),
|
Rc(Rc<RequestHead>, Option<HeaderMap>),
|
||||||
|
|
|
@ -19,7 +19,7 @@ pub struct Request<P = BoxedPayloadStream> {
|
||||||
pub(crate) payload: Payload<P>,
|
pub(crate) payload: Payload<P>,
|
||||||
pub(crate) head: Message<RequestHead>,
|
pub(crate) head: Message<RequestHead>,
|
||||||
pub(crate) conn_data: Option<Rc<Extensions>>,
|
pub(crate) conn_data: Option<Rc<Extensions>>,
|
||||||
pub(crate) req_data: RefCell<Extensions>,
|
pub(crate) extensions: RefCell<Extensions>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P> HttpMessage for Request<P> {
|
impl<P> HttpMessage for Request<P> {
|
||||||
|
@ -34,16 +34,14 @@ impl<P> HttpMessage for Request<P> {
|
||||||
mem::replace(&mut self.payload, Payload::None)
|
mem::replace(&mut self.payload, Payload::None)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Request extensions
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn extensions(&self) -> Ref<'_, Extensions> {
|
fn extensions(&self) -> Ref<'_, Extensions> {
|
||||||
self.req_data.borrow()
|
self.extensions.borrow()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mutable reference to a the request's extensions
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn extensions_mut(&self) -> RefMut<'_, Extensions> {
|
fn extensions_mut(&self) -> RefMut<'_, Extensions> {
|
||||||
self.req_data.borrow_mut()
|
self.extensions.borrow_mut()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,7 +50,7 @@ impl From<Message<RequestHead>> for Request<BoxedPayloadStream> {
|
||||||
Request {
|
Request {
|
||||||
head,
|
head,
|
||||||
payload: Payload::None,
|
payload: Payload::None,
|
||||||
req_data: RefCell::new(Extensions::default()),
|
extensions: RefCell::new(Extensions::default()),
|
||||||
conn_data: None,
|
conn_data: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,7 +63,7 @@ impl Request<BoxedPayloadStream> {
|
||||||
Request {
|
Request {
|
||||||
head: Message::new(),
|
head: Message::new(),
|
||||||
payload: Payload::None,
|
payload: Payload::None,
|
||||||
req_data: RefCell::new(Extensions::default()),
|
extensions: RefCell::new(Extensions::default()),
|
||||||
conn_data: None,
|
conn_data: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,7 +75,7 @@ impl<P> Request<P> {
|
||||||
Request {
|
Request {
|
||||||
payload,
|
payload,
|
||||||
head: Message::new(),
|
head: Message::new(),
|
||||||
req_data: RefCell::new(Extensions::default()),
|
extensions: RefCell::new(Extensions::default()),
|
||||||
conn_data: None,
|
conn_data: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,7 +88,7 @@ impl<P> Request<P> {
|
||||||
Request {
|
Request {
|
||||||
payload,
|
payload,
|
||||||
head: self.head,
|
head: self.head,
|
||||||
req_data: self.req_data,
|
extensions: self.extensions,
|
||||||
conn_data: self.conn_data,
|
conn_data: self.conn_data,
|
||||||
},
|
},
|
||||||
pl,
|
pl,
|
||||||
|
@ -195,16 +193,17 @@ impl<P> Request<P> {
|
||||||
.and_then(|container| container.get::<T>())
|
.and_then(|container| container.get::<T>())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the connection data container if an [on-connect] callback was registered.
|
/// Returns the connection-level data/extensions container if an [on-connect] callback was
|
||||||
|
/// registered, leaving an empty one in its place.
|
||||||
///
|
///
|
||||||
/// [on-connect]: crate::HttpServiceBuilder::on_connect_ext
|
/// [on-connect]: crate::HttpServiceBuilder::on_connect_ext
|
||||||
pub fn take_conn_data(&mut self) -> Option<Rc<Extensions>> {
|
pub fn take_conn_data(&mut self) -> Option<Rc<Extensions>> {
|
||||||
self.conn_data.take()
|
self.conn_data.take()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the request data container, leaving an empty one in it's place.
|
/// Returns the request-local data/extensions container, leaving an empty one in its place.
|
||||||
pub fn take_req_data(&mut self) -> Extensions {
|
pub fn take_req_data(&mut self) -> Extensions {
|
||||||
mem::take(self.req_data.get_mut())
|
mem::take(self.extensions.get_mut())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
//! HTTP response builder.
|
//! HTTP response builder.
|
||||||
|
|
||||||
use std::{
|
use std::{cell::RefCell, fmt, str};
|
||||||
cell::{Ref, RefMut},
|
|
||||||
fmt, str,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
body::{EitherBody, MessageBody},
|
body::{EitherBody, MessageBody},
|
||||||
|
@ -202,20 +199,6 @@ impl ResponseBuilder {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Responses extensions
|
|
||||||
#[inline]
|
|
||||||
pub fn extensions(&self) -> Ref<'_, Extensions> {
|
|
||||||
let head = self.head.as_ref().expect("cannot reuse response builder");
|
|
||||||
head.extensions.borrow()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Mutable reference to a the response's extensions
|
|
||||||
#[inline]
|
|
||||||
pub fn extensions_mut(&mut self) -> RefMut<'_, Extensions> {
|
|
||||||
let head = self.head.as_ref().expect("cannot reuse response builder");
|
|
||||||
head.extensions.borrow_mut()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Generate response with a wrapped body.
|
/// Generate response with a wrapped body.
|
||||||
///
|
///
|
||||||
/// This `ResponseBuilder` will be left in a useless state.
|
/// This `ResponseBuilder` will be left in a useless state.
|
||||||
|
@ -238,7 +221,12 @@ impl ResponseBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
let head = self.head.take().expect("cannot reuse response builder");
|
let head = self.head.take().expect("cannot reuse response builder");
|
||||||
Ok(Response { head, body })
|
|
||||||
|
Ok(Response {
|
||||||
|
head,
|
||||||
|
body,
|
||||||
|
extensions: RefCell::new(Extensions::new()),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate response with an empty body.
|
/// Generate response with an empty body.
|
||||||
|
|
|
@ -1,25 +1,19 @@
|
||||||
//! Response head type and caching pool.
|
//! Response head type and caching pool.
|
||||||
|
|
||||||
use std::{
|
use std::{cell::RefCell, ops};
|
||||||
cell::{Ref, RefCell, RefMut},
|
|
||||||
ops,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{header::HeaderMap, message::Flags, ConnectionType, StatusCode, Version};
|
||||||
header::HeaderMap, message::Flags, ConnectionType, Extensions, StatusCode, Version,
|
|
||||||
};
|
|
||||||
|
|
||||||
thread_local! {
|
thread_local! {
|
||||||
static RESPONSE_POOL: BoxedResponsePool = BoxedResponsePool::create();
|
static RESPONSE_POOL: BoxedResponsePool = BoxedResponsePool::create();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ResponseHead {
|
pub struct ResponseHead {
|
||||||
pub version: Version,
|
pub version: Version,
|
||||||
pub status: StatusCode,
|
pub status: StatusCode,
|
||||||
pub headers: HeaderMap,
|
pub headers: HeaderMap,
|
||||||
pub reason: Option<&'static str>,
|
pub reason: Option<&'static str>,
|
||||||
pub(crate) extensions: RefCell<Extensions>,
|
|
||||||
pub(crate) flags: Flags,
|
pub(crate) flags: Flags,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,18 +27,17 @@ impl ResponseHead {
|
||||||
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()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Read the message headers.
|
/// Read the message headers.
|
||||||
|
#[inline]
|
||||||
pub fn headers(&self) -> &HeaderMap {
|
pub fn headers(&self) -> &HeaderMap {
|
||||||
&self.headers
|
&self.headers
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Mutable reference to the message headers.
|
/// Mutable reference to the message headers.
|
||||||
|
#[inline]
|
||||||
pub fn headers_mut(&mut self) -> &mut HeaderMap {
|
pub fn headers_mut(&mut self) -> &mut HeaderMap {
|
||||||
&mut self.headers
|
&mut self.headers
|
||||||
}
|
}
|
||||||
|
@ -61,20 +54,8 @@ impl ResponseHead {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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
|
/// Set connection type of the message
|
||||||
|
#[inline]
|
||||||
pub fn set_connection_type(&mut self, ctype: ConnectionType) {
|
pub fn set_connection_type(&mut self, ctype: ConnectionType) {
|
||||||
match ctype {
|
match ctype {
|
||||||
ConnectionType::Close => self.flags.insert(Flags::CLOSE),
|
ConnectionType::Close => self.flags.insert(Flags::CLOSE),
|
||||||
|
@ -133,14 +114,14 @@ impl ResponseHead {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Get response body chunking state
|
/// Get response body chunking state
|
||||||
|
#[inline]
|
||||||
pub fn chunked(&self) -> bool {
|
pub fn chunked(&self) -> bool {
|
||||||
!self.flags.contains(Flags::NO_CHUNKING)
|
!self.flags.contains(Flags::NO_CHUNKING)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Set no chunking for payload
|
/// Set no chunking for payload
|
||||||
|
#[inline]
|
||||||
pub fn no_chunking(&mut self, val: bool) {
|
pub fn no_chunking(&mut self, val: bool) {
|
||||||
if val {
|
if val {
|
||||||
self.flags.insert(Flags::NO_CHUNKING);
|
self.flags.insert(Flags::NO_CHUNKING);
|
||||||
|
@ -183,7 +164,7 @@ impl Drop for BoxedResponseHead {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Request's objects pool
|
/// Response head object pool.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub struct BoxedResponsePool(#[allow(clippy::vec_box)] RefCell<Vec<Box<ResponseHead>>>);
|
pub struct BoxedResponsePool(#[allow(clippy::vec_box)] RefCell<Vec<Box<ResponseHead>>>);
|
||||||
|
|
||||||
|
@ -192,7 +173,7 @@ impl BoxedResponsePool {
|
||||||
BoxedResponsePool(RefCell::new(Vec::with_capacity(128)))
|
BoxedResponsePool(RefCell::new(Vec::with_capacity(128)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get message from the pool
|
/// Get message from the pool.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_message(&self, status: StatusCode) -> BoxedResponseHead {
|
fn get_message(&self, status: StatusCode) -> BoxedResponseHead {
|
||||||
if let Some(mut head) = self.0.borrow_mut().pop() {
|
if let Some(mut head) = self.0.borrow_mut().pop() {
|
||||||
|
@ -208,12 +189,12 @@ impl BoxedResponsePool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Release request instance
|
/// Release request instance.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn release(&self, mut msg: Box<ResponseHead>) {
|
fn release(&self, msg: Box<ResponseHead>) {
|
||||||
let pool = &mut self.0.borrow_mut();
|
let pool = &mut self.0.borrow_mut();
|
||||||
|
|
||||||
if pool.len() < 128 {
|
if pool.len() < 128 {
|
||||||
msg.extensions.get_mut().clear();
|
|
||||||
pool.push(msg);
|
pool.push(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//! HTTP response.
|
//! HTTP response.
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
cell::{Ref, RefMut},
|
cell::{Ref, RefCell, RefMut},
|
||||||
fmt, str,
|
fmt, str,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ use bytes::{Bytes, BytesMut};
|
||||||
use bytestring::ByteString;
|
use bytestring::ByteString;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
body::{BoxBody, MessageBody},
|
body::{BoxBody, EitherBody, MessageBody},
|
||||||
header::{self, HeaderMap, TryIntoHeaderValue},
|
header::{self, HeaderMap, TryIntoHeaderValue},
|
||||||
responses::BoxedResponseHead,
|
responses::BoxedResponseHead,
|
||||||
Error, Extensions, ResponseBuilder, ResponseHead, StatusCode,
|
Error, Extensions, ResponseBuilder, ResponseHead, StatusCode,
|
||||||
|
@ -19,6 +19,7 @@ use crate::{
|
||||||
pub struct Response<B> {
|
pub struct Response<B> {
|
||||||
pub(crate) head: BoxedResponseHead,
|
pub(crate) head: BoxedResponseHead,
|
||||||
pub(crate) body: B,
|
pub(crate) body: B,
|
||||||
|
pub(crate) extensions: RefCell<Extensions>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Response<BoxBody> {
|
impl Response<BoxBody> {
|
||||||
|
@ -28,6 +29,7 @@ impl Response<BoxBody> {
|
||||||
Response {
|
Response {
|
||||||
head: BoxedResponseHead::new(status),
|
head: BoxedResponseHead::new(status),
|
||||||
body: BoxBody::new(()),
|
body: BoxBody::new(()),
|
||||||
|
extensions: RefCell::new(Extensions::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,6 +76,7 @@ impl<B> Response<B> {
|
||||||
Response {
|
Response {
|
||||||
head: BoxedResponseHead::new(status),
|
head: BoxedResponseHead::new(status),
|
||||||
body,
|
body,
|
||||||
|
extensions: RefCell::new(Extensions::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,20 +123,21 @@ impl<B> Response<B> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if keep-alive is enabled.
|
/// Returns true if keep-alive is enabled.
|
||||||
|
#[inline]
|
||||||
pub fn keep_alive(&self) -> bool {
|
pub fn keep_alive(&self) -> bool {
|
||||||
self.head.keep_alive()
|
self.head.keep_alive()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a reference to the extensions of this response.
|
/// Returns a reference to the request-local data/extensions container.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn extensions(&self) -> Ref<'_, Extensions> {
|
pub fn extensions(&self) -> Ref<'_, Extensions> {
|
||||||
self.head.extensions.borrow()
|
self.extensions.borrow()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a mutable reference to the extensions of this response.
|
/// Returns a mutable reference to the request-local data/extensions container.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn extensions_mut(&mut self) -> RefMut<'_, Extensions> {
|
pub fn extensions_mut(&mut self) -> RefMut<'_, Extensions> {
|
||||||
self.head.extensions.borrow_mut()
|
self.extensions.borrow_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a reference to the body of this response.
|
/// Returns a reference to the body of this response.
|
||||||
|
@ -143,24 +147,29 @@ impl<B> Response<B> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets new body.
|
/// Sets new body.
|
||||||
|
#[inline]
|
||||||
pub fn set_body<B2>(self, body: B2) -> Response<B2> {
|
pub fn set_body<B2>(self, body: B2) -> Response<B2> {
|
||||||
Response {
|
Response {
|
||||||
head: self.head,
|
head: self.head,
|
||||||
body,
|
body,
|
||||||
|
extensions: self.extensions,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Drops body and returns new response.
|
/// Drops body and returns new response.
|
||||||
|
#[inline]
|
||||||
pub fn drop_body(self) -> Response<()> {
|
pub fn drop_body(self) -> Response<()> {
|
||||||
self.set_body(())
|
self.set_body(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets new body, returning new response and previous body value.
|
/// Sets new body, returning new response and previous body value.
|
||||||
|
#[inline]
|
||||||
pub(crate) fn replace_body<B2>(self, body: B2) -> (Response<B2>, B) {
|
pub(crate) fn replace_body<B2>(self, body: B2) -> (Response<B2>, B) {
|
||||||
(
|
(
|
||||||
Response {
|
Response {
|
||||||
head: self.head,
|
head: self.head,
|
||||||
body,
|
body,
|
||||||
|
extensions: self.extensions,
|
||||||
},
|
},
|
||||||
self.body,
|
self.body,
|
||||||
)
|
)
|
||||||
|
@ -171,11 +180,15 @@ impl<B> Response<B> {
|
||||||
/// # Implementation Notes
|
/// # Implementation Notes
|
||||||
/// Due to internal performance optimizations, the first element of the returned tuple is a
|
/// Due to internal performance optimizations, the first element of the returned tuple is a
|
||||||
/// `Response` as well but only contains the head of the response this was called on.
|
/// `Response` as well but only contains the head of the response this was called on.
|
||||||
|
#[inline]
|
||||||
pub fn into_parts(self) -> (Response<()>, B) {
|
pub fn into_parts(self) -> (Response<()>, B) {
|
||||||
self.replace_body(())
|
self.replace_body(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns new response with mapped body.
|
/// Map the current body type to another using a closure. Returns a new response.
|
||||||
|
///
|
||||||
|
/// Closure receives the response head and the current body type.
|
||||||
|
#[inline]
|
||||||
pub fn map_body<F, B2>(mut self, f: F) -> Response<B2>
|
pub fn map_body<F, B2>(mut self, f: F) -> Response<B2>
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut ResponseHead, B) -> B2,
|
F: FnOnce(&mut ResponseHead, B) -> B2,
|
||||||
|
@ -185,6 +198,7 @@ impl<B> Response<B> {
|
||||||
Response {
|
Response {
|
||||||
head: self.head,
|
head: self.head,
|
||||||
body,
|
body,
|
||||||
|
extensions: self.extensions,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,6 +211,7 @@ impl<B> Response<B> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns body, consuming this response.
|
/// Returns body, consuming this response.
|
||||||
|
#[inline]
|
||||||
pub fn into_body(self) -> B {
|
pub fn into_body(self) -> B {
|
||||||
self.body
|
self.body
|
||||||
}
|
}
|
||||||
|
@ -239,9 +254,9 @@ impl<I: Into<Response<BoxBody>>, E: Into<Error>> From<Result<I, E>> for Response
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ResponseBuilder> for Response<BoxBody> {
|
impl From<ResponseBuilder> for Response<EitherBody<()>> {
|
||||||
fn from(mut builder: ResponseBuilder) -> Self {
|
fn from(mut builder: ResponseBuilder) -> Self {
|
||||||
builder.finish().map_into_boxed_body()
|
builder.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use std::{
|
use std::{
|
||||||
cell::{Ref, RefMut},
|
cell::{Ref, RefCell, RefMut},
|
||||||
fmt, mem,
|
fmt, mem,
|
||||||
pin::Pin,
|
pin::Pin,
|
||||||
task::{Context, Poll},
|
task::{Context, Poll},
|
||||||
|
@ -28,6 +28,8 @@ pin_project! {
|
||||||
#[pin]
|
#[pin]
|
||||||
pub(crate) payload: Payload<S>,
|
pub(crate) payload: Payload<S>,
|
||||||
pub(crate) timeout: ResponseTimeout,
|
pub(crate) timeout: ResponseTimeout,
|
||||||
|
pub(crate) extensions: RefCell<Extensions>,
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,6 +40,7 @@ impl<S> ClientResponse<S> {
|
||||||
head,
|
head,
|
||||||
payload,
|
payload,
|
||||||
timeout: ResponseTimeout::default(),
|
timeout: ResponseTimeout::default(),
|
||||||
|
extensions: RefCell::new(Extensions::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,7 +67,9 @@ impl<S> ClientResponse<S> {
|
||||||
&self.head().headers
|
&self.head().headers
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a body and return previous body value
|
/// Map the current body type to another using a closure. Returns a new response.
|
||||||
|
///
|
||||||
|
/// Closure receives the response head and the current body type.
|
||||||
pub fn map_body<F, U>(mut self, f: F) -> ClientResponse<U>
|
pub fn map_body<F, U>(mut self, f: F) -> ClientResponse<U>
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut ResponseHead, Payload<S>) -> Payload<U>,
|
F: FnOnce(&mut ResponseHead, Payload<S>) -> Payload<U>,
|
||||||
|
@ -75,6 +80,7 @@ impl<S> ClientResponse<S> {
|
||||||
payload,
|
payload,
|
||||||
head: self.head,
|
head: self.head,
|
||||||
timeout: self.timeout,
|
timeout: self.timeout,
|
||||||
|
extensions: self.extensions,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,6 +107,7 @@ impl<S> ClientResponse<S> {
|
||||||
payload: self.payload,
|
payload: self.payload,
|
||||||
head: self.head,
|
head: self.head,
|
||||||
timeout,
|
timeout,
|
||||||
|
extensions: self.extensions,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,11 +231,11 @@ impl<S> HttpMessage for ClientResponse<S> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extensions(&self) -> Ref<'_, Extensions> {
|
fn extensions(&self) -> Ref<'_, Extensions> {
|
||||||
self.head.extensions()
|
self.extensions.borrow()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extensions_mut(&self) -> RefMut<'_, Extensions> {
|
fn extensions_mut(&self) -> RefMut<'_, Extensions> {
|
||||||
self.head.extensions_mut()
|
self.extensions.borrow_mut()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ fi
|
||||||
|
|
||||||
# get current version
|
# get current version
|
||||||
PACKAGE_NAME="$(sed -nE 's/^name ?= ?"([^"]+)"$/\1/ p' "$CARGO_MANIFEST" | head -n 1)"
|
PACKAGE_NAME="$(sed -nE 's/^name ?= ?"([^"]+)"$/\1/ p' "$CARGO_MANIFEST" | head -n 1)"
|
||||||
CURRENT_VERSION="$(sed -nE 's/^version ?= ?"([^"]+)"$/\1/ p' "$CARGO_MANIFEST")"
|
CURRENT_VERSION="$(sed -nE 's/^version ?= ?"([^"]+)"$/\1/ p' "$CARGO_MANIFEST" | head -n 1)"
|
||||||
|
|
||||||
CHANGE_CHUNK_FILE="$(mktemp)"
|
CHANGE_CHUNK_FILE="$(mktemp)"
|
||||||
echo saving changelog to $CHANGE_CHUNK_FILE
|
echo saving changelog to $CHANGE_CHUNK_FILE
|
||||||
|
|
|
@ -201,27 +201,29 @@ where
|
||||||
actix_service::forward_ready!(service);
|
actix_service::forward_ready!(service);
|
||||||
|
|
||||||
fn call(&self, mut req: Request) -> Self::Future {
|
fn call(&self, mut req: Request) -> Self::Future {
|
||||||
let req_data = Rc::new(RefCell::new(req.take_req_data()));
|
let extensions = Rc::new(RefCell::new(req.take_req_data()));
|
||||||
let conn_data = req.take_conn_data();
|
let conn_data = req.take_conn_data();
|
||||||
let (head, payload) = req.into_parts();
|
let (head, payload) = req.into_parts();
|
||||||
|
|
||||||
let req = if let Some(mut req) = self.app_state.pool().pop() {
|
let req = match self.app_state.pool().pop() {
|
||||||
|
Some(mut req) => {
|
||||||
let inner = Rc::get_mut(&mut req.inner).unwrap();
|
let inner = Rc::get_mut(&mut req.inner).unwrap();
|
||||||
inner.path.get_mut().update(&head.uri);
|
inner.path.get_mut().update(&head.uri);
|
||||||
inner.path.reset();
|
inner.path.reset();
|
||||||
inner.head = head;
|
inner.head = head;
|
||||||
inner.conn_data = conn_data;
|
inner.conn_data = conn_data;
|
||||||
inner.req_data = req_data;
|
inner.extensions = extensions;
|
||||||
req
|
req
|
||||||
} else {
|
}
|
||||||
HttpRequest::new(
|
|
||||||
|
None => HttpRequest::new(
|
||||||
Path::new(Url::new(head.uri.clone())),
|
Path::new(Url::new(head.uri.clone())),
|
||||||
head,
|
head,
|
||||||
self.app_state.clone(),
|
Rc::clone(&self.app_state),
|
||||||
self.app_data.clone(),
|
Rc::clone(&self.app_data),
|
||||||
conn_data,
|
conn_data,
|
||||||
req_data,
|
extensions,
|
||||||
)
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
self.service.call(ServiceRequest::new(req, payload))
|
self.service.call(ServiceRequest::new(req, payload))
|
||||||
|
|
10
src/guard.rs
10
src/guard.rs
|
@ -54,7 +54,7 @@ use std::{
|
||||||
|
|
||||||
use actix_http::{header, uri::Uri, Extensions, Method as HttpMethod, RequestHead};
|
use actix_http::{header, uri::Uri, Extensions, Method as HttpMethod, RequestHead};
|
||||||
|
|
||||||
use crate::{http::header::Header, service::ServiceRequest};
|
use crate::{http::header::Header, service::ServiceRequest, HttpMessage as _};
|
||||||
|
|
||||||
/// Provides access to request parts that are useful during routing.
|
/// Provides access to request parts that are useful during routing.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -69,16 +69,16 @@ impl<'a> GuardContext<'a> {
|
||||||
self.req.head()
|
self.req.head()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns reference to the request-local data container.
|
/// Returns reference to the request-local data/extensions container.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn req_data(&self) -> Ref<'a, Extensions> {
|
pub fn req_data(&self) -> Ref<'a, Extensions> {
|
||||||
self.req.req_data()
|
self.req.extensions()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns mutable reference to the request-local data container.
|
/// Returns mutable reference to the request-local data/extensions container.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn req_data_mut(&self) -> RefMut<'a, Extensions> {
|
pub fn req_data_mut(&self) -> RefMut<'a, Extensions> {
|
||||||
self.req.req_data_mut()
|
self.req.extensions_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extracts a typed header from the request.
|
/// Extracts a typed header from the request.
|
||||||
|
|
|
@ -5,10 +5,7 @@ use std::{
|
||||||
str,
|
str,
|
||||||
};
|
};
|
||||||
|
|
||||||
use actix_http::{
|
use actix_http::{Message, RequestHead};
|
||||||
header::HeaderMap, Extensions, HttpMessage, Message, Method, Payload, RequestHead, Uri,
|
|
||||||
Version,
|
|
||||||
};
|
|
||||||
use actix_router::{Path, Url};
|
use actix_router::{Path, Url};
|
||||||
use actix_utils::future::{ok, Ready};
|
use actix_utils::future::{ok, Ready};
|
||||||
#[cfg(feature = "cookies")]
|
#[cfg(feature = "cookies")]
|
||||||
|
@ -16,8 +13,14 @@ use cookie::{Cookie, ParseError as CookieParseError};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
app_service::AppInitServiceState, config::AppConfig, error::UrlGenerationError,
|
app_service::AppInitServiceState,
|
||||||
info::ConnectionInfo, rmap::ResourceMap, Error, FromRequest,
|
config::AppConfig,
|
||||||
|
dev::{Extensions, Payload},
|
||||||
|
error::UrlGenerationError,
|
||||||
|
http::{header::HeaderMap, Method, Uri, Version},
|
||||||
|
info::ConnectionInfo,
|
||||||
|
rmap::ResourceMap,
|
||||||
|
Error, FromRequest, HttpMessage,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "cookies")]
|
#[cfg(feature = "cookies")]
|
||||||
|
@ -38,7 +41,7 @@ pub(crate) struct HttpRequestInner {
|
||||||
pub(crate) path: Path<Url>,
|
pub(crate) path: Path<Url>,
|
||||||
pub(crate) app_data: SmallVec<[Rc<Extensions>; 4]>,
|
pub(crate) app_data: SmallVec<[Rc<Extensions>; 4]>,
|
||||||
pub(crate) conn_data: Option<Rc<Extensions>>,
|
pub(crate) conn_data: Option<Rc<Extensions>>,
|
||||||
pub(crate) req_data: Rc<RefCell<Extensions>>,
|
pub(crate) extensions: Rc<RefCell<Extensions>>,
|
||||||
app_state: Rc<AppInitServiceState>,
|
app_state: Rc<AppInitServiceState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +53,7 @@ impl HttpRequest {
|
||||||
app_state: Rc<AppInitServiceState>,
|
app_state: Rc<AppInitServiceState>,
|
||||||
app_data: Rc<Extensions>,
|
app_data: Rc<Extensions>,
|
||||||
conn_data: Option<Rc<Extensions>>,
|
conn_data: Option<Rc<Extensions>>,
|
||||||
req_data: Rc<RefCell<Extensions>>,
|
extensions: Rc<RefCell<Extensions>>,
|
||||||
) -> HttpRequest {
|
) -> HttpRequest {
|
||||||
let mut data = SmallVec::<[Rc<Extensions>; 4]>::new();
|
let mut data = SmallVec::<[Rc<Extensions>; 4]>::new();
|
||||||
data.push(app_data);
|
data.push(app_data);
|
||||||
|
@ -62,7 +65,7 @@ impl HttpRequest {
|
||||||
app_state,
|
app_state,
|
||||||
app_data: data,
|
app_data: data,
|
||||||
conn_data,
|
conn_data,
|
||||||
req_data,
|
extensions,
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -159,14 +162,6 @@ impl HttpRequest {
|
||||||
self.resource_map().match_name(self.path())
|
self.resource_map().match_name(self.path())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn req_data(&self) -> Ref<'_, Extensions> {
|
|
||||||
self.inner.req_data.borrow()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn req_data_mut(&self) -> RefMut<'_, Extensions> {
|
|
||||||
self.inner.req_data.borrow_mut()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a reference a piece of connection data set in an [on-connect] callback.
|
/// Returns a reference a piece of connection data set in an [on-connect] callback.
|
||||||
///
|
///
|
||||||
/// ```ignore
|
/// ```ignore
|
||||||
|
@ -356,12 +351,12 @@ impl HttpMessage for HttpRequest {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn extensions(&self) -> Ref<'_, Extensions> {
|
fn extensions(&self) -> Ref<'_, Extensions> {
|
||||||
self.req_data()
|
self.inner.extensions.borrow()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn extensions_mut(&self) -> RefMut<'_, Extensions> {
|
fn extensions_mut(&self) -> RefMut<'_, Extensions> {
|
||||||
self.req_data_mut()
|
self.inner.extensions.borrow_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -382,7 +377,10 @@ impl Drop for HttpRequest {
|
||||||
|
|
||||||
// Inner is borrowed mut here and; get req data mutably to reduce borrow check. Also
|
// Inner is borrowed mut here and; get req data mutably to reduce borrow check. Also
|
||||||
// we know the req_data Rc will not have any cloned at this point to unwrap is okay.
|
// we know the req_data Rc will not have any cloned at this point to unwrap is okay.
|
||||||
Rc::get_mut(&mut inner.req_data).unwrap().get_mut().clear();
|
Rc::get_mut(&mut inner.extensions)
|
||||||
|
.unwrap()
|
||||||
|
.get_mut()
|
||||||
|
.clear();
|
||||||
|
|
||||||
// a re-borrow of pool is necessary here.
|
// a re-borrow of pool is necessary here.
|
||||||
let req = Rc::clone(&self.inner);
|
let req = Rc::clone(&self.inner);
|
||||||
|
|
|
@ -2,7 +2,10 @@ use std::{any::type_name, ops::Deref};
|
||||||
|
|
||||||
use actix_utils::future::{err, ok, Ready};
|
use actix_utils::future::{err, ok, Ready};
|
||||||
|
|
||||||
use crate::{dev::Payload, error::ErrorInternalServerError, Error, FromRequest, HttpRequest};
|
use crate::{
|
||||||
|
dev::Payload, error::ErrorInternalServerError, Error, FromRequest, HttpMessage as _,
|
||||||
|
HttpRequest,
|
||||||
|
};
|
||||||
|
|
||||||
/// Request-local data extractor.
|
/// Request-local data extractor.
|
||||||
///
|
///
|
||||||
|
@ -17,13 +20,13 @@ use crate::{dev::Payload, error::ErrorInternalServerError, Error, FromRequest, H
|
||||||
/// # Mutating Request Data
|
/// # Mutating Request Data
|
||||||
/// Note that since extractors must output owned data, only types that `impl Clone` can use this
|
/// Note that since extractors must output owned data, only types that `impl Clone` can use this
|
||||||
/// extractor. A clone is taken of the required request data and can, therefore, not be directly
|
/// extractor. A clone is taken of the required request data and can, therefore, not be directly
|
||||||
/// mutated in-place. To mutate request data, continue to use [`HttpRequest::req_data_mut`] or
|
/// mutated in-place. To mutate request data, continue to use [`HttpRequest::extensions_mut`] or
|
||||||
/// re-insert the cloned data back into the extensions map. A `DerefMut` impl is intentionally not
|
/// re-insert the cloned data back into the extensions map. A `DerefMut` impl is intentionally not
|
||||||
/// provided to make this potential foot-gun more obvious.
|
/// provided to make this potential foot-gun more obvious.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// # use actix_web::{web, HttpResponse, HttpRequest, Responder};
|
/// # use actix_web::{web, HttpResponse, HttpRequest, Responder, HttpMessage as _};
|
||||||
///
|
///
|
||||||
/// #[derive(Debug, Clone, PartialEq)]
|
/// #[derive(Debug, Clone, PartialEq)]
|
||||||
/// struct FlagFromMiddleware(String);
|
/// struct FlagFromMiddleware(String);
|
||||||
|
@ -35,7 +38,7 @@ use crate::{dev::Payload, error::ErrorInternalServerError, Error, FromRequest, H
|
||||||
/// ) -> impl Responder {
|
/// ) -> impl Responder {
|
||||||
/// // use an option extractor if middleware is not guaranteed to add this type of req data
|
/// // use an option extractor if middleware is not guaranteed to add this type of req data
|
||||||
/// if let Some(flag) = opt_flag {
|
/// if let Some(flag) = opt_flag {
|
||||||
/// assert_eq!(&flag.into_inner(), req.req_data().get::<FlagFromMiddleware>().unwrap());
|
/// assert_eq!(&flag.into_inner(), req.extensions().get::<FlagFromMiddleware>().unwrap());
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// HttpResponse::Ok()
|
/// HttpResponse::Ok()
|
||||||
|
@ -67,7 +70,7 @@ impl<T: Clone + 'static> FromRequest for ReqData<T> {
|
||||||
type Future = Ready<Result<Self, Error>>;
|
type Future = Ready<Result<Self, Error>>;
|
||||||
|
|
||||||
fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
|
fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
|
||||||
if let Some(st) = req.req_data().get::<T>() {
|
if let Some(st) = req.extensions().get::<T>() {
|
||||||
ok(ReqData(st.clone()))
|
ok(ReqData(st.clone()))
|
||||||
} else {
|
} else {
|
||||||
log::debug!(
|
log::debug!(
|
||||||
|
|
|
@ -7,7 +7,6 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use actix_http::{
|
use actix_http::{
|
||||||
body::{BodyStream, BoxBody, MessageBody},
|
|
||||||
error::HttpError,
|
error::HttpError,
|
||||||
header::{self, HeaderName, TryIntoHeaderPair, TryIntoHeaderValue},
|
header::{self, HeaderName, TryIntoHeaderPair, TryIntoHeaderValue},
|
||||||
ConnectionType, Extensions, Response, ResponseHead, StatusCode,
|
ConnectionType, Extensions, Response, ResponseHead, StatusCode,
|
||||||
|
@ -16,12 +15,8 @@ use bytes::Bytes;
|
||||||
use futures_core::Stream;
|
use futures_core::Stream;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
#[cfg(feature = "cookies")]
|
|
||||||
use actix_http::header::HeaderValue;
|
|
||||||
#[cfg(feature = "cookies")]
|
|
||||||
use cookie::{Cookie, CookieJar};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
body::{BodyStream, BoxBody, MessageBody},
|
||||||
error::{Error, JsonPayloadError},
|
error::{Error, JsonPayloadError},
|
||||||
BoxError, HttpRequest, HttpResponse, Responder,
|
BoxError, HttpRequest, HttpResponse, Responder,
|
||||||
};
|
};
|
||||||
|
@ -33,7 +28,7 @@ pub struct HttpResponseBuilder {
|
||||||
res: Option<Response<BoxBody>>,
|
res: Option<Response<BoxBody>>,
|
||||||
err: Option<HttpError>,
|
err: Option<HttpError>,
|
||||||
#[cfg(feature = "cookies")]
|
#[cfg(feature = "cookies")]
|
||||||
cookies: Option<CookieJar>,
|
cookies: Option<cookie::CookieJar>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HttpResponseBuilder {
|
impl HttpResponseBuilder {
|
||||||
|
@ -242,9 +237,9 @@ impl HttpResponseBuilder {
|
||||||
/// .finish();
|
/// .finish();
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(feature = "cookies")]
|
#[cfg(feature = "cookies")]
|
||||||
pub fn cookie<'c>(&mut self, cookie: Cookie<'c>) -> &mut Self {
|
pub fn cookie<'c>(&mut self, cookie: cookie::Cookie<'c>) -> &mut Self {
|
||||||
if self.cookies.is_none() {
|
if self.cookies.is_none() {
|
||||||
let mut jar = CookieJar::new();
|
let mut jar = cookie::CookieJar::new();
|
||||||
jar.add(cookie.into_owned());
|
jar.add(cookie.into_owned());
|
||||||
self.cookies = Some(jar)
|
self.cookies = Some(jar)
|
||||||
} else {
|
} else {
|
||||||
|
@ -271,9 +266,9 @@ impl HttpResponseBuilder {
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(feature = "cookies")]
|
#[cfg(feature = "cookies")]
|
||||||
pub fn del_cookie(&mut self, cookie: &Cookie<'_>) -> &mut Self {
|
pub fn del_cookie(&mut self, cookie: &cookie::Cookie<'_>) -> &mut Self {
|
||||||
if self.cookies.is_none() {
|
if self.cookies.is_none() {
|
||||||
self.cookies = Some(CookieJar::new())
|
self.cookies = Some(cookie::CookieJar::new())
|
||||||
}
|
}
|
||||||
let jar = self.cookies.as_mut().unwrap();
|
let jar = self.cookies.as_mut().unwrap();
|
||||||
let cookie = cookie.clone().into_owned();
|
let cookie = cookie.clone().into_owned();
|
||||||
|
@ -282,7 +277,7 @@ impl HttpResponseBuilder {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Responses extensions
|
/// Returns a reference to the response-local data/extensions container.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn extensions(&self) -> Ref<'_, Extensions> {
|
pub fn extensions(&self) -> Ref<'_, Extensions> {
|
||||||
self.res
|
self.res
|
||||||
|
@ -291,7 +286,8 @@ impl HttpResponseBuilder {
|
||||||
.extensions()
|
.extensions()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mutable reference to a the response's extensions
|
/// Returns a mutable reference to the response-local data/extensions container.
|
||||||
|
#[inline]
|
||||||
pub fn extensions_mut(&mut self) -> RefMut<'_, Extensions> {
|
pub fn extensions_mut(&mut self) -> RefMut<'_, Extensions> {
|
||||||
self.res
|
self.res
|
||||||
.as_mut()
|
.as_mut()
|
||||||
|
@ -332,7 +328,7 @@ impl HttpResponseBuilder {
|
||||||
#[cfg(feature = "cookies")]
|
#[cfg(feature = "cookies")]
|
||||||
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 actix_http::header::HeaderValue::from_str(&cookie.to_string()) {
|
||||||
Ok(val) => res.headers_mut().append(header::SET_COOKIE, val),
|
Ok(val) => res.headers_mut().append(header::SET_COOKIE, val),
|
||||||
Err(err) => return Err(err.into()),
|
Err(err) => return Err(err.into()),
|
||||||
};
|
};
|
||||||
|
@ -394,7 +390,6 @@ impl HttpResponseBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn inner(&mut self) -> Option<&mut ResponseHead> {
|
fn inner(&mut self) -> Option<&mut ResponseHead> {
|
||||||
if self.err.is_some() {
|
if self.err.is_some() {
|
||||||
return None;
|
return None;
|
||||||
|
@ -435,10 +430,9 @@ impl Responder for HttpResponseBuilder {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use actix_http::body;
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
|
body,
|
||||||
http::{
|
http::{
|
||||||
header::{self, HeaderValue, CONTENT_TYPE},
|
header::{self, HeaderValue, CONTENT_TYPE},
|
||||||
StatusCode,
|
StatusCode,
|
||||||
|
|
|
@ -168,34 +168,37 @@ impl<B> HttpResponse<B> {
|
||||||
self.res.keep_alive()
|
self.res.keep_alive()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Responses extensions
|
/// Returns reference to the response-local data/extensions container.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn extensions(&self) -> Ref<'_, Extensions> {
|
pub fn extensions(&self) -> Ref<'_, Extensions> {
|
||||||
self.res.extensions()
|
self.res.extensions()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mutable reference to a the response's extensions
|
/// Returns reference to the response-local data/extensions container.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn extensions_mut(&mut self) -> RefMut<'_, Extensions> {
|
pub fn extensions_mut(&mut self) -> RefMut<'_, Extensions> {
|
||||||
self.res.extensions_mut()
|
self.res.extensions_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get body of this response
|
/// Returns a reference to this response's body.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn body(&self) -> &B {
|
pub fn body(&self) -> &B {
|
||||||
self.res.body()
|
self.res.body()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a body
|
/// Sets new body.
|
||||||
pub fn set_body<B2>(self, body: B2) -> HttpResponse<B2> {
|
pub fn set_body<B2>(self, body: B2) -> HttpResponse<B2> {
|
||||||
HttpResponse {
|
HttpResponse {
|
||||||
res: self.res.set_body(body),
|
res: self.res.set_body(body),
|
||||||
error: None,
|
error: self.error,
|
||||||
// error: self.error, ??
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Split response and body
|
/// Returns split head and body.
|
||||||
|
///
|
||||||
|
/// # Implementation Notes
|
||||||
|
/// Due to internal performance optimizations, the first element of the returned tuple is an
|
||||||
|
/// `HttpResponse` as well but only contains the head of the response this was called on.
|
||||||
pub fn into_parts(self) -> (HttpResponse<()>, B) {
|
pub fn into_parts(self) -> (HttpResponse<()>, B) {
|
||||||
let (head, body) = self.res.into_parts();
|
let (head, body) = self.res.into_parts();
|
||||||
|
|
||||||
|
@ -208,7 +211,7 @@ impl<B> HttpResponse<B> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Drop request's body
|
/// Drops body and returns new response.
|
||||||
pub fn drop_body(self) -> HttpResponse<()> {
|
pub fn drop_body(self) -> HttpResponse<()> {
|
||||||
HttpResponse {
|
HttpResponse {
|
||||||
res: self.res.drop_body(),
|
res: self.res.drop_body(),
|
||||||
|
@ -216,7 +219,9 @@ impl<B> HttpResponse<B> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a body and return previous body value
|
/// Map the current body type to another using a closure. Returns a new response.
|
||||||
|
///
|
||||||
|
/// Closure receives the response head and the current body type.
|
||||||
pub fn map_body<F, B2>(self, f: F) -> HttpResponse<B2>
|
pub fn map_body<F, B2>(self, f: F) -> HttpResponse<B2>
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut ResponseHead, B) -> B2,
|
F: FnOnce(&mut ResponseHead, B) -> B2,
|
||||||
|
|
|
@ -103,6 +103,7 @@ impl ServiceRequest {
|
||||||
/// Construct request from request.
|
/// Construct request from request.
|
||||||
///
|
///
|
||||||
/// The returned `ServiceRequest` would have no payload.
|
/// The returned `ServiceRequest` would have no payload.
|
||||||
|
#[inline]
|
||||||
pub fn from_request(req: HttpRequest) -> Self {
|
pub fn from_request(req: HttpRequest) -> Self {
|
||||||
ServiceRequest {
|
ServiceRequest {
|
||||||
req,
|
req,
|
||||||
|
@ -256,18 +257,6 @@ impl ServiceRequest {
|
||||||
self.req.conn_data()
|
self.req.conn_data()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Counterpart to [`HttpRequest::req_data`].
|
|
||||||
#[inline]
|
|
||||||
pub fn req_data(&self) -> Ref<'_, Extensions> {
|
|
||||||
self.req.req_data()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Counterpart to [`HttpRequest::req_data_mut`].
|
|
||||||
#[inline]
|
|
||||||
pub fn req_data_mut(&self) -> RefMut<'_, Extensions> {
|
|
||||||
self.req.req_data_mut()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "cookies")]
|
#[cfg(feature = "cookies")]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn cookies(&self) -> Result<Ref<'_, Vec<Cookie<'static>>>, CookieParseError> {
|
pub fn cookies(&self) -> Result<Ref<'_, Vec<Cookie<'static>>>, CookieParseError> {
|
||||||
|
@ -320,18 +309,15 @@ impl HttpMessage for ServiceRequest {
|
||||||
type Stream = BoxedPayloadStream;
|
type Stream = BoxedPayloadStream;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
/// Returns Request's headers.
|
|
||||||
fn headers(&self) -> &HeaderMap {
|
fn headers(&self) -> &HeaderMap {
|
||||||
&self.head().headers
|
&self.head().headers
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Request extensions
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn extensions(&self) -> Ref<'_, Extensions> {
|
fn extensions(&self) -> Ref<'_, Extensions> {
|
||||||
self.req.extensions()
|
self.req.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.extensions_mut()
|
self.req.extensions_mut()
|
||||||
|
@ -398,32 +384,32 @@ impl<B> ServiceResponse<B> {
|
||||||
ServiceResponse::new(self.request, response)
|
ServiceResponse::new(self.request, response)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get reference to original request
|
/// Returns reference to original request.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn request(&self) -> &HttpRequest {
|
pub fn request(&self) -> &HttpRequest {
|
||||||
&self.request
|
&self.request
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get reference to response
|
/// Returns reference to response.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn response(&self) -> &HttpResponse<B> {
|
pub fn response(&self) -> &HttpResponse<B> {
|
||||||
&self.response
|
&self.response
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get mutable reference to response
|
/// Returns mutable reference to response.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn response_mut(&mut self) -> &mut HttpResponse<B> {
|
pub fn response_mut(&mut self) -> &mut HttpResponse<B> {
|
||||||
&mut self.response
|
&mut self.response
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the response status code
|
/// Returns response status code.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn status(&self) -> StatusCode {
|
pub fn status(&self) -> StatusCode {
|
||||||
self.response.status()
|
self.response.status()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Returns response's headers.
|
/// Returns response's headers.
|
||||||
|
#[inline]
|
||||||
pub fn headers(&self) -> &HeaderMap {
|
pub fn headers(&self) -> &HeaderMap {
|
||||||
self.response.headers()
|
self.response.headers()
|
||||||
}
|
}
|
||||||
|
@ -440,13 +426,9 @@ impl<B> ServiceResponse<B> {
|
||||||
(self.request, self.response)
|
(self.request, self.response)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extract response body
|
/// Map the current body type to another using a closure. Returns a new response.
|
||||||
#[inline]
|
///
|
||||||
pub fn into_body(self) -> B {
|
/// Closure receives the response head and the current body type.
|
||||||
self.response.into_body()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set a new body
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn map_body<F, B2>(self, f: F) -> ServiceResponse<B2>
|
pub fn map_body<F, B2>(self, f: F) -> ServiceResponse<B2>
|
||||||
where
|
where
|
||||||
|
@ -477,6 +459,12 @@ impl<B> ServiceResponse<B> {
|
||||||
{
|
{
|
||||||
self.map_body(|_, body| body.boxed())
|
self.map_body(|_, body| body.boxed())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Consumes the response and returns its body.
|
||||||
|
#[inline]
|
||||||
|
pub fn into_body(self) -> B {
|
||||||
|
self.response.into_body()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B> From<ServiceResponse<B>> for HttpResponse<B> {
|
impl<B> From<ServiceResponse<B>> for HttpResponse<B> {
|
||||||
|
@ -546,14 +534,12 @@ impl WebService {
|
||||||
/// Ok(req.into_response(HttpResponse::Ok().finish()))
|
/// Ok(req.into_response(HttpResponse::Ok().finish()))
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// fn main() {
|
|
||||||
/// let app = App::new()
|
/// let app = App::new()
|
||||||
/// .service(
|
/// .service(
|
||||||
/// web::service("/app")
|
/// web::service("/app")
|
||||||
/// .guard(guard::Header("content-type", "text/plain"))
|
/// .guard(guard::Header("content-type", "text/plain"))
|
||||||
/// .finish(index)
|
/// .finish(index)
|
||||||
/// );
|
/// );
|
||||||
/// }
|
|
||||||
/// ```
|
/// ```
|
||||||
pub fn guard<G: Guard + 'static>(mut self, guard: G) -> Self {
|
pub fn guard<G: Guard + 'static>(mut self, guard: G) -> Self {
|
||||||
self.guards.push(Box::new(guard));
|
self.guards.push(Box::new(guard));
|
||||||
|
|
Loading…
Reference in a new issue