move response extensions out of head

This commit is contained in:
Rob Ede 2022-01-15 22:26:39 +00:00
parent 7b8a392ef5
commit 2fc9e76930
No known key found for this signature in database
GPG Key ID: 97C636207D3EF933
11 changed files with 129 additions and 129 deletions

View File

@ -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,15 @@ 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),
) res.req_data_mut().insert(5usize);
Ok::<_, Error>(res)
}) })
// No TLS
.tcp() .tcp()
})? })?
.run() .run()

View File

@ -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

View File

@ -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> {

View File

@ -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>),

View File

@ -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.

View File

@ -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);
} }
} }

View File

@ -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,6 +123,7 @@ 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()
} }
@ -127,13 +131,13 @@ impl<B> Response<B> {
/// Returns a reference to the extensions of this response. /// Returns a reference to the extensions of this response.
#[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 extensions of this response.
#[inline] #[inline]
pub fn extensions_mut(&mut self) -> RefMut<'_, Extensions> { pub fn extensions_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,13 @@ 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. /// Returns new response with mapped body.
#[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 +196,7 @@ impl<B> Response<B> {
Response { Response {
head: self.head, head: self.head,
body, body,
extensions: self.extensions,
} }
} }
@ -197,6 +209,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 +252,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()
} }
} }

View File

@ -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()),
} }
} }
@ -75,6 +78,7 @@ impl<S> ClientResponse<S> {
payload, payload,
head: self.head, head: self.head,
timeout: self.timeout, timeout: self.timeout,
extensions: self.extensions,
} }
} }
@ -101,6 +105,7 @@ impl<S> ClientResponse<S> {
payload: self.payload, payload: self.payload,
head: self.head, head: self.head,
timeout, timeout,
extensions: self.extensions,
} }
} }
@ -112,6 +117,18 @@ impl<S> ClientResponse<S> {
self self
} }
/// Returns a reference to the extensions of this response.
#[inline]
pub fn req_data(&self) -> Ref<'_, Extensions> {
self.extensions.borrow()
}
/// Returns a mutable reference to the extensions of this response.
#[inline]
pub fn req_data_mut(&self) -> RefMut<'_, Extensions> {
self.extensions.borrow_mut()
}
/// Load request cookies. /// Load request cookies.
#[cfg(feature = "cookies")] #[cfg(feature = "cookies")]
pub fn cookies(&self) -> Result<Ref<'_, Vec<Cookie<'static>>>, CookieParseError> { pub fn cookies(&self) -> Result<Ref<'_, Vec<Cookie<'static>>>, CookieParseError> {
@ -224,11 +241,11 @@ impl<S> HttpMessage for ClientResponse<S> {
} }
fn extensions(&self) -> Ref<'_, Extensions> { fn extensions(&self) -> Ref<'_, Extensions> {
self.head.extensions() self.req_data()
} }
fn extensions_mut(&self) -> RefMut<'_, Extensions> { fn extensions_mut(&self) -> RefMut<'_, Extensions> {
self.head.extensions_mut() self.req_data_mut()
} }
} }

View File

@ -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")]

View File

@ -1,5 +1,4 @@
use std::{ use std::{
cell::{Ref, RefMut},
convert::TryInto, convert::TryInto,
future::Future, future::Future,
pin::Pin, pin::Pin,
@ -7,21 +6,16 @@ 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, Response, ResponseHead, StatusCode,
}; };
use bytes::Bytes; 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 +27,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 +236,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 +265,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,22 +276,22 @@ impl HttpResponseBuilder {
self self
} }
/// Responses extensions // /// Responses extensions
#[inline] // #[inline]
pub fn extensions(&self) -> Ref<'_, Extensions> { // pub fn extensions(&self) -> Ref<'_, Extensions> {
self.res // self.res
.as_ref() // .as_ref()
.expect("cannot reuse response builder") // .expect("cannot reuse response builder")
.extensions() // .extensions()
} // }
/// Mutable reference to a the response's extensions // /// Mutable reference to a the response's extensions
pub fn extensions_mut(&mut self) -> RefMut<'_, Extensions> { // pub fn extensions_mut(&mut self) -> RefMut<'_, Extensions> {
self.res // self.res
.as_mut() // .as_mut()
.expect("cannot reuse response builder") // .expect("cannot reuse response builder")
.extensions_mut() // .extensions_mut()
} // }
/// Set a body and build the `HttpResponse`. /// Set a body and build the `HttpResponse`.
/// ///
@ -332,7 +326,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()),
}; };
@ -435,10 +429,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,

View File

@ -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,
@ -546,14 +547,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));