mirror of https://github.com/fafhrd91/actix-web
fix body types
This commit is contained in:
parent
d284875391
commit
e4e2cef2e1
|
@ -4,6 +4,7 @@
|
|||
### Added
|
||||
* Methods on `AcceptLanguage`: `ranked` and `preference`. [#2480]
|
||||
* `AcceptEncoding` typed header. [#2482]
|
||||
* `HttpResponse::map_into_boxed_body`. [#????]
|
||||
|
||||
### Changed
|
||||
* Rename `Accept::{mime_precedence => ranked}`. [#2480]
|
||||
|
@ -13,6 +14,7 @@
|
|||
* Accept wildcard `*` items in `AcceptLanguage`. [#2480]
|
||||
* Typed headers containing lists that require one or more items now enforce this minimum. [#2482]
|
||||
|
||||
[#????]: https://github.com/actix/actix-web/pull/????
|
||||
[#2480]: https://github.com/actix/actix-web/pull/2480
|
||||
[#2482]: https://github.com/actix/actix-web/pull/2482
|
||||
|
||||
|
|
|
@ -527,7 +527,10 @@ impl NamedFile {
|
|||
if precondition_failed {
|
||||
return resp.status(StatusCode::PRECONDITION_FAILED).finish();
|
||||
} else if not_modified {
|
||||
return resp.status(StatusCode::NOT_MODIFIED).body(AnyBody::None);
|
||||
return resp
|
||||
.status(StatusCode::NOT_MODIFIED)
|
||||
.body(AnyBody::<()>::None)
|
||||
.map_into_boxed_body();
|
||||
}
|
||||
|
||||
let reader = super::chunked::new_chunked_read(length, offset, self.file);
|
||||
|
|
|
@ -6,10 +6,14 @@
|
|||
* HTTP/2 handshake timeout can be configured with `ServiceConfig::client_timeout`. [#2483]
|
||||
* Rename `body::BoxBody::{from_body => new}`. [#????]
|
||||
* `Response::into_boxed_body`. [#????]
|
||||
* `Response::map_into_boxed_body`. [#????]
|
||||
* `body::EitherBody` enum. [#????]
|
||||
* `body::None` struct. [#????]
|
||||
* `impl Clone for ws::HandshakeError`. [#????]
|
||||
|
||||
### Changed
|
||||
* Rename `body::BoxBody::{from_body => new}`. [#????]
|
||||
* Body type for `Responses` returned from `Response::{new, ok, etc...}` is now `BoxBody`. [#????]
|
||||
|
||||
### Removed
|
||||
* Remove unnecessary `MessageBody` bound on types passed to `body::AnyBody::new`. [#????]
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
use std::io;
|
||||
|
||||
use actix_http::{body::AnyBody, http::HeaderValue, http::StatusCode};
|
||||
use actix_http::{Error, HttpService, Request, Response};
|
||||
use actix_http::{
|
||||
body::BoxBody, http::HeaderValue, http::StatusCode, Error, HttpService, Request,
|
||||
Response,
|
||||
};
|
||||
use actix_server::Server;
|
||||
use bytes::BytesMut;
|
||||
use futures_util::StreamExt as _;
|
||||
|
||||
async fn handle_request(mut req: Request) -> Result<Response<AnyBody>, Error> {
|
||||
async fn handle_request(mut req: Request) -> Result<Response<BoxBody>, Error> {
|
||||
let mut body = BytesMut::new();
|
||||
while let Some(item) = req.payload().next().await {
|
||||
body.extend_from_slice(&item?)
|
||||
|
@ -16,7 +18,8 @@ async fn handle_request(mut req: Request) -> Result<Response<AnyBody>, Error> {
|
|||
|
||||
Ok(Response::build(StatusCode::OK)
|
||||
.insert_header(("x-head", HeaderValue::from_static("dummy value!")))
|
||||
.body(body))
|
||||
.body(body)
|
||||
.map_into_boxed_body())
|
||||
}
|
||||
|
||||
#[actix_rt::main]
|
||||
|
|
|
@ -34,7 +34,7 @@ impl BoxBody {
|
|||
|
||||
impl fmt::Debug for BoxBody {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str("BoxAnyBody(dyn MessageBody)")
|
||||
f.write_str("BoxBody(dyn MessageBody)")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ impl MessageBody for Infallible {
|
|||
|
||||
fn poll_next(
|
||||
self: Pin<&mut Self>,
|
||||
_: &mut Context<'_>,
|
||||
_cx: &mut Context<'_>,
|
||||
) -> Poll<Option<Result<Bytes, Self::Error>>> {
|
||||
match *self {}
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ impl MessageBody for () {
|
|||
|
||||
fn poll_next(
|
||||
self: Pin<&mut Self>,
|
||||
_: &mut Context<'_>,
|
||||
_cx: &mut Context<'_>,
|
||||
) -> Poll<Option<Result<Bytes, Self::Error>>> {
|
||||
Poll::Ready(None)
|
||||
}
|
||||
|
@ -93,6 +93,27 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl MessageBody for &'static [u8] {
|
||||
type Error = Infallible;
|
||||
|
||||
fn size(&self) -> BodySize {
|
||||
BodySize::Sized(self.len() as u64)
|
||||
}
|
||||
|
||||
fn poll_next(
|
||||
self: Pin<&mut Self>,
|
||||
_cx: &mut Context<'_>,
|
||||
) -> Poll<Option<Result<Bytes, Self::Error>>> {
|
||||
if self.is_empty() {
|
||||
Poll::Ready(None)
|
||||
} else {
|
||||
let bytes = mem::take(self.get_mut());
|
||||
let bytes = Bytes::from_static(bytes);
|
||||
Poll::Ready(Some(Ok(bytes)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MessageBody for Bytes {
|
||||
type Error = Infallible;
|
||||
|
||||
|
@ -102,16 +123,36 @@ impl MessageBody for Bytes {
|
|||
|
||||
fn poll_next(
|
||||
self: Pin<&mut Self>,
|
||||
_: &mut Context<'_>,
|
||||
_cx: &mut Context<'_>,
|
||||
) -> Poll<Option<Result<Bytes, Self::Error>>> {
|
||||
if self.is_empty() {
|
||||
Poll::Ready(None)
|
||||
} else {
|
||||
Poll::Ready(Some(Ok(mem::take(self.get_mut()))))
|
||||
let bytes = mem::take(self.get_mut());
|
||||
Poll::Ready(Some(Ok(bytes)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// impl<'a> MessageBody for &'a Bytes {
|
||||
// type Error = Infallible;
|
||||
|
||||
// fn size(&self) -> BodySize {
|
||||
// BodySize::Sized(self.len() as u64)
|
||||
// }
|
||||
|
||||
// fn poll_next(
|
||||
// self: Pin<&mut Self>,
|
||||
// _cx: &mut Context<'_>,
|
||||
// ) -> Poll<Option<Result<Bytes, Self::Error>>> {
|
||||
// if self.is_empty() {
|
||||
// Poll::Ready(None)
|
||||
// } else {
|
||||
// Poll::Ready(Some(Ok(self.clone())))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
impl MessageBody for BytesMut {
|
||||
type Error = Infallible;
|
||||
|
||||
|
@ -121,7 +162,7 @@ impl MessageBody for BytesMut {
|
|||
|
||||
fn poll_next(
|
||||
self: Pin<&mut Self>,
|
||||
_: &mut Context<'_>,
|
||||
_cx: &mut Context<'_>,
|
||||
) -> Poll<Option<Result<Bytes, Self::Error>>> {
|
||||
if self.is_empty() {
|
||||
Poll::Ready(None)
|
||||
|
@ -131,6 +172,25 @@ impl MessageBody for BytesMut {
|
|||
}
|
||||
}
|
||||
|
||||
// impl<'a> MessageBody for &'a BytesMut {
|
||||
// type Error = Infallible;
|
||||
|
||||
// fn size(&self) -> BodySize {
|
||||
// BodySize::Sized(self.len() as u64)
|
||||
// }
|
||||
|
||||
// fn poll_next(
|
||||
// self: Pin<&mut Self>,
|
||||
// _cx: &mut Context<'_>,
|
||||
// ) -> Poll<Option<Result<Bytes, Self::Error>>> {
|
||||
// if self.is_empty() {
|
||||
// Poll::Ready(None)
|
||||
// } else {
|
||||
// Poll::Ready(Some(Ok(self.clone().freeze())))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
impl MessageBody for &'static str {
|
||||
type Error = Infallible;
|
||||
|
||||
|
@ -140,14 +200,14 @@ impl MessageBody for &'static str {
|
|||
|
||||
fn poll_next(
|
||||
self: Pin<&mut Self>,
|
||||
_: &mut Context<'_>,
|
||||
_cx: &mut Context<'_>,
|
||||
) -> Poll<Option<Result<Bytes, Self::Error>>> {
|
||||
if self.is_empty() {
|
||||
Poll::Ready(None)
|
||||
} else {
|
||||
Poll::Ready(Some(Ok(Bytes::from_static(
|
||||
mem::take(self.get_mut()).as_ref(),
|
||||
))))
|
||||
let string = mem::take(self.get_mut());
|
||||
let bytes = Bytes::from_static(string.as_bytes());
|
||||
Poll::Ready(Some(Ok(bytes)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -161,7 +221,7 @@ impl MessageBody for Vec<u8> {
|
|||
|
||||
fn poll_next(
|
||||
self: Pin<&mut Self>,
|
||||
_: &mut Context<'_>,
|
||||
_cx: &mut Context<'_>,
|
||||
) -> Poll<Option<Result<Bytes, Self::Error>>> {
|
||||
if self.is_empty() {
|
||||
Poll::Ready(None)
|
||||
|
@ -180,18 +240,74 @@ impl MessageBody for String {
|
|||
|
||||
fn poll_next(
|
||||
self: Pin<&mut Self>,
|
||||
_: &mut Context<'_>,
|
||||
_cx: &mut Context<'_>,
|
||||
) -> Poll<Option<Result<Bytes, Self::Error>>> {
|
||||
if self.is_empty() {
|
||||
Poll::Ready(None)
|
||||
} else {
|
||||
Poll::Ready(Some(Ok(Bytes::from(
|
||||
mem::take(self.get_mut()).into_bytes(),
|
||||
))))
|
||||
Poll::Ready(Some(Ok(Bytes::from(mem::take(self.get_mut())))))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// impl<'a> MessageBody for &'a String {
|
||||
// type Error = Infallible;
|
||||
|
||||
// fn size(&self) -> BodySize {
|
||||
// BodySize::Sized(self.len() as u64)
|
||||
// }
|
||||
|
||||
// fn poll_next(
|
||||
// self: Pin<&mut Self>,
|
||||
// _cx: &mut Context<'_>,
|
||||
// ) -> Poll<Option<Result<Bytes, Self::Error>>> {
|
||||
// if self.is_empty() {
|
||||
// Poll::Ready(None)
|
||||
// } else {
|
||||
// Poll::Ready(Some(Ok(Bytes::from(self.clone()))))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// impl MessageBody for Cow<'_, str> {
|
||||
// type Error = Infallible;
|
||||
|
||||
// fn size(&self) -> BodySize {
|
||||
// BodySize::Sized(self.len() as u64)
|
||||
// }
|
||||
|
||||
// fn poll_next(
|
||||
// self: Pin<&mut Self>,
|
||||
// cx: &mut Context<'_>,
|
||||
// ) -> Poll<Option<Result<Bytes, Self::Error>>> {
|
||||
// if self.is_empty() {
|
||||
// Poll::Ready(None)
|
||||
// } else {
|
||||
// let cow = Pin::into_inner(self);
|
||||
// let mut string = cow.clone().into_owned();
|
||||
// Pin::new(&mut string).poll_next(cx)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
impl MessageBody for bytestring::ByteString {
|
||||
type Error = Infallible;
|
||||
|
||||
fn size(&self) -> BodySize {
|
||||
BodySize::Sized(self.len() as u64)
|
||||
}
|
||||
|
||||
fn poll_next(
|
||||
self: Pin<&mut Self>,
|
||||
_cx: &mut Context<'_>,
|
||||
) -> Poll<Option<Result<Bytes, Self::Error>>> {
|
||||
let string = mem::take(self.get_mut());
|
||||
Poll::Ready(Some(Ok(string.into_bytes())))
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: ensure consistent impls of MessageBody that always terminate
|
||||
|
||||
pin_project! {
|
||||
pub(crate) struct MessageBodyMapErr<B, F> {
|
||||
#[pin]
|
||||
|
|
|
@ -6,6 +6,7 @@ mod body_stream;
|
|||
mod boxed;
|
||||
mod either;
|
||||
mod message_body;
|
||||
mod none;
|
||||
mod size;
|
||||
mod sized_stream;
|
||||
mod utils;
|
||||
|
@ -18,6 +19,7 @@ pub use self::boxed::BoxBody;
|
|||
pub use self::either::EitherBody;
|
||||
pub use self::message_body::MessageBody;
|
||||
pub(crate) use self::message_body::MessageBodyMapErr;
|
||||
pub use self::none::None;
|
||||
pub use self::size::BodySize;
|
||||
pub use self::sized_stream::SizedStream;
|
||||
pub use self::utils::to_bytes;
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
use std::{
|
||||
convert::Infallible,
|
||||
pin::Pin,
|
||||
task::{Context, Poll},
|
||||
};
|
||||
|
||||
use bytes::Bytes;
|
||||
|
||||
use super::{BodySize, MessageBody};
|
||||
|
||||
/// Body type for responses that forbid payloads.
|
||||
///
|
||||
/// Distinct from an empty response which would contain Content-Length header.
|
||||
///
|
||||
/// For an "empty" body, use `()` or `Bytes::new()`.
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
pub struct None(());
|
||||
|
||||
impl None {
|
||||
/// Constructs new "none" body.
|
||||
pub fn new() -> Self {
|
||||
None(())
|
||||
}
|
||||
}
|
||||
|
||||
impl MessageBody for None {
|
||||
type Error = Infallible;
|
||||
|
||||
fn size(&self) -> BodySize {
|
||||
BodySize::None
|
||||
}
|
||||
|
||||
fn poll_next(
|
||||
self: Pin<&mut Self>,
|
||||
_cx: &mut Context<'_>,
|
||||
) -> Poll<Option<Result<Bytes, Self::Error>>> {
|
||||
Poll::Ready(Option::None)
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@ use actix_codec::Framed;
|
|||
use actix_service::{IntoServiceFactory, Service, ServiceFactory};
|
||||
|
||||
use crate::{
|
||||
body::{AnyBody, MessageBody},
|
||||
body::{BoxBody, MessageBody},
|
||||
config::{KeepAlive, ServiceConfig},
|
||||
h1::{self, ExpectHandler, H1Service, UpgradeHandler},
|
||||
h2::H2Service,
|
||||
|
@ -31,7 +31,7 @@ pub struct HttpServiceBuilder<T, S, X = ExpectHandler, U = UpgradeHandler> {
|
|||
impl<T, S> HttpServiceBuilder<T, S, ExpectHandler, UpgradeHandler>
|
||||
where
|
||||
S: ServiceFactory<Request, Config = ()>,
|
||||
S::Error: Into<Response<AnyBody>> + 'static,
|
||||
S::Error: Into<Response<BoxBody>> + 'static,
|
||||
S::InitError: fmt::Debug,
|
||||
<S::Service as Service<Request>>::Future: 'static,
|
||||
{
|
||||
|
@ -54,11 +54,11 @@ where
|
|||
impl<T, S, X, U> HttpServiceBuilder<T, S, X, U>
|
||||
where
|
||||
S: ServiceFactory<Request, Config = ()>,
|
||||
S::Error: Into<Response<AnyBody>> + 'static,
|
||||
S::Error: Into<Response<BoxBody>> + 'static,
|
||||
S::InitError: fmt::Debug,
|
||||
<S::Service as Service<Request>>::Future: 'static,
|
||||
X: ServiceFactory<Request, Config = (), Response = Request>,
|
||||
X::Error: Into<Response<AnyBody>>,
|
||||
X::Error: Into<Response<BoxBody>>,
|
||||
X::InitError: fmt::Debug,
|
||||
U: ServiceFactory<(Request, Framed<T, h1::Codec>), Config = (), Response = ()>,
|
||||
U::Error: fmt::Display,
|
||||
|
@ -120,7 +120,7 @@ where
|
|||
where
|
||||
F: IntoServiceFactory<X1, Request>,
|
||||
X1: ServiceFactory<Request, Config = (), Response = Request>,
|
||||
X1::Error: Into<Response<AnyBody>>,
|
||||
X1::Error: Into<Response<BoxBody>>,
|
||||
X1::InitError: fmt::Debug,
|
||||
{
|
||||
HttpServiceBuilder {
|
||||
|
@ -178,7 +178,7 @@ where
|
|||
where
|
||||
B: MessageBody,
|
||||
F: IntoServiceFactory<S, Request>,
|
||||
S::Error: Into<Response<AnyBody>>,
|
||||
S::Error: Into<Response<BoxBody>>,
|
||||
S::InitError: fmt::Debug,
|
||||
S::Response: Into<Response<B>>,
|
||||
{
|
||||
|
@ -200,7 +200,7 @@ where
|
|||
pub fn h2<F, B>(self, service: F) -> H2Service<T, S, B>
|
||||
where
|
||||
F: IntoServiceFactory<S, Request>,
|
||||
S::Error: Into<Response<AnyBody>> + 'static,
|
||||
S::Error: Into<Response<BoxBody>> + 'static,
|
||||
S::InitError: fmt::Debug,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
|
||||
|
@ -223,7 +223,7 @@ where
|
|||
pub fn finish<F, B>(self, service: F) -> HttpService<T, S, B, X, U>
|
||||
where
|
||||
F: IntoServiceFactory<S, Request>,
|
||||
S::Error: Into<Response<AnyBody>> + 'static,
|
||||
S::Error: Into<Response<BoxBody>> + 'static,
|
||||
S::InitError: fmt::Debug,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ use actix_rt::task::{spawn_blocking, JoinHandle};
|
|||
use bytes::Bytes;
|
||||
use derive_more::Display;
|
||||
use futures_core::ready;
|
||||
use pin_project::pin_project;
|
||||
use pin_project_lite::pin_project;
|
||||
|
||||
#[cfg(feature = "compress-brotli")]
|
||||
use brotli2::write::BrotliEncoder;
|
||||
|
@ -23,8 +23,10 @@ use flate2::write::{GzEncoder, ZlibEncoder};
|
|||
#[cfg(feature = "compress-zstd")]
|
||||
use zstd::stream::write::Encoder as ZstdEncoder;
|
||||
|
||||
use super::Writer;
|
||||
use crate::{
|
||||
body::{AnyBody, BodySize, MessageBody},
|
||||
body::{BodySize, MessageBody},
|
||||
error::BlockingError,
|
||||
http::{
|
||||
header::{ContentEncoding, CONTENT_ENCODING},
|
||||
HeaderValue, StatusCode,
|
||||
|
@ -32,72 +34,79 @@ use crate::{
|
|||
ResponseHead,
|
||||
};
|
||||
|
||||
use super::Writer;
|
||||
use crate::error::BlockingError;
|
||||
|
||||
const MAX_CHUNK_SIZE_ENCODE_IN_PLACE: usize = 1024;
|
||||
|
||||
#[pin_project]
|
||||
pub struct Encoder<B> {
|
||||
eof: bool,
|
||||
#[pin]
|
||||
body: EncoderBody<B>,
|
||||
encoder: Option<ContentEncoder>,
|
||||
fut: Option<JoinHandle<Result<ContentEncoder, io::Error>>>,
|
||||
pin_project! {
|
||||
pub struct Encoder<B> {
|
||||
#[pin]
|
||||
body: EncoderBody<B>,
|
||||
encoder: Option<ContentEncoder>,
|
||||
fut: Option<JoinHandle<Result<ContentEncoder, io::Error>>>,
|
||||
eof: bool,
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: MessageBody> Encoder<B> {
|
||||
fn none() -> Self {
|
||||
Encoder {
|
||||
body: EncoderBody::None,
|
||||
encoder: None,
|
||||
fut: None,
|
||||
eof: true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn response(
|
||||
encoding: ContentEncoding,
|
||||
head: &mut ResponseHead,
|
||||
body: AnyBody<B>,
|
||||
) -> AnyBody<Encoder<B>> {
|
||||
body: B,
|
||||
) -> Self {
|
||||
let can_encode = !(head.headers().contains_key(&CONTENT_ENCODING)
|
||||
|| head.status == StatusCode::SWITCHING_PROTOCOLS
|
||||
|| head.status == StatusCode::NO_CONTENT
|
||||
|| encoding == ContentEncoding::Identity
|
||||
|| encoding == ContentEncoding::Auto);
|
||||
|
||||
let body = match body {
|
||||
AnyBody::None => return AnyBody::None,
|
||||
AnyBody::Bytes(buf) => {
|
||||
if can_encode {
|
||||
EncoderBody::Bytes(buf)
|
||||
} else {
|
||||
return AnyBody::Bytes(buf);
|
||||
}
|
||||
}
|
||||
AnyBody::Body(body) => EncoderBody::Stream(body),
|
||||
};
|
||||
match body.size() {
|
||||
// no need to compress an empty body
|
||||
BodySize::None => return Self::none(),
|
||||
|
||||
// we cannot assume that Sized is not a stream
|
||||
BodySize::Sized(_) | BodySize::Stream => {}
|
||||
}
|
||||
|
||||
if can_encode {
|
||||
// Modify response body only if encoder is not None
|
||||
// Modify response body only if encoder is set
|
||||
if let Some(enc) = ContentEncoder::encoder(encoding) {
|
||||
update_head(encoding, head);
|
||||
head.no_chunking(false);
|
||||
|
||||
return AnyBody::Body(Encoder {
|
||||
body,
|
||||
eof: false,
|
||||
fut: None,
|
||||
return Encoder {
|
||||
body: EncoderBody::Stream { body },
|
||||
encoder: Some(enc),
|
||||
});
|
||||
fut: None,
|
||||
eof: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
AnyBody::Body(Encoder {
|
||||
body,
|
||||
eof: false,
|
||||
fut: None,
|
||||
Encoder {
|
||||
body: EncoderBody::Stream { body },
|
||||
encoder: None,
|
||||
})
|
||||
fut: None,
|
||||
eof: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pin_project(project = EncoderBodyProj)]
|
||||
enum EncoderBody<B> {
|
||||
Bytes(Bytes),
|
||||
Stream(#[pin] B),
|
||||
pin_project! {
|
||||
#[project = EncoderBodyProj]
|
||||
enum EncoderBody<B> {
|
||||
None,
|
||||
// TODO: this variant is not used but RA can't see it because of macro wrapper
|
||||
Bytes { bytes: Bytes },
|
||||
Stream { #[pin] body: B },
|
||||
}
|
||||
}
|
||||
|
||||
impl<B> MessageBody for EncoderBody<B>
|
||||
|
@ -108,8 +117,9 @@ where
|
|||
|
||||
fn size(&self) -> BodySize {
|
||||
match self {
|
||||
EncoderBody::Bytes(ref b) => b.size(),
|
||||
EncoderBody::Stream(ref b) => b.size(),
|
||||
EncoderBody::None => BodySize::None,
|
||||
EncoderBody::Bytes { bytes } => bytes.size(),
|
||||
EncoderBody::Stream { body } => body.size(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -118,14 +128,19 @@ where
|
|||
cx: &mut Context<'_>,
|
||||
) -> Poll<Option<Result<Bytes, Self::Error>>> {
|
||||
match self.project() {
|
||||
EncoderBodyProj::Bytes(b) => {
|
||||
if b.is_empty() {
|
||||
EncoderBodyProj::None => Poll::Ready(None),
|
||||
|
||||
EncoderBodyProj::Bytes { bytes } => {
|
||||
if bytes.is_empty() {
|
||||
Poll::Ready(None)
|
||||
} else {
|
||||
Poll::Ready(Some(Ok(std::mem::take(b))))
|
||||
Poll::Ready(Some(Ok(std::mem::take(bytes))))
|
||||
}
|
||||
}
|
||||
EncoderBodyProj::Stream(b) => b.poll_next(cx).map_err(EncoderError::Body),
|
||||
|
||||
EncoderBodyProj::Stream { body } => {
|
||||
body.poll_next(cx).map_err(EncoderError::Body)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -197,6 +212,7 @@ where
|
|||
None => {
|
||||
if let Some(encoder) = this.encoder.take() {
|
||||
let chunk = encoder.finish().map_err(EncoderError::Io)?;
|
||||
|
||||
if chunk.is_empty() {
|
||||
return Poll::Ready(None);
|
||||
} else {
|
||||
|
@ -222,12 +238,15 @@ fn update_head(encoding: ContentEncoding, head: &mut ResponseHead) {
|
|||
enum ContentEncoder {
|
||||
#[cfg(feature = "compress-gzip")]
|
||||
Deflate(ZlibEncoder<Writer>),
|
||||
|
||||
#[cfg(feature = "compress-gzip")]
|
||||
Gzip(GzEncoder<Writer>),
|
||||
|
||||
#[cfg(feature = "compress-brotli")]
|
||||
Br(BrotliEncoder<Writer>),
|
||||
// We need explicit 'static lifetime here because ZstdEncoder need lifetime
|
||||
// argument, and we use `spawn_blocking` in `Encoder::poll_next` that require `FnOnce() -> R + Send + 'static`
|
||||
|
||||
// Wwe need explicit 'static lifetime here because ZstdEncoder needs a lifetime argument and we
|
||||
// use `spawn_blocking` in `Encoder::poll_next` that requires `FnOnce() -> R + Send + 'static`.
|
||||
#[cfg(feature = "compress-zstd")]
|
||||
Zstd(ZstdEncoder<'static, Writer>),
|
||||
}
|
||||
|
@ -240,20 +259,24 @@ impl ContentEncoder {
|
|||
Writer::new(),
|
||||
flate2::Compression::fast(),
|
||||
))),
|
||||
|
||||
#[cfg(feature = "compress-gzip")]
|
||||
ContentEncoding::Gzip => Some(ContentEncoder::Gzip(GzEncoder::new(
|
||||
Writer::new(),
|
||||
flate2::Compression::fast(),
|
||||
))),
|
||||
|
||||
#[cfg(feature = "compress-brotli")]
|
||||
ContentEncoding::Br => {
|
||||
Some(ContentEncoder::Br(BrotliEncoder::new(Writer::new(), 3)))
|
||||
}
|
||||
|
||||
#[cfg(feature = "compress-zstd")]
|
||||
ContentEncoding::Zstd => {
|
||||
let encoder = ZstdEncoder::new(Writer::new(), 3).ok()?;
|
||||
Some(ContentEncoder::Zstd(encoder))
|
||||
}
|
||||
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -263,10 +286,13 @@ impl ContentEncoder {
|
|||
match *self {
|
||||
#[cfg(feature = "compress-brotli")]
|
||||
ContentEncoder::Br(ref mut encoder) => encoder.get_mut().take(),
|
||||
|
||||
#[cfg(feature = "compress-gzip")]
|
||||
ContentEncoder::Deflate(ref mut encoder) => encoder.get_mut().take(),
|
||||
|
||||
#[cfg(feature = "compress-gzip")]
|
||||
ContentEncoder::Gzip(ref mut encoder) => encoder.get_mut().take(),
|
||||
|
||||
#[cfg(feature = "compress-zstd")]
|
||||
ContentEncoder::Zstd(ref mut encoder) => encoder.get_mut().take(),
|
||||
}
|
||||
|
@ -279,16 +305,19 @@ impl ContentEncoder {
|
|||
Ok(writer) => Ok(writer.buf.freeze()),
|
||||
Err(err) => Err(err),
|
||||
},
|
||||
|
||||
#[cfg(feature = "compress-gzip")]
|
||||
ContentEncoder::Gzip(encoder) => match encoder.finish() {
|
||||
Ok(writer) => Ok(writer.buf.freeze()),
|
||||
Err(err) => Err(err),
|
||||
},
|
||||
|
||||
#[cfg(feature = "compress-gzip")]
|
||||
ContentEncoder::Deflate(encoder) => match encoder.finish() {
|
||||
Ok(writer) => Ok(writer.buf.freeze()),
|
||||
Err(err) => Err(err),
|
||||
},
|
||||
|
||||
#[cfg(feature = "compress-zstd")]
|
||||
ContentEncoder::Zstd(encoder) => match encoder.finish() {
|
||||
Ok(writer) => Ok(writer.buf.freeze()),
|
||||
|
@ -307,6 +336,7 @@ impl ContentEncoder {
|
|||
Err(err)
|
||||
}
|
||||
},
|
||||
|
||||
#[cfg(feature = "compress-gzip")]
|
||||
ContentEncoder::Gzip(ref mut encoder) => match encoder.write_all(data) {
|
||||
Ok(_) => Ok(()),
|
||||
|
@ -315,6 +345,7 @@ impl ContentEncoder {
|
|||
Err(err)
|
||||
}
|
||||
},
|
||||
|
||||
#[cfg(feature = "compress-gzip")]
|
||||
ContentEncoder::Deflate(ref mut encoder) => match encoder.write_all(data) {
|
||||
Ok(_) => Ok(()),
|
||||
|
@ -323,6 +354,7 @@ impl ContentEncoder {
|
|||
Err(err)
|
||||
}
|
||||
},
|
||||
|
||||
#[cfg(feature = "compress-zstd")]
|
||||
ContentEncoder::Zstd(ref mut encoder) => match encoder.write_all(data) {
|
||||
Ok(_) => Ok(()),
|
||||
|
|
|
@ -5,7 +5,7 @@ use std::{error::Error as StdError, fmt, io, str::Utf8Error, string::FromUtf8Err
|
|||
use derive_more::{Display, Error, From};
|
||||
use http::{uri::InvalidUri, StatusCode};
|
||||
|
||||
use crate::{body::AnyBody, ws, Response};
|
||||
use crate::{body::BoxBody, ws, Response};
|
||||
|
||||
pub use http::Error as HttpError;
|
||||
|
||||
|
@ -66,14 +66,14 @@ impl Error {
|
|||
}
|
||||
}
|
||||
|
||||
impl<B> From<Error> for Response<AnyBody<B>> {
|
||||
impl From<Error> for Response<BoxBody> {
|
||||
fn from(err: Error) -> Self {
|
||||
let status_code = match err.inner.kind {
|
||||
Kind::Parse => StatusCode::BAD_REQUEST,
|
||||
_ => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
};
|
||||
|
||||
Response::new(status_code).set_body(AnyBody::from(err.to_string()))
|
||||
Response::new(status_code).set_body(BoxBody::new(err.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -240,7 +240,7 @@ impl From<ParseError> for Error {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<ParseError> for Response<AnyBody> {
|
||||
impl From<ParseError> for Response<BoxBody> {
|
||||
fn from(err: ParseError) -> Self {
|
||||
Error::from(err).into()
|
||||
}
|
||||
|
@ -337,7 +337,7 @@ pub enum DispatchError {
|
|||
/// Service error
|
||||
// FIXME: display and error type
|
||||
#[display(fmt = "Service Error")]
|
||||
Service(#[error(not(source))] Response<AnyBody>),
|
||||
Service(#[error(not(source))] Response<BoxBody>),
|
||||
|
||||
/// Body error
|
||||
// FIXME: display and error type
|
||||
|
@ -421,11 +421,11 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_into_response() {
|
||||
let resp: Response<AnyBody> = ParseError::Incomplete.into();
|
||||
let resp: Response<BoxBody> = ParseError::Incomplete.into();
|
||||
assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
|
||||
|
||||
let err: HttpError = StatusCode::from_u16(10000).err().unwrap().into();
|
||||
let resp: Response<AnyBody> = Error::new_http().with_cause(err).into();
|
||||
let resp: Response<BoxBody> = Error::new_http().with_cause(err).into();
|
||||
assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
|
@ -450,7 +450,7 @@ mod tests {
|
|||
fn test_error_http_response() {
|
||||
let orig = io::Error::new(io::ErrorKind::Other, "other");
|
||||
let err = Error::new_io().with_cause(orig);
|
||||
let resp: Response<AnyBody> = err.into();
|
||||
let resp: Response<BoxBody> = err.into();
|
||||
assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ use log::{error, trace};
|
|||
use pin_project::pin_project;
|
||||
|
||||
use crate::{
|
||||
body::{AnyBody, BodySize, MessageBody},
|
||||
body::{BodySize, BoxBody, MessageBody},
|
||||
config::ServiceConfig,
|
||||
error::{DispatchError, ParseError, PayloadError},
|
||||
service::HttpFlow,
|
||||
|
@ -51,13 +51,13 @@ bitflags! {
|
|||
pub struct Dispatcher<T, S, B, X, U>
|
||||
where
|
||||
S: Service<Request>,
|
||||
S::Error: Into<Response<AnyBody>>,
|
||||
S::Error: Into<Response<BoxBody>>,
|
||||
|
||||
B: MessageBody,
|
||||
B::Error: Into<Box<dyn StdError>>,
|
||||
|
||||
X: Service<Request, Response = Request>,
|
||||
X::Error: Into<Response<AnyBody>>,
|
||||
X::Error: Into<Response<BoxBody>>,
|
||||
|
||||
U: Service<(Request, Framed<T, Codec>), Response = ()>,
|
||||
U::Error: fmt::Display,
|
||||
|
@ -73,13 +73,13 @@ where
|
|||
enum DispatcherState<T, S, B, X, U>
|
||||
where
|
||||
S: Service<Request>,
|
||||
S::Error: Into<Response<AnyBody>>,
|
||||
S::Error: Into<Response<BoxBody>>,
|
||||
|
||||
B: MessageBody,
|
||||
B::Error: Into<Box<dyn StdError>>,
|
||||
|
||||
X: Service<Request, Response = Request>,
|
||||
X::Error: Into<Response<AnyBody>>,
|
||||
X::Error: Into<Response<BoxBody>>,
|
||||
|
||||
U: Service<(Request, Framed<T, Codec>), Response = ()>,
|
||||
U::Error: fmt::Display,
|
||||
|
@ -92,13 +92,13 @@ where
|
|||
struct InnerDispatcher<T, S, B, X, U>
|
||||
where
|
||||
S: Service<Request>,
|
||||
S::Error: Into<Response<AnyBody>>,
|
||||
S::Error: Into<Response<BoxBody>>,
|
||||
|
||||
B: MessageBody,
|
||||
B::Error: Into<Box<dyn StdError>>,
|
||||
|
||||
X: Service<Request, Response = Request>,
|
||||
X::Error: Into<Response<AnyBody>>,
|
||||
X::Error: Into<Response<BoxBody>>,
|
||||
|
||||
U: Service<(Request, Framed<T, Codec>), Response = ()>,
|
||||
U::Error: fmt::Display,
|
||||
|
@ -143,7 +143,7 @@ where
|
|||
ExpectCall(#[pin] X::Future),
|
||||
ServiceCall(#[pin] S::Future),
|
||||
SendPayload(#[pin] B),
|
||||
SendErrorPayload(#[pin] AnyBody),
|
||||
SendErrorPayload(#[pin] BoxBody),
|
||||
}
|
||||
|
||||
impl<S, B, X> State<S, B, X>
|
||||
|
@ -171,14 +171,14 @@ where
|
|||
T: AsyncRead + AsyncWrite + Unpin,
|
||||
|
||||
S: Service<Request>,
|
||||
S::Error: Into<Response<AnyBody>>,
|
||||
S::Error: Into<Response<BoxBody>>,
|
||||
S::Response: Into<Response<B>>,
|
||||
|
||||
B: MessageBody,
|
||||
B::Error: Into<Box<dyn StdError>>,
|
||||
|
||||
X: Service<Request, Response = Request>,
|
||||
X::Error: Into<Response<AnyBody>>,
|
||||
X::Error: Into<Response<BoxBody>>,
|
||||
|
||||
U: Service<(Request, Framed<T, Codec>), Response = ()>,
|
||||
U::Error: fmt::Display,
|
||||
|
@ -232,14 +232,14 @@ where
|
|||
T: AsyncRead + AsyncWrite + Unpin,
|
||||
|
||||
S: Service<Request>,
|
||||
S::Error: Into<Response<AnyBody>>,
|
||||
S::Error: Into<Response<BoxBody>>,
|
||||
S::Response: Into<Response<B>>,
|
||||
|
||||
B: MessageBody,
|
||||
B::Error: Into<Box<dyn StdError>>,
|
||||
|
||||
X: Service<Request, Response = Request>,
|
||||
X::Error: Into<Response<AnyBody>>,
|
||||
X::Error: Into<Response<BoxBody>>,
|
||||
|
||||
U: Service<(Request, Framed<T, Codec>), Response = ()>,
|
||||
U::Error: fmt::Display,
|
||||
|
@ -335,7 +335,7 @@ where
|
|||
fn send_error_response(
|
||||
mut self: Pin<&mut Self>,
|
||||
message: Response<()>,
|
||||
body: AnyBody,
|
||||
body: BoxBody,
|
||||
) -> Result<(), DispatchError> {
|
||||
let size = self.as_mut().send_response_inner(message, &body)?;
|
||||
let state = match size {
|
||||
|
@ -380,7 +380,7 @@ where
|
|||
// send_response would update InnerDispatcher state to SendPayload or
|
||||
// None(If response body is empty).
|
||||
// continue loop to poll it.
|
||||
self.as_mut().send_error_response(res, AnyBody::empty())?;
|
||||
self.as_mut().send_error_response(res, BoxBody::new(()))?;
|
||||
}
|
||||
|
||||
// return with upgrade request and poll it exclusively.
|
||||
|
@ -400,7 +400,7 @@ where
|
|||
|
||||
// send service call error as response
|
||||
Poll::Ready(Err(err)) => {
|
||||
let res: Response<AnyBody> = err.into();
|
||||
let res: Response<BoxBody> = err.into();
|
||||
let (res, body) = res.replace_body(());
|
||||
self.as_mut().send_error_response(res, body)?;
|
||||
}
|
||||
|
@ -497,7 +497,7 @@ where
|
|||
|
||||
// send expect error as response
|
||||
Poll::Ready(Err(err)) => {
|
||||
let res: Response<AnyBody> = err.into();
|
||||
let res: Response<BoxBody> = err.into();
|
||||
let (res, body) = res.replace_body(());
|
||||
self.as_mut().send_error_response(res, body)?;
|
||||
}
|
||||
|
@ -546,7 +546,7 @@ where
|
|||
// to notify the dispatcher a new state is set and the outer loop
|
||||
// should be continue.
|
||||
Poll::Ready(Err(err)) => {
|
||||
let res: Response<AnyBody> = err.into();
|
||||
let res: Response<BoxBody> = err.into();
|
||||
let (res, body) = res.replace_body(());
|
||||
return self.send_error_response(res, body);
|
||||
}
|
||||
|
@ -566,7 +566,7 @@ where
|
|||
Poll::Pending => Ok(()),
|
||||
// see the comment on ExpectCall state branch's Ready(Err(err)).
|
||||
Poll::Ready(Err(err)) => {
|
||||
let res: Response<AnyBody> = err.into();
|
||||
let res: Response<BoxBody> = err.into();
|
||||
let (res, body) = res.replace_body(());
|
||||
self.send_error_response(res, body)
|
||||
}
|
||||
|
@ -772,7 +772,7 @@ where
|
|||
trace!("Slow request timeout");
|
||||
let _ = self.as_mut().send_error_response(
|
||||
Response::with_body(StatusCode::REQUEST_TIMEOUT, ()),
|
||||
AnyBody::empty(),
|
||||
BoxBody::new(()),
|
||||
);
|
||||
this = self.project();
|
||||
this.flags.insert(Flags::STARTED | Flags::SHUTDOWN);
|
||||
|
@ -909,14 +909,14 @@ where
|
|||
T: AsyncRead + AsyncWrite + Unpin,
|
||||
|
||||
S: Service<Request>,
|
||||
S::Error: Into<Response<AnyBody>>,
|
||||
S::Error: Into<Response<BoxBody>>,
|
||||
S::Response: Into<Response<B>>,
|
||||
|
||||
B: MessageBody,
|
||||
B::Error: Into<Box<dyn StdError>>,
|
||||
|
||||
X: Service<Request, Response = Request>,
|
||||
X::Error: Into<Response<AnyBody>>,
|
||||
X::Error: Into<Response<BoxBody>>,
|
||||
|
||||
U: Service<(Request, Framed<T, Codec>), Response = ()>,
|
||||
U::Error: fmt::Display,
|
||||
|
@ -1044,6 +1044,7 @@ mod tests {
|
|||
|
||||
use super::*;
|
||||
use crate::{
|
||||
body::BoxBody,
|
||||
error::Error,
|
||||
h1::{ExpectHandler, UpgradeHandler},
|
||||
http::Method,
|
||||
|
@ -1067,17 +1068,17 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
fn ok_service() -> impl Service<Request, Response = Response<AnyBody>, Error = Error>
|
||||
fn ok_service() -> impl Service<Request, Response = Response<BoxBody>, Error = Error>
|
||||
{
|
||||
fn_service(|_req: Request| ready(Ok::<_, Error>(Response::ok())))
|
||||
}
|
||||
|
||||
fn echo_path_service(
|
||||
) -> impl Service<Request, Response = Response<AnyBody>, Error = Error> {
|
||||
) -> impl Service<Request, Response = Response<Bytes>, Error = Error> {
|
||||
fn_service(|req: Request| {
|
||||
let path = req.path().as_bytes();
|
||||
ready(Ok::<_, Error>(
|
||||
Response::ok().set_body(AnyBody::copy_from_slice(path)),
|
||||
Response::ok().set_body(Bytes::copy_from_slice(path)),
|
||||
))
|
||||
})
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ use actix_utils::future::ready;
|
|||
use futures_core::future::LocalBoxFuture;
|
||||
|
||||
use crate::{
|
||||
body::{AnyBody, MessageBody},
|
||||
body::{BoxBody, MessageBody},
|
||||
config::ServiceConfig,
|
||||
error::DispatchError,
|
||||
service::HttpServiceHandler,
|
||||
|
@ -38,7 +38,7 @@ pub struct H1Service<T, S, B, X = ExpectHandler, U = UpgradeHandler> {
|
|||
impl<T, S, B> H1Service<T, S, B>
|
||||
where
|
||||
S: ServiceFactory<Request, Config = ()>,
|
||||
S::Error: Into<Response<AnyBody>>,
|
||||
S::Error: Into<Response<BoxBody>>,
|
||||
S::InitError: fmt::Debug,
|
||||
S::Response: Into<Response<B>>,
|
||||
B: MessageBody,
|
||||
|
@ -63,7 +63,7 @@ impl<S, B, X, U> H1Service<TcpStream, S, B, X, U>
|
|||
where
|
||||
S: ServiceFactory<Request, Config = ()>,
|
||||
S::Future: 'static,
|
||||
S::Error: Into<Response<AnyBody>>,
|
||||
S::Error: Into<Response<BoxBody>>,
|
||||
S::InitError: fmt::Debug,
|
||||
S::Response: Into<Response<B>>,
|
||||
|
||||
|
@ -72,12 +72,12 @@ where
|
|||
|
||||
X: ServiceFactory<Request, Config = (), Response = Request>,
|
||||
X::Future: 'static,
|
||||
X::Error: Into<Response<AnyBody>>,
|
||||
X::Error: Into<Response<BoxBody>>,
|
||||
X::InitError: fmt::Debug,
|
||||
|
||||
U: ServiceFactory<(Request, Framed<TcpStream, Codec>), Config = (), Response = ()>,
|
||||
U::Future: 'static,
|
||||
U::Error: fmt::Display + Into<Response<AnyBody>>,
|
||||
U::Error: fmt::Display + Into<Response<BoxBody>>,
|
||||
U::InitError: fmt::Debug,
|
||||
{
|
||||
/// Create simple tcp stream service
|
||||
|
@ -114,7 +114,7 @@ mod openssl {
|
|||
where
|
||||
S: ServiceFactory<Request, Config = ()>,
|
||||
S::Future: 'static,
|
||||
S::Error: Into<Response<AnyBody>>,
|
||||
S::Error: Into<Response<BoxBody>>,
|
||||
S::InitError: fmt::Debug,
|
||||
S::Response: Into<Response<B>>,
|
||||
|
||||
|
@ -123,7 +123,7 @@ mod openssl {
|
|||
|
||||
X: ServiceFactory<Request, Config = (), Response = Request>,
|
||||
X::Future: 'static,
|
||||
X::Error: Into<Response<AnyBody>>,
|
||||
X::Error: Into<Response<BoxBody>>,
|
||||
X::InitError: fmt::Debug,
|
||||
|
||||
U: ServiceFactory<
|
||||
|
@ -132,7 +132,7 @@ mod openssl {
|
|||
Response = (),
|
||||
>,
|
||||
U::Future: 'static,
|
||||
U::Error: fmt::Display + Into<Response<AnyBody>>,
|
||||
U::Error: fmt::Display + Into<Response<BoxBody>>,
|
||||
U::InitError: fmt::Debug,
|
||||
{
|
||||
/// Create OpenSSL based service.
|
||||
|
@ -177,7 +177,7 @@ mod rustls {
|
|||
where
|
||||
S: ServiceFactory<Request, Config = ()>,
|
||||
S::Future: 'static,
|
||||
S::Error: Into<Response<AnyBody>>,
|
||||
S::Error: Into<Response<BoxBody>>,
|
||||
S::InitError: fmt::Debug,
|
||||
S::Response: Into<Response<B>>,
|
||||
|
||||
|
@ -186,7 +186,7 @@ mod rustls {
|
|||
|
||||
X: ServiceFactory<Request, Config = (), Response = Request>,
|
||||
X::Future: 'static,
|
||||
X::Error: Into<Response<AnyBody>>,
|
||||
X::Error: Into<Response<BoxBody>>,
|
||||
X::InitError: fmt::Debug,
|
||||
|
||||
U: ServiceFactory<
|
||||
|
@ -195,7 +195,7 @@ mod rustls {
|
|||
Response = (),
|
||||
>,
|
||||
U::Future: 'static,
|
||||
U::Error: fmt::Display + Into<Response<AnyBody>>,
|
||||
U::Error: fmt::Display + Into<Response<BoxBody>>,
|
||||
U::InitError: fmt::Debug,
|
||||
{
|
||||
/// Create Rustls based service.
|
||||
|
@ -226,7 +226,7 @@ mod rustls {
|
|||
impl<T, S, B, X, U> H1Service<T, S, B, X, U>
|
||||
where
|
||||
S: ServiceFactory<Request, Config = ()>,
|
||||
S::Error: Into<Response<AnyBody>>,
|
||||
S::Error: Into<Response<BoxBody>>,
|
||||
S::Response: Into<Response<B>>,
|
||||
S::InitError: fmt::Debug,
|
||||
B: MessageBody,
|
||||
|
@ -234,7 +234,7 @@ where
|
|||
pub fn expect<X1>(self, expect: X1) -> H1Service<T, S, B, X1, U>
|
||||
where
|
||||
X1: ServiceFactory<Request, Response = Request>,
|
||||
X1::Error: Into<Response<AnyBody>>,
|
||||
X1::Error: Into<Response<BoxBody>>,
|
||||
X1::InitError: fmt::Debug,
|
||||
{
|
||||
H1Service {
|
||||
|
@ -277,7 +277,7 @@ where
|
|||
|
||||
S: ServiceFactory<Request, Config = ()>,
|
||||
S::Future: 'static,
|
||||
S::Error: Into<Response<AnyBody>>,
|
||||
S::Error: Into<Response<BoxBody>>,
|
||||
S::Response: Into<Response<B>>,
|
||||
S::InitError: fmt::Debug,
|
||||
|
||||
|
@ -286,12 +286,12 @@ where
|
|||
|
||||
X: ServiceFactory<Request, Config = (), Response = Request>,
|
||||
X::Future: 'static,
|
||||
X::Error: Into<Response<AnyBody>>,
|
||||
X::Error: Into<Response<BoxBody>>,
|
||||
X::InitError: fmt::Debug,
|
||||
|
||||
U: ServiceFactory<(Request, Framed<T, Codec>), Config = (), Response = ()>,
|
||||
U::Future: 'static,
|
||||
U::Error: fmt::Display + Into<Response<AnyBody>>,
|
||||
U::Error: fmt::Display + Into<Response<BoxBody>>,
|
||||
U::InitError: fmt::Debug,
|
||||
{
|
||||
type Response = ();
|
||||
|
@ -347,17 +347,17 @@ where
|
|||
T: AsyncRead + AsyncWrite + Unpin,
|
||||
|
||||
S: Service<Request>,
|
||||
S::Error: Into<Response<AnyBody>>,
|
||||
S::Error: Into<Response<BoxBody>>,
|
||||
S::Response: Into<Response<B>>,
|
||||
|
||||
B: MessageBody,
|
||||
B::Error: Into<Box<dyn StdError>>,
|
||||
|
||||
X: Service<Request, Response = Request>,
|
||||
X::Error: Into<Response<AnyBody>>,
|
||||
X::Error: Into<Response<BoxBody>>,
|
||||
|
||||
U: Service<(Request, Framed<T, Codec>), Response = ()>,
|
||||
U::Error: fmt::Display + Into<Response<AnyBody>>,
|
||||
U::Error: fmt::Display + Into<Response<BoxBody>>,
|
||||
{
|
||||
type Response = ();
|
||||
type Error = DispatchError;
|
||||
|
|
|
@ -24,7 +24,7 @@ use log::{error, trace};
|
|||
use pin_project_lite::pin_project;
|
||||
|
||||
use crate::{
|
||||
body::{AnyBody, BodySize, MessageBody},
|
||||
body::{BodySize, BoxBody, MessageBody},
|
||||
config::ServiceConfig,
|
||||
service::HttpFlow,
|
||||
OnConnectData, Payload, Request, Response, ResponseHead,
|
||||
|
@ -92,7 +92,7 @@ where
|
|||
T: AsyncRead + AsyncWrite + Unpin,
|
||||
|
||||
S: Service<Request>,
|
||||
S::Error: Into<Response<AnyBody>>,
|
||||
S::Error: Into<Response<BoxBody>>,
|
||||
S::Future: 'static,
|
||||
S::Response: Into<Response<B>>,
|
||||
|
||||
|
@ -132,7 +132,7 @@ where
|
|||
let res = match fut.await {
|
||||
Ok(res) => handle_response(res.into(), tx, config).await,
|
||||
Err(err) => {
|
||||
let res: Response<AnyBody> = err.into();
|
||||
let res: Response<BoxBody> = err.into();
|
||||
handle_response(res, tx, config).await
|
||||
}
|
||||
};
|
||||
|
|
|
@ -19,7 +19,7 @@ use futures_core::{future::LocalBoxFuture, ready};
|
|||
use log::error;
|
||||
|
||||
use crate::{
|
||||
body::{AnyBody, MessageBody},
|
||||
body::{BoxBody, MessageBody},
|
||||
config::ServiceConfig,
|
||||
error::DispatchError,
|
||||
service::HttpFlow,
|
||||
|
@ -39,7 +39,7 @@ pub struct H2Service<T, S, B> {
|
|||
impl<T, S, B> H2Service<T, S, B>
|
||||
where
|
||||
S: ServiceFactory<Request, Config = ()>,
|
||||
S::Error: Into<Response<AnyBody>> + 'static,
|
||||
S::Error: Into<Response<BoxBody>> + 'static,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
<S::Service as Service<Request>>::Future: 'static,
|
||||
|
||||
|
@ -70,7 +70,7 @@ impl<S, B> H2Service<TcpStream, S, B>
|
|||
where
|
||||
S: ServiceFactory<Request, Config = ()>,
|
||||
S::Future: 'static,
|
||||
S::Error: Into<Response<AnyBody>> + 'static,
|
||||
S::Error: Into<Response<BoxBody>> + 'static,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
<S::Service as Service<Request>>::Future: 'static,
|
||||
|
||||
|
@ -114,7 +114,7 @@ mod openssl {
|
|||
where
|
||||
S: ServiceFactory<Request, Config = ()>,
|
||||
S::Future: 'static,
|
||||
S::Error: Into<Response<AnyBody>> + 'static,
|
||||
S::Error: Into<Response<BoxBody>> + 'static,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
<S::Service as Service<Request>>::Future: 'static,
|
||||
|
||||
|
@ -162,7 +162,7 @@ mod rustls {
|
|||
where
|
||||
S: ServiceFactory<Request, Config = ()>,
|
||||
S::Future: 'static,
|
||||
S::Error: Into<Response<AnyBody>> + 'static,
|
||||
S::Error: Into<Response<BoxBody>> + 'static,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
<S::Service as Service<Request>>::Future: 'static,
|
||||
|
||||
|
@ -204,7 +204,7 @@ where
|
|||
|
||||
S: ServiceFactory<Request, Config = ()>,
|
||||
S::Future: 'static,
|
||||
S::Error: Into<Response<AnyBody>> + 'static,
|
||||
S::Error: Into<Response<BoxBody>> + 'static,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
<S::Service as Service<Request>>::Future: 'static,
|
||||
|
||||
|
@ -244,7 +244,7 @@ where
|
|||
impl<T, S, B> H2ServiceHandler<T, S, B>
|
||||
where
|
||||
S: Service<Request>,
|
||||
S::Error: Into<Response<AnyBody>> + 'static,
|
||||
S::Error: Into<Response<BoxBody>> + 'static,
|
||||
S::Future: 'static,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
B: MessageBody + 'static,
|
||||
|
@ -267,7 +267,7 @@ impl<T, S, B> Service<(T, Option<net::SocketAddr>)> for H2ServiceHandler<T, S, B
|
|||
where
|
||||
T: AsyncRead + AsyncWrite + Unpin,
|
||||
S: Service<Request>,
|
||||
S::Error: Into<Response<AnyBody>> + 'static,
|
||||
S::Error: Into<Response<BoxBody>> + 'static,
|
||||
S::Future: 'static,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
B: MessageBody + 'static,
|
||||
|
@ -320,7 +320,7 @@ pub struct H2ServiceHandlerResponse<T, S, B>
|
|||
where
|
||||
T: AsyncRead + AsyncWrite + Unpin,
|
||||
S: Service<Request>,
|
||||
S::Error: Into<Response<AnyBody>> + 'static,
|
||||
S::Error: Into<Response<BoxBody>> + 'static,
|
||||
S::Future: 'static,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
B: MessageBody + 'static,
|
||||
|
@ -332,7 +332,7 @@ impl<T, S, B> Future for H2ServiceHandlerResponse<T, S, B>
|
|||
where
|
||||
T: AsyncRead + AsyncWrite + Unpin,
|
||||
S: Service<Request>,
|
||||
S::Error: Into<Response<AnyBody>> + 'static,
|
||||
S::Error: Into<Response<BoxBody>> + 'static,
|
||||
S::Future: 'static,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
B: MessageBody,
|
||||
|
|
|
@ -2,15 +2,17 @@
|
|||
|
||||
use std::{
|
||||
cell::{Ref, RefMut},
|
||||
error::Error as StdError,
|
||||
fmt, str,
|
||||
};
|
||||
|
||||
use bytes::{Bytes, BytesMut};
|
||||
use bytestring::ByteString;
|
||||
|
||||
use crate::{
|
||||
body::{AnyBody, MessageBody},
|
||||
error::Error,
|
||||
body::{BoxBody, MessageBody},
|
||||
extensions::Extensions,
|
||||
header::{self, IntoHeaderValue},
|
||||
http::{HeaderMap, StatusCode},
|
||||
message::{BoxedResponseHead, ResponseHead},
|
||||
ResponseBuilder,
|
||||
|
@ -22,13 +24,13 @@ pub struct Response<B> {
|
|||
pub(crate) body: B,
|
||||
}
|
||||
|
||||
impl Response<AnyBody> {
|
||||
impl Response<BoxBody> {
|
||||
/// Constructs a new response with default body.
|
||||
#[inline]
|
||||
pub fn new(status: StatusCode) -> Self {
|
||||
Response {
|
||||
head: BoxedResponseHead::new(status),
|
||||
body: AnyBody::empty(),
|
||||
body: BoxBody::new(()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -189,6 +191,14 @@ impl<B> Response<B> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn map_into_boxed_body(self) -> Response<BoxBody>
|
||||
where
|
||||
B: MessageBody + 'static,
|
||||
B::Error: Into<Box<dyn StdError + 'static>>,
|
||||
{
|
||||
self.map_body(|_, body| BoxBody::new(body))
|
||||
}
|
||||
|
||||
/// Returns body, consuming this response.
|
||||
pub fn into_body(self) -> B {
|
||||
self.body
|
||||
|
@ -223,81 +233,104 @@ impl<B: Default> Default for Response<B> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<I: Into<Response<AnyBody>>, E: Into<Error>> From<Result<I, E>>
|
||||
for Response<AnyBody>
|
||||
{
|
||||
fn from(res: Result<I, E>) -> Self {
|
||||
match res {
|
||||
Ok(val) => val.into(),
|
||||
Err(err) => err.into().into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: fix this impl
|
||||
// impl<B, I, E> From<Result<I, E>> for Response<BoxBody>
|
||||
// where
|
||||
// B: MessageBody + 'static,
|
||||
// B::Error: Into<Box<dyn StdError + 'static>>,
|
||||
// I: Into<Response<B>>,
|
||||
// E: Into<Error>,
|
||||
// {
|
||||
// fn from(res: Result<I, E>) -> Self {
|
||||
// match res {
|
||||
// Ok(val) => val.into(),
|
||||
// Err(err) => err.into().into(),
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
impl From<ResponseBuilder> for Response<AnyBody> {
|
||||
impl From<ResponseBuilder> for Response<BoxBody> {
|
||||
fn from(mut builder: ResponseBuilder) -> Self {
|
||||
builder.finish()
|
||||
builder.finish().map_into_boxed_body()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::convert::Infallible> for Response<AnyBody> {
|
||||
impl From<std::convert::Infallible> for Response<BoxBody> {
|
||||
fn from(val: std::convert::Infallible) -> Self {
|
||||
match val {}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'static str> for Response<AnyBody> {
|
||||
impl From<&'static str> for Response<&'static str> {
|
||||
fn from(val: &'static str) -> Self {
|
||||
Response::build(StatusCode::OK)
|
||||
.content_type(mime::TEXT_PLAIN_UTF_8)
|
||||
.body(val)
|
||||
let mut res = Response::with_body(StatusCode::OK, val);
|
||||
let mime = mime::TEXT_PLAIN_UTF_8.try_into_value().unwrap();
|
||||
res.headers_mut().insert(header::CONTENT_TYPE, mime);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'static [u8]> for Response<AnyBody> {
|
||||
impl From<&'static [u8]> for Response<&'static [u8]> {
|
||||
fn from(val: &'static [u8]) -> Self {
|
||||
Response::build(StatusCode::OK)
|
||||
.content_type(mime::APPLICATION_OCTET_STREAM)
|
||||
.body(val)
|
||||
let mut res = Response::with_body(StatusCode::OK, val);
|
||||
let mime = mime::APPLICATION_OCTET_STREAM.try_into_value().unwrap();
|
||||
res.headers_mut().insert(header::CONTENT_TYPE, mime);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for Response<AnyBody> {
|
||||
impl From<String> for Response<String> {
|
||||
fn from(val: String) -> Self {
|
||||
Response::build(StatusCode::OK)
|
||||
.content_type(mime::TEXT_PLAIN_UTF_8)
|
||||
.body(val)
|
||||
let mut res = Response::with_body(StatusCode::OK, val);
|
||||
let mime = mime::TEXT_PLAIN_UTF_8.try_into_value().unwrap();
|
||||
res.headers_mut().insert(header::CONTENT_TYPE, mime);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a String> for Response<AnyBody> {
|
||||
fn from(val: &'a String) -> Self {
|
||||
Response::build(StatusCode::OK)
|
||||
.content_type(mime::TEXT_PLAIN_UTF_8)
|
||||
.body(val)
|
||||
}
|
||||
}
|
||||
// TODO: was this is useful impl
|
||||
// impl<'a> From<&'a String> for Response<&'a String> {
|
||||
// fn from(val: &'a String) -> Self {
|
||||
// todo!()
|
||||
// }
|
||||
// }
|
||||
|
||||
impl From<Bytes> for Response<AnyBody> {
|
||||
impl From<Bytes> for Response<Bytes> {
|
||||
fn from(val: Bytes) -> Self {
|
||||
Response::build(StatusCode::OK)
|
||||
.content_type(mime::APPLICATION_OCTET_STREAM)
|
||||
.body(val)
|
||||
let mut res = Response::with_body(StatusCode::OK, val);
|
||||
let mime = mime::APPLICATION_OCTET_STREAM.try_into_value().unwrap();
|
||||
res.headers_mut().insert(header::CONTENT_TYPE, mime);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BytesMut> for Response<AnyBody> {
|
||||
impl From<BytesMut> for Response<BytesMut> {
|
||||
fn from(val: BytesMut) -> Self {
|
||||
Response::build(StatusCode::OK)
|
||||
.content_type(mime::APPLICATION_OCTET_STREAM)
|
||||
.body(val)
|
||||
let mut res = Response::with_body(StatusCode::OK, val);
|
||||
let mime = mime::APPLICATION_OCTET_STREAM.try_into_value().unwrap();
|
||||
res.headers_mut().insert(header::CONTENT_TYPE, mime);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ByteString> for Response<ByteString> {
|
||||
fn from(val: ByteString) -> Self {
|
||||
let mut res = Response::with_body(StatusCode::OK, val);
|
||||
let mime = mime::TEXT_PLAIN_UTF_8.try_into_value().unwrap();
|
||||
res.headers_mut().insert(header::CONTENT_TYPE, mime);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: impl into Response for ByteString
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::http::header::{HeaderValue, CONTENT_TYPE, COOKIE};
|
||||
use crate::{
|
||||
body::to_bytes,
|
||||
http::header::{HeaderValue, CONTENT_TYPE, COOKIE},
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test_debug() {
|
||||
|
@ -309,73 +342,73 @@ mod tests {
|
|||
assert!(dbg.contains("Response"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_into_response() {
|
||||
let resp: Response<AnyBody> = "test".into();
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
#[actix_rt::test]
|
||||
async fn test_into_response() {
|
||||
let res = Response::from("test");
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
assert_eq!(
|
||||
resp.headers().get(CONTENT_TYPE).unwrap(),
|
||||
res.headers().get(CONTENT_TYPE).unwrap(),
|
||||
HeaderValue::from_static("text/plain; charset=utf-8")
|
||||
);
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
assert_eq!(resp.body().get_ref(), b"test");
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
assert_eq!(to_bytes(res.into_body()).await.unwrap(), &b"test"[..]);
|
||||
|
||||
let resp: Response<AnyBody> = b"test".as_ref().into();
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
let res = Response::from(b"test".as_ref());
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
assert_eq!(
|
||||
resp.headers().get(CONTENT_TYPE).unwrap(),
|
||||
res.headers().get(CONTENT_TYPE).unwrap(),
|
||||
HeaderValue::from_static("application/octet-stream")
|
||||
);
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
assert_eq!(resp.body().get_ref(), b"test");
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
assert_eq!(to_bytes(res.into_body()).await.unwrap(), &b"test"[..]);
|
||||
|
||||
let resp: Response<AnyBody> = "test".to_owned().into();
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
let res = Response::from("test".to_owned());
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
assert_eq!(
|
||||
resp.headers().get(CONTENT_TYPE).unwrap(),
|
||||
res.headers().get(CONTENT_TYPE).unwrap(),
|
||||
HeaderValue::from_static("text/plain; charset=utf-8")
|
||||
);
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
assert_eq!(resp.body().get_ref(), b"test");
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
assert_eq!(to_bytes(res.into_body()).await.unwrap(), &b"test"[..]);
|
||||
|
||||
let resp: Response<AnyBody> = (&"test".to_owned()).into();
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
let res = Response::from("test".to_owned());
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
assert_eq!(
|
||||
resp.headers().get(CONTENT_TYPE).unwrap(),
|
||||
res.headers().get(CONTENT_TYPE).unwrap(),
|
||||
HeaderValue::from_static("text/plain; charset=utf-8")
|
||||
);
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
assert_eq!(resp.body().get_ref(), b"test");
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
assert_eq!(to_bytes(res.into_body()).await.unwrap(), &b"test"[..]);
|
||||
|
||||
let b = Bytes::from_static(b"test");
|
||||
let resp: Response<AnyBody> = b.into();
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
let res = Response::from(b);
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
assert_eq!(
|
||||
resp.headers().get(CONTENT_TYPE).unwrap(),
|
||||
res.headers().get(CONTENT_TYPE).unwrap(),
|
||||
HeaderValue::from_static("application/octet-stream")
|
||||
);
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
assert_eq!(resp.body().get_ref(), b"test");
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
assert_eq!(to_bytes(res.into_body()).await.unwrap(), &b"test"[..]);
|
||||
|
||||
let b = Bytes::from_static(b"test");
|
||||
let resp: Response<AnyBody> = b.into();
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
let res = Response::from(b);
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
assert_eq!(
|
||||
resp.headers().get(CONTENT_TYPE).unwrap(),
|
||||
res.headers().get(CONTENT_TYPE).unwrap(),
|
||||
HeaderValue::from_static("application/octet-stream")
|
||||
);
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
assert_eq!(resp.body().get_ref(), b"test");
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
assert_eq!(to_bytes(res.into_body()).await.unwrap(), &b"test"[..]);
|
||||
|
||||
let b = BytesMut::from("test");
|
||||
let resp: Response<AnyBody> = b.into();
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
let res = Response::from(b);
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
assert_eq!(
|
||||
resp.headers().get(CONTENT_TYPE).unwrap(),
|
||||
res.headers().get(CONTENT_TYPE).unwrap(),
|
||||
HeaderValue::from_static("application/octet-stream")
|
||||
);
|
||||
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
assert_eq!(resp.body().get_ref(), b"test");
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
assert_eq!(to_bytes(res.into_body()).await.unwrap(), &b"test"[..]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,11 +10,8 @@ use std::{
|
|||
task::{Context, Poll},
|
||||
};
|
||||
|
||||
use bytes::Bytes;
|
||||
use futures_core::Stream;
|
||||
|
||||
use crate::{
|
||||
body::{AnyBody, BodyStream},
|
||||
body::{BoxBody, EitherBody, MessageBody},
|
||||
error::{Error, HttpError},
|
||||
header::{self, IntoHeaderPair, IntoHeaderValue},
|
||||
message::{BoxedResponseHead, ConnectionType, ResponseHead},
|
||||
|
@ -235,10 +232,16 @@ impl ResponseBuilder {
|
|||
/// Generate response with a wrapped body.
|
||||
///
|
||||
/// This `ResponseBuilder` will be left in a useless state.
|
||||
#[inline]
|
||||
pub fn body<B: Into<AnyBody>>(&mut self, body: B) -> Response<AnyBody> {
|
||||
self.message_body(body.into())
|
||||
.unwrap_or_else(Response::from)
|
||||
pub fn body<B>(&mut self, body: B) -> Response<EitherBody<B>>
|
||||
where
|
||||
B: MessageBody + 'static,
|
||||
B::Error: Into<Box<dyn StdError + 'static>>,
|
||||
{
|
||||
match self.message_body(body) {
|
||||
Ok(res) => res.map_body(|_, body| EitherBody::left(body)),
|
||||
// TODO: add error path
|
||||
Err(err) => Response::from(err).map_body(|_, body| EitherBody::right(body)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate response with a body.
|
||||
|
@ -253,24 +256,12 @@ impl ResponseBuilder {
|
|||
Ok(Response { head, body })
|
||||
}
|
||||
|
||||
/// Generate response with a streaming body.
|
||||
///
|
||||
/// This `ResponseBuilder` will be left in a useless state.
|
||||
#[inline]
|
||||
pub fn streaming<S, E>(&mut self, stream: S) -> Response<AnyBody>
|
||||
where
|
||||
S: Stream<Item = Result<Bytes, E>> + 'static,
|
||||
E: Into<Box<dyn StdError>> + 'static,
|
||||
{
|
||||
self.body(AnyBody::new_boxed(BodyStream::new(stream)))
|
||||
}
|
||||
|
||||
/// Generate response with an empty body.
|
||||
///
|
||||
/// This `ResponseBuilder` will be left in a useless state.
|
||||
#[inline]
|
||||
pub fn finish(&mut self) -> Response<AnyBody> {
|
||||
self.body(AnyBody::empty())
|
||||
pub fn finish(&mut self) -> Response<EitherBody<()>> {
|
||||
self.body(())
|
||||
}
|
||||
|
||||
/// Create an owned `ResponseBuilder`, leaving the original in a useless state.
|
||||
|
@ -328,10 +319,10 @@ impl<'a> From<&'a ResponseHead> for ResponseBuilder {
|
|||
}
|
||||
|
||||
impl Future for ResponseBuilder {
|
||||
type Output = Result<Response<AnyBody>, Error>;
|
||||
type Output = Result<Response<BoxBody>, Error>;
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
Poll::Ready(Ok(self.finish()))
|
||||
Poll::Ready(Ok(self.finish().map_into_boxed_body()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -396,7 +387,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_into_builder() {
|
||||
let mut resp: Response<AnyBody> = "test".into();
|
||||
let mut resp: Response<_> = "test".into();
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
|
||||
resp.headers_mut().insert(
|
||||
|
|
|
@ -18,7 +18,7 @@ use futures_core::{future::LocalBoxFuture, ready};
|
|||
use pin_project::pin_project;
|
||||
|
||||
use crate::{
|
||||
body::{AnyBody, MessageBody},
|
||||
body::{BoxBody, MessageBody},
|
||||
builder::HttpServiceBuilder,
|
||||
config::{KeepAlive, ServiceConfig},
|
||||
error::DispatchError,
|
||||
|
@ -38,7 +38,7 @@ pub struct HttpService<T, S, B, X = h1::ExpectHandler, U = h1::UpgradeHandler> {
|
|||
impl<T, S, B> HttpService<T, S, B>
|
||||
where
|
||||
S: ServiceFactory<Request, Config = ()>,
|
||||
S::Error: Into<Response<AnyBody>> + 'static,
|
||||
S::Error: Into<Response<BoxBody>> + 'static,
|
||||
S::InitError: fmt::Debug,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
<S::Service as Service<Request>>::Future: 'static,
|
||||
|
@ -53,7 +53,7 @@ where
|
|||
impl<T, S, B> HttpService<T, S, B>
|
||||
where
|
||||
S: ServiceFactory<Request, Config = ()>,
|
||||
S::Error: Into<Response<AnyBody>> + 'static,
|
||||
S::Error: Into<Response<BoxBody>> + 'static,
|
||||
S::InitError: fmt::Debug,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
<S::Service as Service<Request>>::Future: 'static,
|
||||
|
@ -93,7 +93,7 @@ where
|
|||
impl<T, S, B, X, U> HttpService<T, S, B, X, U>
|
||||
where
|
||||
S: ServiceFactory<Request, Config = ()>,
|
||||
S::Error: Into<Response<AnyBody>> + 'static,
|
||||
S::Error: Into<Response<BoxBody>> + 'static,
|
||||
S::InitError: fmt::Debug,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
<S::Service as Service<Request>>::Future: 'static,
|
||||
|
@ -107,7 +107,7 @@ where
|
|||
pub fn expect<X1>(self, expect: X1) -> HttpService<T, S, B, X1, U>
|
||||
where
|
||||
X1: ServiceFactory<Request, Config = (), Response = Request>,
|
||||
X1::Error: Into<Response<AnyBody>>,
|
||||
X1::Error: Into<Response<BoxBody>>,
|
||||
X1::InitError: fmt::Debug,
|
||||
{
|
||||
HttpService {
|
||||
|
@ -151,7 +151,7 @@ impl<S, B, X, U> HttpService<TcpStream, S, B, X, U>
|
|||
where
|
||||
S: ServiceFactory<Request, Config = ()>,
|
||||
S::Future: 'static,
|
||||
S::Error: Into<Response<AnyBody>> + 'static,
|
||||
S::Error: Into<Response<BoxBody>> + 'static,
|
||||
S::InitError: fmt::Debug,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
<S::Service as Service<Request>>::Future: 'static,
|
||||
|
@ -161,7 +161,7 @@ where
|
|||
|
||||
X: ServiceFactory<Request, Config = (), Response = Request>,
|
||||
X::Future: 'static,
|
||||
X::Error: Into<Response<AnyBody>>,
|
||||
X::Error: Into<Response<BoxBody>>,
|
||||
X::InitError: fmt::Debug,
|
||||
|
||||
U: ServiceFactory<
|
||||
|
@ -170,7 +170,7 @@ where
|
|||
Response = (),
|
||||
>,
|
||||
U::Future: 'static,
|
||||
U::Error: fmt::Display + Into<Response<AnyBody>>,
|
||||
U::Error: fmt::Display + Into<Response<BoxBody>>,
|
||||
U::InitError: fmt::Debug,
|
||||
{
|
||||
/// Create simple tcp stream service
|
||||
|
@ -208,7 +208,7 @@ mod openssl {
|
|||
where
|
||||
S: ServiceFactory<Request, Config = ()>,
|
||||
S::Future: 'static,
|
||||
S::Error: Into<Response<AnyBody>> + 'static,
|
||||
S::Error: Into<Response<BoxBody>> + 'static,
|
||||
S::InitError: fmt::Debug,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
<S::Service as Service<Request>>::Future: 'static,
|
||||
|
@ -218,7 +218,7 @@ mod openssl {
|
|||
|
||||
X: ServiceFactory<Request, Config = (), Response = Request>,
|
||||
X::Future: 'static,
|
||||
X::Error: Into<Response<AnyBody>>,
|
||||
X::Error: Into<Response<BoxBody>>,
|
||||
X::InitError: fmt::Debug,
|
||||
|
||||
U: ServiceFactory<
|
||||
|
@ -227,7 +227,7 @@ mod openssl {
|
|||
Response = (),
|
||||
>,
|
||||
U::Future: 'static,
|
||||
U::Error: fmt::Display + Into<Response<AnyBody>>,
|
||||
U::Error: fmt::Display + Into<Response<BoxBody>>,
|
||||
U::InitError: fmt::Debug,
|
||||
{
|
||||
/// Create OpenSSL based service.
|
||||
|
@ -281,7 +281,7 @@ mod rustls {
|
|||
where
|
||||
S: ServiceFactory<Request, Config = ()>,
|
||||
S::Future: 'static,
|
||||
S::Error: Into<Response<AnyBody>> + 'static,
|
||||
S::Error: Into<Response<BoxBody>> + 'static,
|
||||
S::InitError: fmt::Debug,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
<S::Service as Service<Request>>::Future: 'static,
|
||||
|
@ -291,7 +291,7 @@ mod rustls {
|
|||
|
||||
X: ServiceFactory<Request, Config = (), Response = Request>,
|
||||
X::Future: 'static,
|
||||
X::Error: Into<Response<AnyBody>>,
|
||||
X::Error: Into<Response<BoxBody>>,
|
||||
X::InitError: fmt::Debug,
|
||||
|
||||
U: ServiceFactory<
|
||||
|
@ -300,7 +300,7 @@ mod rustls {
|
|||
Response = (),
|
||||
>,
|
||||
U::Future: 'static,
|
||||
U::Error: fmt::Display + Into<Response<AnyBody>>,
|
||||
U::Error: fmt::Display + Into<Response<BoxBody>>,
|
||||
U::InitError: fmt::Debug,
|
||||
{
|
||||
/// Create Rustls based service.
|
||||
|
@ -348,7 +348,7 @@ where
|
|||
|
||||
S: ServiceFactory<Request, Config = ()>,
|
||||
S::Future: 'static,
|
||||
S::Error: Into<Response<AnyBody>> + 'static,
|
||||
S::Error: Into<Response<BoxBody>> + 'static,
|
||||
S::InitError: fmt::Debug,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
<S::Service as Service<Request>>::Future: 'static,
|
||||
|
@ -358,12 +358,12 @@ where
|
|||
|
||||
X: ServiceFactory<Request, Config = (), Response = Request>,
|
||||
X::Future: 'static,
|
||||
X::Error: Into<Response<AnyBody>>,
|
||||
X::Error: Into<Response<BoxBody>>,
|
||||
X::InitError: fmt::Debug,
|
||||
|
||||
U: ServiceFactory<(Request, Framed<T, h1::Codec>), Config = (), Response = ()>,
|
||||
U::Future: 'static,
|
||||
U::Error: fmt::Display + Into<Response<AnyBody>>,
|
||||
U::Error: fmt::Display + Into<Response<BoxBody>>,
|
||||
U::InitError: fmt::Debug,
|
||||
{
|
||||
type Response = ();
|
||||
|
@ -426,11 +426,11 @@ where
|
|||
impl<T, S, B, X, U> HttpServiceHandler<T, S, B, X, U>
|
||||
where
|
||||
S: Service<Request>,
|
||||
S::Error: Into<Response<AnyBody>>,
|
||||
S::Error: Into<Response<BoxBody>>,
|
||||
X: Service<Request>,
|
||||
X::Error: Into<Response<AnyBody>>,
|
||||
X::Error: Into<Response<BoxBody>>,
|
||||
U: Service<(Request, Framed<T, h1::Codec>)>,
|
||||
U::Error: Into<Response<AnyBody>>,
|
||||
U::Error: Into<Response<BoxBody>>,
|
||||
{
|
||||
pub(super) fn new(
|
||||
cfg: ServiceConfig,
|
||||
|
@ -450,7 +450,7 @@ where
|
|||
pub(super) fn _poll_ready(
|
||||
&self,
|
||||
cx: &mut Context<'_>,
|
||||
) -> Poll<Result<(), Response<AnyBody>>> {
|
||||
) -> Poll<Result<(), Response<BoxBody>>> {
|
||||
ready!(self.flow.expect.poll_ready(cx).map_err(Into::into))?;
|
||||
|
||||
ready!(self.flow.service.poll_ready(cx).map_err(Into::into))?;
|
||||
|
@ -486,7 +486,7 @@ where
|
|||
T: AsyncRead + AsyncWrite + Unpin,
|
||||
|
||||
S: Service<Request>,
|
||||
S::Error: Into<Response<AnyBody>> + 'static,
|
||||
S::Error: Into<Response<BoxBody>> + 'static,
|
||||
S::Future: 'static,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
|
||||
|
@ -494,10 +494,10 @@ where
|
|||
B::Error: Into<Box<dyn StdError>>,
|
||||
|
||||
X: Service<Request, Response = Request>,
|
||||
X::Error: Into<Response<AnyBody>>,
|
||||
X::Error: Into<Response<BoxBody>>,
|
||||
|
||||
U: Service<(Request, Framed<T, h1::Codec>), Response = ()>,
|
||||
U::Error: fmt::Display + Into<Response<AnyBody>>,
|
||||
U::Error: fmt::Display + Into<Response<BoxBody>>,
|
||||
{
|
||||
type Response = ();
|
||||
type Error = DispatchError;
|
||||
|
@ -550,13 +550,13 @@ where
|
|||
|
||||
S: Service<Request>,
|
||||
S::Future: 'static,
|
||||
S::Error: Into<Response<AnyBody>>,
|
||||
S::Error: Into<Response<BoxBody>>,
|
||||
|
||||
B: MessageBody,
|
||||
B::Error: Into<Box<dyn StdError>>,
|
||||
|
||||
X: Service<Request, Response = Request>,
|
||||
X::Error: Into<Response<AnyBody>>,
|
||||
X::Error: Into<Response<BoxBody>>,
|
||||
|
||||
U: Service<(Request, Framed<T, h1::Codec>), Response = ()>,
|
||||
U::Error: fmt::Display,
|
||||
|
@ -580,7 +580,7 @@ where
|
|||
T: AsyncRead + AsyncWrite + Unpin,
|
||||
|
||||
S: Service<Request>,
|
||||
S::Error: Into<Response<AnyBody>> + 'static,
|
||||
S::Error: Into<Response<BoxBody>> + 'static,
|
||||
S::Future: 'static,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
|
||||
|
@ -588,7 +588,7 @@ where
|
|||
B::Error: Into<Box<dyn StdError>>,
|
||||
|
||||
X: Service<Request, Response = Request>,
|
||||
X::Error: Into<Response<AnyBody>>,
|
||||
X::Error: Into<Response<BoxBody>>,
|
||||
|
||||
U: Service<(Request, Framed<T, h1::Codec>), Response = ()>,
|
||||
U::Error: fmt::Display,
|
||||
|
@ -602,7 +602,7 @@ where
|
|||
T: AsyncRead + AsyncWrite + Unpin,
|
||||
|
||||
S: Service<Request>,
|
||||
S::Error: Into<Response<AnyBody>> + 'static,
|
||||
S::Error: Into<Response<BoxBody>> + 'static,
|
||||
S::Future: 'static,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
|
||||
|
@ -610,7 +610,7 @@ where
|
|||
B::Error: Into<Box<dyn StdError>>,
|
||||
|
||||
X: Service<Request, Response = Request>,
|
||||
X::Error: Into<Response<AnyBody>>,
|
||||
X::Error: Into<Response<BoxBody>>,
|
||||
|
||||
U: Service<(Request, Framed<T, h1::Codec>), Response = ()>,
|
||||
U::Error: fmt::Display,
|
||||
|
|
|
@ -72,7 +72,7 @@ mod inner {
|
|||
|
||||
use actix_codec::{AsyncRead, AsyncWrite, Decoder, Encoder, Framed};
|
||||
|
||||
use crate::{body::AnyBody, Response};
|
||||
use crate::{body::BoxBody, Response};
|
||||
|
||||
/// Framed transport errors
|
||||
pub enum DispatcherError<E, U, I>
|
||||
|
@ -136,7 +136,7 @@ mod inner {
|
|||
}
|
||||
}
|
||||
|
||||
impl<E, U, I> From<DispatcherError<E, U, I>> for Response<AnyBody>
|
||||
impl<E, U, I> From<DispatcherError<E, U, I>> for Response<BoxBody>
|
||||
where
|
||||
E: fmt::Debug + fmt::Display,
|
||||
U: Encoder<I> + Decoder,
|
||||
|
@ -144,7 +144,7 @@ mod inner {
|
|||
<U as Decoder>::Error: fmt::Debug,
|
||||
{
|
||||
fn from(err: DispatcherError<E, U, I>) -> Self {
|
||||
Response::internal_server_error().set_body(AnyBody::from(err.to_string()))
|
||||
Response::internal_server_error().set_body(BoxBody::new(err.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,9 +8,9 @@ use std::io;
|
|||
use derive_more::{Display, Error, From};
|
||||
use http::{header, Method, StatusCode};
|
||||
|
||||
use crate::body::BoxBody;
|
||||
use crate::{
|
||||
body::AnyBody, header::HeaderValue, message::RequestHead, response::Response,
|
||||
ResponseBuilder,
|
||||
header::HeaderValue, message::RequestHead, response::Response, ResponseBuilder,
|
||||
};
|
||||
|
||||
mod codec;
|
||||
|
@ -69,7 +69,7 @@ pub enum ProtocolError {
|
|||
}
|
||||
|
||||
/// WebSocket handshake errors
|
||||
#[derive(Debug, PartialEq, Display, Error)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Display, Error)]
|
||||
pub enum HandshakeError {
|
||||
/// Only get method is allowed.
|
||||
#[display(fmt = "Method not allowed.")]
|
||||
|
@ -96,8 +96,8 @@ pub enum HandshakeError {
|
|||
BadWebsocketKey,
|
||||
}
|
||||
|
||||
impl From<&HandshakeError> for Response<AnyBody> {
|
||||
fn from(err: &HandshakeError) -> Self {
|
||||
impl From<HandshakeError> for Response<BoxBody> {
|
||||
fn from(err: HandshakeError) -> Self {
|
||||
match err {
|
||||
HandshakeError::GetMethodRequired => {
|
||||
let mut res = Response::new(StatusCode::METHOD_NOT_ALLOWED);
|
||||
|
@ -139,9 +139,9 @@ impl From<&HandshakeError> for Response<AnyBody> {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<HandshakeError> for Response<AnyBody> {
|
||||
fn from(err: HandshakeError) -> Self {
|
||||
(&err).into()
|
||||
impl From<&HandshakeError> for Response<BoxBody> {
|
||||
fn from(err: &HandshakeError) -> Self {
|
||||
(*err).into()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -220,9 +220,10 @@ pub fn handshake_response(req: &RequestHead) -> ResponseBuilder {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{header, Method};
|
||||
|
||||
use super::*;
|
||||
use crate::{body::AnyBody, test::TestRequest};
|
||||
use http::{header, Method};
|
||||
use crate::test::TestRequest;
|
||||
|
||||
#[test]
|
||||
fn test_handshake() {
|
||||
|
@ -336,17 +337,17 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_ws_error_http_response() {
|
||||
let resp: Response<AnyBody> = HandshakeError::GetMethodRequired.into();
|
||||
let resp: Response<BoxBody> = HandshakeError::GetMethodRequired.into();
|
||||
assert_eq!(resp.status(), StatusCode::METHOD_NOT_ALLOWED);
|
||||
let resp: Response<AnyBody> = HandshakeError::NoWebsocketUpgrade.into();
|
||||
let resp: Response<BoxBody> = HandshakeError::NoWebsocketUpgrade.into();
|
||||
assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
|
||||
let resp: Response<AnyBody> = HandshakeError::NoConnectionUpgrade.into();
|
||||
let resp: Response<BoxBody> = HandshakeError::NoConnectionUpgrade.into();
|
||||
assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
|
||||
let resp: Response<AnyBody> = HandshakeError::NoVersionHeader.into();
|
||||
let resp: Response<BoxBody> = HandshakeError::NoVersionHeader.into();
|
||||
assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
|
||||
let resp: Response<AnyBody> = HandshakeError::UnsupportedVersion.into();
|
||||
let resp: Response<BoxBody> = HandshakeError::UnsupportedVersion.into();
|
||||
assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
|
||||
let resp: Response<AnyBody> = HandshakeError::BadWebsocketKey.into();
|
||||
let resp: Response<BoxBody> = HandshakeError::BadWebsocketKey.into();
|
||||
assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::convert::Infallible;
|
||||
|
||||
use actix_http::{
|
||||
body::AnyBody, http, http::StatusCode, HttpMessage, HttpService, Request, Response,
|
||||
body::BoxBody, http, http::StatusCode, HttpMessage, HttpService, Request, Response,
|
||||
};
|
||||
use actix_http_test::test_server;
|
||||
use actix_service::ServiceFactoryExt;
|
||||
|
@ -99,7 +99,7 @@ async fn test_with_query_parameter() {
|
|||
#[display(fmt = "expect failed")]
|
||||
struct ExpectFailed;
|
||||
|
||||
impl From<ExpectFailed> for Response<AnyBody> {
|
||||
impl From<ExpectFailed> for Response<BoxBody> {
|
||||
fn from(_: ExpectFailed) -> Self {
|
||||
Response::new(StatusCode::EXPECTATION_FAILED)
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ extern crate tls_openssl as openssl;
|
|||
use std::{convert::Infallible, io};
|
||||
|
||||
use actix_http::{
|
||||
body::{AnyBody, SizedStream},
|
||||
body::{BodyStream, BoxBody, SizedStream},
|
||||
error::PayloadError,
|
||||
http::{
|
||||
header::{self, HeaderValue},
|
||||
|
@ -348,7 +348,7 @@ async fn test_h2_body_chunked_explicit() {
|
|||
ok::<_, Infallible>(
|
||||
Response::build(StatusCode::OK)
|
||||
.insert_header((header::TRANSFER_ENCODING, "chunked"))
|
||||
.streaming(body),
|
||||
.body(BodyStream::new(body)),
|
||||
)
|
||||
})
|
||||
.openssl(tls_config())
|
||||
|
@ -399,9 +399,11 @@ async fn test_h2_response_http_error_handling() {
|
|||
#[display(fmt = "error")]
|
||||
struct BadRequest;
|
||||
|
||||
impl From<BadRequest> for Response<AnyBody> {
|
||||
impl From<BadRequest> for Response<BoxBody> {
|
||||
fn from(err: BadRequest) -> Self {
|
||||
Response::build(StatusCode::BAD_REQUEST).body(err.to_string())
|
||||
Response::build(StatusCode::BAD_REQUEST)
|
||||
.body(err.to_string())
|
||||
.map_into_boxed_body()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -409,7 +411,7 @@ impl From<BadRequest> for Response<AnyBody> {
|
|||
async fn test_h2_service_error() {
|
||||
let mut srv = test_server(move || {
|
||||
HttpService::build()
|
||||
.h2(|_| err::<Response<AnyBody>, _>(BadRequest))
|
||||
.h2(|_| err::<Response<BoxBody>, _>(BadRequest))
|
||||
.openssl(tls_config())
|
||||
.map_err(|_| ())
|
||||
})
|
||||
|
|
|
@ -10,7 +10,7 @@ use std::{
|
|||
};
|
||||
|
||||
use actix_http::{
|
||||
body::{AnyBody, SizedStream},
|
||||
body::{BodyStream, BoxBody, SizedStream},
|
||||
error::PayloadError,
|
||||
http::{
|
||||
header::{self, HeaderName, HeaderValue},
|
||||
|
@ -416,7 +416,7 @@ async fn test_h2_body_chunked_explicit() {
|
|||
ok::<_, Infallible>(
|
||||
Response::build(StatusCode::OK)
|
||||
.insert_header((header::TRANSFER_ENCODING, "chunked"))
|
||||
.streaming(body),
|
||||
.body(BodyStream::new(body)),
|
||||
)
|
||||
})
|
||||
.rustls(tls_config())
|
||||
|
@ -467,9 +467,9 @@ async fn test_h2_response_http_error_handling() {
|
|||
#[display(fmt = "error")]
|
||||
struct BadRequest;
|
||||
|
||||
impl From<BadRequest> for Response<AnyBody> {
|
||||
impl From<BadRequest> for Response<BoxBody> {
|
||||
fn from(_: BadRequest) -> Self {
|
||||
Response::bad_request().set_body(AnyBody::from("error"))
|
||||
Response::bad_request().set_body(BoxBody::new("error"))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -477,7 +477,7 @@ impl From<BadRequest> for Response<AnyBody> {
|
|||
async fn test_h2_service_error() {
|
||||
let mut srv = test_server(move || {
|
||||
HttpService::build()
|
||||
.h2(|_| err::<Response<AnyBody>, _>(BadRequest))
|
||||
.h2(|_| err::<Response<BoxBody>, _>(BadRequest))
|
||||
.rustls(tls_config())
|
||||
})
|
||||
.await;
|
||||
|
@ -494,7 +494,7 @@ async fn test_h2_service_error() {
|
|||
async fn test_h1_service_error() {
|
||||
let mut srv = test_server(move || {
|
||||
HttpService::build()
|
||||
.h1(|_| err::<Response<AnyBody>, _>(BadRequest))
|
||||
.h1(|_| err::<Response<BoxBody>, _>(BadRequest))
|
||||
.rustls(tls_config())
|
||||
})
|
||||
.await;
|
||||
|
|
|
@ -6,7 +6,7 @@ use std::{
|
|||
};
|
||||
|
||||
use actix_http::{
|
||||
body::{AnyBody, SizedStream},
|
||||
body::{self, BodyStream, BoxBody, SizedStream},
|
||||
header, http, Error, HttpMessage, HttpService, KeepAlive, Request, Response,
|
||||
StatusCode,
|
||||
};
|
||||
|
@ -69,7 +69,7 @@ async fn test_h1_2() {
|
|||
#[display(fmt = "expect failed")]
|
||||
struct ExpectFailed;
|
||||
|
||||
impl From<ExpectFailed> for Response<AnyBody> {
|
||||
impl From<ExpectFailed> for Response<BoxBody> {
|
||||
fn from(_: ExpectFailed) -> Self {
|
||||
Response::new(StatusCode::EXPECTATION_FAILED)
|
||||
}
|
||||
|
@ -622,7 +622,7 @@ async fn test_h1_body_chunked_explicit() {
|
|||
ok::<_, Infallible>(
|
||||
Response::build(StatusCode::OK)
|
||||
.insert_header((header::TRANSFER_ENCODING, "chunked"))
|
||||
.streaming(body),
|
||||
.body(BodyStream::new(body)),
|
||||
)
|
||||
})
|
||||
.tcp()
|
||||
|
@ -656,7 +656,9 @@ async fn test_h1_body_chunked_implicit() {
|
|||
HttpService::build()
|
||||
.h1(|_| {
|
||||
let body = once(ok::<_, Error>(Bytes::from_static(STR.as_ref())));
|
||||
ok::<_, Infallible>(Response::build(StatusCode::OK).streaming(body))
|
||||
ok::<_, Infallible>(
|
||||
Response::build(StatusCode::OK).body(BodyStream::new(body)),
|
||||
)
|
||||
})
|
||||
.tcp()
|
||||
})
|
||||
|
@ -714,9 +716,9 @@ async fn test_h1_response_http_error_handling() {
|
|||
#[display(fmt = "error")]
|
||||
struct BadRequest;
|
||||
|
||||
impl From<BadRequest> for Response<AnyBody> {
|
||||
impl From<BadRequest> for Response<BoxBody> {
|
||||
fn from(_: BadRequest) -> Self {
|
||||
Response::bad_request().set_body(AnyBody::from("error"))
|
||||
Response::bad_request().set_body(BoxBody::new("error"))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -724,7 +726,7 @@ impl From<BadRequest> for Response<AnyBody> {
|
|||
async fn test_h1_service_error() {
|
||||
let mut srv = test_server(|| {
|
||||
HttpService::build()
|
||||
.h1(|_| err::<Response<AnyBody>, _>(BadRequest))
|
||||
.h1(|_| err::<Response<()>, _>(BadRequest))
|
||||
.tcp()
|
||||
})
|
||||
.await;
|
||||
|
@ -773,36 +775,35 @@ async fn test_not_modified_spec_h1() {
|
|||
let mut srv = test_server(|| {
|
||||
HttpService::build()
|
||||
.h1(|req: Request| {
|
||||
let res: Response<AnyBody> = match req.path() {
|
||||
let res: Response<BoxBody> = match req.path() {
|
||||
// with no content-length
|
||||
"/none" => {
|
||||
Response::with_body(StatusCode::NOT_MODIFIED, AnyBody::None)
|
||||
Response::with_body(StatusCode::NOT_MODIFIED, body::None::new())
|
||||
.map_into_boxed_body()
|
||||
}
|
||||
|
||||
// with no content-length
|
||||
"/body" => Response::with_body(
|
||||
StatusCode::NOT_MODIFIED,
|
||||
AnyBody::from("1234"),
|
||||
),
|
||||
"/body" => Response::with_body(StatusCode::NOT_MODIFIED, "1234")
|
||||
.map_into_boxed_body(),
|
||||
|
||||
// with manual content-length header and specific None body
|
||||
"/cl-none" => {
|
||||
let mut res =
|
||||
Response::with_body(StatusCode::NOT_MODIFIED, AnyBody::None);
|
||||
let mut res = Response::with_body(
|
||||
StatusCode::NOT_MODIFIED,
|
||||
body::None::new(),
|
||||
);
|
||||
res.headers_mut()
|
||||
.insert(CL.clone(), header::HeaderValue::from_static("24"));
|
||||
res
|
||||
res.map_into_boxed_body()
|
||||
}
|
||||
|
||||
// with manual content-length header and ignore-able body
|
||||
"/cl-body" => {
|
||||
let mut res = Response::with_body(
|
||||
StatusCode::NOT_MODIFIED,
|
||||
AnyBody::from("1234"),
|
||||
);
|
||||
let mut res =
|
||||
Response::with_body(StatusCode::NOT_MODIFIED, "1234");
|
||||
res.headers_mut()
|
||||
.insert(CL.clone(), header::HeaderValue::from_static("4"));
|
||||
res
|
||||
res.map_into_boxed_body()
|
||||
}
|
||||
|
||||
_ => panic!("unknown route"),
|
||||
|
|
|
@ -6,7 +6,7 @@ use std::{
|
|||
|
||||
use actix_codec::{AsyncRead, AsyncWrite, Framed};
|
||||
use actix_http::{
|
||||
body::{AnyBody, BodySize},
|
||||
body::{BodySize, BoxBody},
|
||||
h1,
|
||||
ws::{self, CloseCode, Frame, Item, Message},
|
||||
Error, HttpService, Request, Response,
|
||||
|
@ -50,14 +50,14 @@ enum WsServiceError {
|
|||
Dispatcher,
|
||||
}
|
||||
|
||||
impl From<WsServiceError> for Response<AnyBody> {
|
||||
impl From<WsServiceError> for Response<BoxBody> {
|
||||
fn from(err: WsServiceError) -> Self {
|
||||
match err {
|
||||
WsServiceError::Http(err) => err.into(),
|
||||
WsServiceError::Ws(err) => err.into(),
|
||||
WsServiceError::Io(_err) => unreachable!(),
|
||||
WsServiceError::Dispatcher => Response::internal_server_error()
|
||||
.set_body(AnyBody::from(format!("{}", err))),
|
||||
.set_body(BoxBody::new(format!("{}", err))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use std::future::Future;
|
|||
use std::marker::PhantomData;
|
||||
use std::rc::Rc;
|
||||
|
||||
use actix_http::body::{AnyBody, MessageBody};
|
||||
use actix_http::body::{BoxBody, MessageBody};
|
||||
use actix_http::{Extensions, Request};
|
||||
use actix_service::boxed::{self, BoxServiceFactory};
|
||||
use actix_service::{
|
||||
|
@ -39,7 +39,7 @@ pub struct App<T, B> {
|
|||
_phantom: PhantomData<B>,
|
||||
}
|
||||
|
||||
impl App<AppEntry, AnyBody> {
|
||||
impl App<AppEntry, BoxBody> {
|
||||
/// Create application builder. Application can be configured with a builder-like pattern.
|
||||
#[allow(clippy::new_without_default)]
|
||||
pub fn new() -> Self {
|
||||
|
|
12
src/dev.rs
12
src/dev.rs
|
@ -1,7 +1,7 @@
|
|||
//! Lower-level types and re-exports.
|
||||
//!
|
||||
//! Most users will not have to interact with the types in this module, but it is useful for those
|
||||
//! writing extractors, middleware and libraries, or interacting with the service API directly.
|
||||
//! writing extractors, middleware, libraries, or interacting with the service API directly.
|
||||
|
||||
pub use crate::config::{AppConfig, AppService};
|
||||
#[doc(hidden)]
|
||||
|
@ -17,8 +17,6 @@ pub use crate::types::readlines::Readlines;
|
|||
#[allow(deprecated)]
|
||||
pub use actix_http::body::{AnyBody, Body, BodySize, MessageBody, SizedStream};
|
||||
|
||||
#[cfg(feature = "__compress")]
|
||||
pub use actix_http::encoding::Decoder as Decompress;
|
||||
pub use actix_http::{Extensions, Payload, PayloadStream, RequestHead, Response, ResponseHead};
|
||||
pub use actix_router::{Path, ResourceDef, ResourcePath, Url};
|
||||
pub use actix_server::{Server, ServerHandle};
|
||||
|
@ -26,8 +24,10 @@ pub use actix_service::{
|
|||
always_ready, fn_factory, fn_service, forward_ready, Service, ServiceFactory, Transform,
|
||||
};
|
||||
|
||||
#[cfg(feature = "__compress")]
|
||||
pub use actix_http::encoding::Decoder as Decompress;
|
||||
|
||||
use crate::http::header::ContentEncoding;
|
||||
use actix_http::ResponseBuilder;
|
||||
|
||||
use actix_router::Patterns;
|
||||
|
||||
|
@ -62,7 +62,7 @@ pub trait BodyEncoding {
|
|||
fn encoding(&mut self, encoding: ContentEncoding) -> &mut Self;
|
||||
}
|
||||
|
||||
impl BodyEncoding for ResponseBuilder {
|
||||
impl BodyEncoding for actix_http::ResponseBuilder {
|
||||
fn get_encoding(&self) -> Option<ContentEncoding> {
|
||||
self.extensions().get::<Enc>().map(|enc| enc.0)
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ impl BodyEncoding for ResponseBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
impl<B> BodyEncoding for Response<B> {
|
||||
impl<B> BodyEncoding for actix_http::Response<B> {
|
||||
fn get_encoding(&self) -> Option<ContentEncoding> {
|
||||
self.extensions().get::<Enc>().map(|enc| enc.0)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::{error::Error as StdError, fmt};
|
||||
|
||||
use actix_http::{body::AnyBody, Response};
|
||||
use actix_http::{body::BoxBody, Response};
|
||||
|
||||
use crate::{HttpResponse, ResponseError};
|
||||
|
||||
|
@ -69,8 +69,8 @@ impl<T: ResponseError + 'static> From<T> for Error {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<Error> for Response<AnyBody> {
|
||||
fn from(err: Error) -> Response<AnyBody> {
|
||||
impl From<Error> for Response<BoxBody> {
|
||||
fn from(err: Error) -> Response<BoxBody> {
|
||||
err.error_response().into()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
use std::{cell::RefCell, fmt, io::Write as _};
|
||||
|
||||
use actix_http::{body::AnyBody, header, StatusCode};
|
||||
use actix_http::{
|
||||
body::BoxBody,
|
||||
header::{self, IntoHeaderValue as _},
|
||||
StatusCode,
|
||||
};
|
||||
use bytes::{BufMut as _, BytesMut};
|
||||
|
||||
use crate::{Error, HttpRequest, HttpResponse, Responder, ResponseError};
|
||||
|
@ -84,11 +88,10 @@ where
|
|||
let mut buf = BytesMut::new().writer();
|
||||
let _ = write!(buf, "{}", self);
|
||||
|
||||
res.headers_mut().insert(
|
||||
header::CONTENT_TYPE,
|
||||
header::HeaderValue::from_static("text/plain; charset=utf-8"),
|
||||
);
|
||||
res.set_body(AnyBody::from(buf.into_inner()))
|
||||
let mime = mime::TEXT_PLAIN_UTF_8.try_into_value().unwrap();
|
||||
res.headers_mut().insert(header::CONTENT_TYPE, mime);
|
||||
|
||||
res.set_body(BoxBody::new(buf.into_inner()))
|
||||
}
|
||||
|
||||
InternalErrorType::Response(ref resp) => {
|
||||
|
|
|
@ -6,11 +6,17 @@ use std::{
|
|||
io::{self, Write as _},
|
||||
};
|
||||
|
||||
use actix_http::{body::AnyBody, header, Response, StatusCode};
|
||||
use actix_http::{
|
||||
body::BoxBody,
|
||||
header::{self, IntoHeaderValue},
|
||||
Response, StatusCode,
|
||||
};
|
||||
use bytes::BytesMut;
|
||||
|
||||
use crate::error::{downcast_dyn, downcast_get_type_id};
|
||||
use crate::{helpers, HttpResponse};
|
||||
use crate::{
|
||||
error::{downcast_dyn, downcast_get_type_id},
|
||||
helpers, HttpResponse,
|
||||
};
|
||||
|
||||
/// Errors that can generate responses.
|
||||
// TODO: add std::error::Error bound when replacement for Box<dyn Error> is found
|
||||
|
@ -27,18 +33,16 @@ pub trait ResponseError: fmt::Debug + fmt::Display {
|
|||
///
|
||||
/// By default, the generated response uses a 500 Internal Server Error status code, a
|
||||
/// `Content-Type` of `text/plain`, and the body is set to `Self`'s `Display` impl.
|
||||
fn error_response(&self) -> HttpResponse {
|
||||
fn error_response(&self) -> HttpResponse<BoxBody> {
|
||||
let mut res = HttpResponse::new(self.status_code());
|
||||
|
||||
let mut buf = BytesMut::new();
|
||||
let _ = write!(helpers::MutWriter(&mut buf), "{}", self);
|
||||
|
||||
res.headers_mut().insert(
|
||||
header::CONTENT_TYPE,
|
||||
header::HeaderValue::from_static("text/plain; charset=utf-8"),
|
||||
);
|
||||
let mime = mime::TEXT_PLAIN_UTF_8.try_into_value().unwrap();
|
||||
res.headers_mut().insert(header::CONTENT_TYPE, mime);
|
||||
|
||||
res.set_body(AnyBody::from(buf))
|
||||
res.set_body(BoxBody::new(buf))
|
||||
}
|
||||
|
||||
downcast_get_type_id!();
|
||||
|
@ -86,8 +90,8 @@ impl ResponseError for actix_http::Error {
|
|||
StatusCode::INTERNAL_SERVER_ERROR
|
||||
}
|
||||
|
||||
fn error_response(&self) -> HttpResponse {
|
||||
HttpResponse::new(self.status_code()).set_body(self.to_string().into())
|
||||
fn error_response(&self) -> HttpResponse<BoxBody> {
|
||||
HttpResponse::with_body(self.status_code(), self.to_string()).map_into_boxed_body()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -123,8 +127,8 @@ impl ResponseError for actix_http::error::ContentTypeError {
|
|||
}
|
||||
|
||||
impl ResponseError for actix_http::ws::HandshakeError {
|
||||
fn error_response(&self) -> HttpResponse {
|
||||
Response::from(self).into()
|
||||
fn error_response(&self) -> HttpResponse<BoxBody> {
|
||||
Response::from(self).map_into_boxed_body().into()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ use std::{
|
|||
task::{Context, Poll},
|
||||
};
|
||||
|
||||
use actix_http::body::{AnyBody, MessageBody};
|
||||
use actix_http::body::MessageBody;
|
||||
use actix_service::{Service, Transform};
|
||||
use futures_core::{future::LocalBoxFuture, ready};
|
||||
use pin_project_lite::pin_project;
|
||||
|
@ -126,7 +126,7 @@ where
|
|||
B::Error: Into<Box<dyn StdError + 'static>>,
|
||||
{
|
||||
fn map_body(self) -> ServiceResponse {
|
||||
self.map_body(|_, body| AnyBody::new_boxed(body))
|
||||
self.map_into_boxed_body()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,14 +10,13 @@ use std::{
|
|||
};
|
||||
|
||||
use actix_http::{
|
||||
body::{AnyBody, MessageBody},
|
||||
body::{BoxBody, EitherBody, MessageBody},
|
||||
encoding::Encoder,
|
||||
http::header::{ContentEncoding, ACCEPT_ENCODING},
|
||||
StatusCode,
|
||||
};
|
||||
use actix_service::{Service, Transform};
|
||||
use actix_utils::future::{ok, Either, Ready};
|
||||
use bytes::Bytes;
|
||||
use futures_core::ready;
|
||||
use once_cell::sync::Lazy;
|
||||
use pin_project_lite::pin_project;
|
||||
|
@ -62,7 +61,7 @@ where
|
|||
B: MessageBody,
|
||||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
{
|
||||
type Response = ServiceResponse<AnyBody<Encoder<B>>>;
|
||||
type Response = ServiceResponse<EitherBody<Encoder<B>>>;
|
||||
type Error = Error;
|
||||
type Transform = CompressMiddleware<S>;
|
||||
type InitError = ();
|
||||
|
@ -112,7 +111,7 @@ where
|
|||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
B: MessageBody,
|
||||
{
|
||||
type Response = ServiceResponse<AnyBody<Encoder<B>>>;
|
||||
type Response = ServiceResponse<EitherBody<Encoder<B>>>;
|
||||
type Error = Error;
|
||||
type Future = Either<CompressResponse<S, B>, Ready<Result<Self::Response, Self::Error>>>;
|
||||
|
||||
|
@ -144,19 +143,14 @@ where
|
|||
|
||||
// There is an HTTP header but we cannot match what client as asked for
|
||||
Some(Err(_)) => {
|
||||
let res = HttpResponse::new(StatusCode::NOT_ACCEPTABLE);
|
||||
let res = HttpResponse::with_body(
|
||||
StatusCode::NOT_ACCEPTABLE,
|
||||
SUPPORTED_ALGORITHM_NAMES.clone(),
|
||||
);
|
||||
|
||||
let res: HttpResponse<AnyBody<Encoder<B>>> = res.map_body(move |head, _| {
|
||||
let body_bytes = Bytes::from(SUPPORTED_ALGORITHM_NAMES.as_bytes());
|
||||
|
||||
Encoder::response(
|
||||
ContentEncoding::Identity,
|
||||
head,
|
||||
AnyBody::Bytes(body_bytes),
|
||||
)
|
||||
});
|
||||
|
||||
Either::right(ok(req.into_response(res)))
|
||||
Either::right(ok(req
|
||||
.into_response(res)
|
||||
.map_body(|_, body| EitherBody::right(BoxBody::new(body)))))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -179,7 +173,7 @@ where
|
|||
B: MessageBody,
|
||||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
{
|
||||
type Output = Result<ServiceResponse<AnyBody<Encoder<B>>>, Error>;
|
||||
type Output = Result<ServiceResponse<EitherBody<Encoder<B>>>, Error>;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let this = self.project();
|
||||
|
@ -193,10 +187,11 @@ where
|
|||
};
|
||||
|
||||
Poll::Ready(Ok(resp.map_body(move |head, body| {
|
||||
Encoder::response(enc, head, AnyBody::Body(body))
|
||||
EitherBody::left(Encoder::response(enc, head, body))
|
||||
})))
|
||||
}
|
||||
Err(e) => Poll::Ready(Err(e)),
|
||||
|
||||
Err(err) => Poll::Ready(Err(err)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
212
src/responder.rs
212
src/responder.rs
|
@ -1,7 +1,5 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use actix_http::{
|
||||
body::AnyBody,
|
||||
body::BoxBody,
|
||||
http::{header::IntoHeaderPair, Error as HttpError, HeaderMap, StatusCode},
|
||||
};
|
||||
use bytes::{Bytes, BytesMut};
|
||||
|
@ -13,7 +11,7 @@ use crate::{Error, HttpRequest, HttpResponse, HttpResponseBuilder};
|
|||
/// Any types that implement this trait can be used in the return type of a handler.
|
||||
pub trait Responder {
|
||||
/// Convert self to `HttpResponse`.
|
||||
fn respond_to(self, req: &HttpRequest) -> HttpResponse;
|
||||
fn respond_to(self, req: &HttpRequest) -> HttpResponse<BoxBody>;
|
||||
|
||||
/// Override a status code for a Responder.
|
||||
///
|
||||
|
@ -60,34 +58,34 @@ pub trait Responder {
|
|||
|
||||
impl Responder for HttpResponse {
|
||||
#[inline]
|
||||
fn respond_to(self, _: &HttpRequest) -> HttpResponse {
|
||||
fn respond_to(self, _: &HttpRequest) -> HttpResponse<BoxBody> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Responder for actix_http::Response<AnyBody> {
|
||||
impl Responder for actix_http::Response<BoxBody> {
|
||||
#[inline]
|
||||
fn respond_to(self, _: &HttpRequest) -> HttpResponse {
|
||||
fn respond_to(self, _: &HttpRequest) -> HttpResponse<BoxBody> {
|
||||
HttpResponse::from(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Responder for HttpResponseBuilder {
|
||||
#[inline]
|
||||
fn respond_to(mut self, _: &HttpRequest) -> HttpResponse {
|
||||
fn respond_to(mut self, _: &HttpRequest) -> HttpResponse<BoxBody> {
|
||||
self.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl Responder for actix_http::ResponseBuilder {
|
||||
#[inline]
|
||||
fn respond_to(mut self, _: &HttpRequest) -> HttpResponse {
|
||||
HttpResponse::from(self.finish())
|
||||
fn respond_to(mut self, req: &HttpRequest) -> HttpResponse<BoxBody> {
|
||||
self.finish().map_into_boxed_body().respond_to(req)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Responder> Responder for Option<T> {
|
||||
fn respond_to(self, req: &HttpRequest) -> HttpResponse {
|
||||
fn respond_to(self, req: &HttpRequest) -> HttpResponse<BoxBody> {
|
||||
match self {
|
||||
Some(val) => val.respond_to(req),
|
||||
None => HttpResponse::new(StatusCode::NOT_FOUND),
|
||||
|
@ -100,7 +98,7 @@ where
|
|||
T: Responder,
|
||||
E: Into<Error>,
|
||||
{
|
||||
fn respond_to(self, req: &HttpRequest) -> HttpResponse {
|
||||
fn respond_to(self, req: &HttpRequest) -> HttpResponse<BoxBody> {
|
||||
match self {
|
||||
Ok(val) => val.respond_to(req),
|
||||
Err(e) => HttpResponse::from_error(e.into()),
|
||||
|
@ -109,7 +107,7 @@ where
|
|||
}
|
||||
|
||||
impl<T: Responder> Responder for (T, StatusCode) {
|
||||
fn respond_to(self, req: &HttpRequest) -> HttpResponse {
|
||||
fn respond_to(self, req: &HttpRequest) -> HttpResponse<BoxBody> {
|
||||
let mut res = self.0.respond_to(req);
|
||||
*res.status_mut() = self.1;
|
||||
res
|
||||
|
@ -119,7 +117,7 @@ impl<T: Responder> Responder for (T, StatusCode) {
|
|||
macro_rules! impl_responder {
|
||||
($res: ty, $ct: path) => {
|
||||
impl Responder for $res {
|
||||
fn respond_to(self, _: &HttpRequest) -> HttpResponse {
|
||||
fn respond_to(self, _: &HttpRequest) -> HttpResponse<BoxBody> {
|
||||
HttpResponse::Ok().content_type($ct).body(self)
|
||||
}
|
||||
}
|
||||
|
@ -130,9 +128,9 @@ impl_responder!(&'static str, mime::TEXT_PLAIN_UTF_8);
|
|||
|
||||
impl_responder!(String, mime::TEXT_PLAIN_UTF_8);
|
||||
|
||||
impl_responder!(&'_ String, mime::TEXT_PLAIN_UTF_8);
|
||||
// impl_responder!(&'_ String, mime::TEXT_PLAIN_UTF_8);
|
||||
|
||||
impl_responder!(Cow<'_, str>, mime::TEXT_PLAIN_UTF_8);
|
||||
// impl_responder!(Cow<'_, str>, mime::TEXT_PLAIN_UTF_8);
|
||||
|
||||
impl_responder!(&'static [u8], mime::APPLICATION_OCTET_STREAM);
|
||||
|
||||
|
@ -231,11 +229,15 @@ pub(crate) mod tests {
|
|||
use actix_service::Service;
|
||||
use bytes::{Bytes, BytesMut};
|
||||
|
||||
use actix_http::body::to_bytes;
|
||||
|
||||
use super::*;
|
||||
use crate::dev::AnyBody;
|
||||
use crate::http::{header::CONTENT_TYPE, HeaderValue, StatusCode};
|
||||
use crate::test::{init_service, TestRequest};
|
||||
use crate::{error, web, App};
|
||||
use crate::{
|
||||
error,
|
||||
http::{header::CONTENT_TYPE, HeaderValue, StatusCode},
|
||||
test::{assert_body_eq, init_service, TestRequest},
|
||||
web, App,
|
||||
};
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn test_option_responder() {
|
||||
|
@ -253,112 +255,107 @@ pub(crate) mod tests {
|
|||
let req = TestRequest::with_uri("/some").to_request();
|
||||
let resp = srv.call(req).await.unwrap();
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
match resp.response().body() {
|
||||
AnyBody::Bytes(ref b) => {
|
||||
let bytes = b.clone();
|
||||
assert_eq!(bytes, Bytes::from_static(b"some"));
|
||||
}
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) trait BodyTest {
|
||||
fn bin_ref(&self) -> &[u8];
|
||||
fn body(&self) -> &AnyBody;
|
||||
}
|
||||
|
||||
impl BodyTest for AnyBody {
|
||||
fn bin_ref(&self) -> &[u8] {
|
||||
match self {
|
||||
AnyBody::Bytes(ref bin) => bin,
|
||||
_ => unreachable!("bug in test impl"),
|
||||
}
|
||||
}
|
||||
fn body(&self) -> &AnyBody {
|
||||
self
|
||||
}
|
||||
assert_body_eq!(resp, b"some");
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn test_responder() {
|
||||
let req = TestRequest::default().to_http_request();
|
||||
|
||||
let resp = "test".respond_to(&req);
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
assert_eq!(resp.body().bin_ref(), b"test");
|
||||
let res = "test".respond_to(&req);
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
assert_eq!(
|
||||
resp.headers().get(CONTENT_TYPE).unwrap(),
|
||||
res.headers().get(CONTENT_TYPE).unwrap(),
|
||||
HeaderValue::from_static("text/plain; charset=utf-8")
|
||||
);
|
||||
|
||||
let resp = b"test".respond_to(&req);
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
assert_eq!(resp.body().bin_ref(), b"test");
|
||||
assert_eq!(
|
||||
resp.headers().get(CONTENT_TYPE).unwrap(),
|
||||
to_bytes(res.into_body()).await.unwrap(),
|
||||
Bytes::from_static(b"test"),
|
||||
);
|
||||
|
||||
let res = b"test".respond_to(&req);
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
assert_eq!(
|
||||
res.headers().get(CONTENT_TYPE).unwrap(),
|
||||
HeaderValue::from_static("application/octet-stream")
|
||||
);
|
||||
|
||||
let resp = "test".to_string().respond_to(&req);
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
assert_eq!(resp.body().bin_ref(), b"test");
|
||||
assert_eq!(
|
||||
resp.headers().get(CONTENT_TYPE).unwrap(),
|
||||
HeaderValue::from_static("text/plain; charset=utf-8")
|
||||
to_bytes(res.into_body()).await.unwrap(),
|
||||
Bytes::from_static(b"test"),
|
||||
);
|
||||
|
||||
let resp = (&"test".to_string()).respond_to(&req);
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
assert_eq!(resp.body().bin_ref(), b"test");
|
||||
let res = "test".to_string().respond_to(&req);
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
assert_eq!(
|
||||
resp.headers().get(CONTENT_TYPE).unwrap(),
|
||||
res.headers().get(CONTENT_TYPE).unwrap(),
|
||||
HeaderValue::from_static("text/plain; charset=utf-8")
|
||||
);
|
||||
|
||||
let s = String::from("test");
|
||||
let resp = Cow::Borrowed(s.as_str()).respond_to(&req);
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
assert_eq!(resp.body().bin_ref(), b"test");
|
||||
assert_eq!(
|
||||
resp.headers().get(CONTENT_TYPE).unwrap(),
|
||||
HeaderValue::from_static("text/plain; charset=utf-8")
|
||||
to_bytes(res.into_body()).await.unwrap(),
|
||||
Bytes::from_static(b"test"),
|
||||
);
|
||||
|
||||
let resp = Cow::<'_, str>::Owned(s).respond_to(&req);
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
assert_eq!(resp.body().bin_ref(), b"test");
|
||||
assert_eq!(
|
||||
resp.headers().get(CONTENT_TYPE).unwrap(),
|
||||
HeaderValue::from_static("text/plain; charset=utf-8")
|
||||
);
|
||||
// let res = (&"test".to_string()).respond_to(&req);
|
||||
// assert_eq!(res.status(), StatusCode::OK);
|
||||
// assert_eq!(
|
||||
// res.headers().get(CONTENT_TYPE).unwrap(),
|
||||
// HeaderValue::from_static("text/plain; charset=utf-8")
|
||||
// );
|
||||
// assert_eq!(
|
||||
// to_bytes(res.into_body()).await.unwrap(),
|
||||
// Bytes::from_static(b"test"),
|
||||
// );
|
||||
|
||||
let resp = Cow::Borrowed("test").respond_to(&req);
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
assert_eq!(resp.body().bin_ref(), b"test");
|
||||
assert_eq!(
|
||||
resp.headers().get(CONTENT_TYPE).unwrap(),
|
||||
HeaderValue::from_static("text/plain; charset=utf-8")
|
||||
);
|
||||
// let s = String::from("test");
|
||||
// let res = Cow::Borrowed(s.as_str()).respond_to(&req);
|
||||
// assert_eq!(res.status(), StatusCode::OK);
|
||||
// assert_eq!(res.body().bin_ref(), b"test");
|
||||
// assert_eq!(
|
||||
// res.headers().get(CONTENT_TYPE).unwrap(),
|
||||
// HeaderValue::from_static("text/plain; charset=utf-8")
|
||||
// );
|
||||
|
||||
let resp = Bytes::from_static(b"test").respond_to(&req);
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
assert_eq!(resp.body().bin_ref(), b"test");
|
||||
// let res = Cow::<'_, str>::Owned(s).respond_to(&req);
|
||||
// assert_eq!(res.status(), StatusCode::OK);
|
||||
// assert_eq!(res.body().bin_ref(), b"test");
|
||||
// assert_eq!(
|
||||
// res.headers().get(CONTENT_TYPE).unwrap(),
|
||||
// HeaderValue::from_static("text/plain; charset=utf-8")
|
||||
// );
|
||||
|
||||
// let res = Cow::Borrowed("test").respond_to(&req);
|
||||
// assert_eq!(res.status(), StatusCode::OK);
|
||||
// assert_eq!(res.body().bin_ref(), b"test");
|
||||
// assert_eq!(
|
||||
// res.headers().get(CONTENT_TYPE).unwrap(),
|
||||
// HeaderValue::from_static("text/plain; charset=utf-8")
|
||||
// );
|
||||
|
||||
let res = Bytes::from_static(b"test").respond_to(&req);
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
assert_eq!(
|
||||
resp.headers().get(CONTENT_TYPE).unwrap(),
|
||||
res.headers().get(CONTENT_TYPE).unwrap(),
|
||||
HeaderValue::from_static("application/octet-stream")
|
||||
);
|
||||
|
||||
let resp = BytesMut::from(b"test".as_ref()).respond_to(&req);
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
assert_eq!(resp.body().bin_ref(), b"test");
|
||||
assert_eq!(
|
||||
resp.headers().get(CONTENT_TYPE).unwrap(),
|
||||
to_bytes(res.into_body()).await.unwrap(),
|
||||
Bytes::from_static(b"test"),
|
||||
);
|
||||
|
||||
let res = BytesMut::from(b"test".as_ref()).respond_to(&req);
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
assert_eq!(
|
||||
res.headers().get(CONTENT_TYPE).unwrap(),
|
||||
HeaderValue::from_static("application/octet-stream")
|
||||
);
|
||||
assert_eq!(
|
||||
to_bytes(res.into_body()).await.unwrap(),
|
||||
Bytes::from_static(b"test"),
|
||||
);
|
||||
|
||||
// InternalError
|
||||
let resp = error::InternalError::new("err", StatusCode::BAD_REQUEST).respond_to(&req);
|
||||
assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
|
||||
let res = error::InternalError::new("err", StatusCode::BAD_REQUEST).respond_to(&req);
|
||||
assert_eq!(res.status(), StatusCode::BAD_REQUEST);
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
|
@ -368,11 +365,14 @@ pub(crate) mod tests {
|
|||
// Result<I, E>
|
||||
let resp = Ok::<_, Error>("test".to_string()).respond_to(&req);
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
assert_eq!(resp.body().bin_ref(), b"test");
|
||||
assert_eq!(
|
||||
resp.headers().get(CONTENT_TYPE).unwrap(),
|
||||
HeaderValue::from_static("text/plain; charset=utf-8")
|
||||
);
|
||||
assert_eq!(
|
||||
to_bytes(resp.into_body()).await.unwrap(),
|
||||
Bytes::from_static(b"test"),
|
||||
);
|
||||
|
||||
let res = Err::<String, _>(error::InternalError::new("err", StatusCode::BAD_REQUEST))
|
||||
.respond_to(&req);
|
||||
|
@ -389,7 +389,10 @@ pub(crate) mod tests {
|
|||
.respond_to(&req);
|
||||
|
||||
assert_eq!(res.status(), StatusCode::BAD_REQUEST);
|
||||
assert_eq!(res.body().bin_ref(), b"test");
|
||||
assert_eq!(
|
||||
to_bytes(res.into_body()).await.unwrap(),
|
||||
Bytes::from_static(b"test"),
|
||||
);
|
||||
|
||||
let res = "test"
|
||||
.to_string()
|
||||
|
@ -397,11 +400,14 @@ pub(crate) mod tests {
|
|||
.respond_to(&req);
|
||||
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
assert_eq!(res.body().bin_ref(), b"test");
|
||||
assert_eq!(
|
||||
res.headers().get(CONTENT_TYPE).unwrap(),
|
||||
HeaderValue::from_static("json")
|
||||
);
|
||||
assert_eq!(
|
||||
to_bytes(res.into_body()).await.unwrap(),
|
||||
Bytes::from_static(b"test"),
|
||||
);
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
|
@ -409,17 +415,23 @@ pub(crate) mod tests {
|
|||
let req = TestRequest::default().to_http_request();
|
||||
let res = ("test".to_string(), StatusCode::BAD_REQUEST).respond_to(&req);
|
||||
assert_eq!(res.status(), StatusCode::BAD_REQUEST);
|
||||
assert_eq!(res.body().bin_ref(), b"test");
|
||||
assert_eq!(
|
||||
to_bytes(res.into_body()).await.unwrap(),
|
||||
Bytes::from_static(b"test"),
|
||||
);
|
||||
|
||||
let req = TestRequest::default().to_http_request();
|
||||
let res = ("test".to_string(), StatusCode::OK)
|
||||
.with_header((CONTENT_TYPE, mime::APPLICATION_JSON))
|
||||
.respond_to(&req);
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
assert_eq!(res.body().bin_ref(), b"test");
|
||||
assert_eq!(
|
||||
res.headers().get(CONTENT_TYPE).unwrap(),
|
||||
HeaderValue::from_static("application/json")
|
||||
);
|
||||
assert_eq!(
|
||||
to_bytes(res.into_body()).await.unwrap(),
|
||||
Bytes::from_static(b"test"),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ use std::{
|
|||
};
|
||||
|
||||
use actix_http::{
|
||||
body::{AnyBody, BodyStream},
|
||||
body::{BodyStream, BoxBody, MessageBody},
|
||||
http::{
|
||||
header::{self, HeaderName, IntoHeaderPair, IntoHeaderValue},
|
||||
ConnectionType, Error as HttpError, StatusCode,
|
||||
|
@ -33,7 +33,7 @@ use crate::{
|
|||
///
|
||||
/// This type can be used to construct an instance of `Response` through a builder-like pattern.
|
||||
pub struct HttpResponseBuilder {
|
||||
res: Option<Response<AnyBody>>,
|
||||
res: Option<Response<BoxBody>>,
|
||||
err: Option<HttpError>,
|
||||
#[cfg(feature = "cookies")]
|
||||
cookies: Option<CookieJar>,
|
||||
|
@ -44,7 +44,7 @@ impl HttpResponseBuilder {
|
|||
/// Create response builder
|
||||
pub fn new(status: StatusCode) -> Self {
|
||||
Self {
|
||||
res: Some(Response::new(status)),
|
||||
res: Some(Response::with_body(status, BoxBody::new(()))),
|
||||
err: None,
|
||||
#[cfg(feature = "cookies")]
|
||||
cookies: None,
|
||||
|
@ -299,7 +299,6 @@ impl HttpResponseBuilder {
|
|||
}
|
||||
|
||||
/// Mutable reference to a the response's extensions
|
||||
#[inline]
|
||||
pub fn extensions_mut(&mut self) -> RefMut<'_, Extensions> {
|
||||
self.res
|
||||
.as_mut()
|
||||
|
@ -310,10 +309,13 @@ impl HttpResponseBuilder {
|
|||
/// Set a body and generate `Response`.
|
||||
///
|
||||
/// `HttpResponseBuilder` can not be used after this call.
|
||||
#[inline]
|
||||
pub fn body<B: Into<AnyBody>>(&mut self, body: B) -> HttpResponse<AnyBody> {
|
||||
match self.message_body(body.into()) {
|
||||
Ok(res) => res,
|
||||
pub fn body<B>(&mut self, body: B) -> HttpResponse<BoxBody>
|
||||
where
|
||||
B: MessageBody + 'static,
|
||||
B::Error: Into<Box<dyn StdError + 'static>>,
|
||||
{
|
||||
match self.message_body(body) {
|
||||
Ok(res) => res.map_into_boxed_body(),
|
||||
Err(err) => HttpResponse::from_error(err),
|
||||
}
|
||||
}
|
||||
|
@ -332,7 +334,7 @@ impl HttpResponseBuilder {
|
|||
.expect("cannot reuse response builder")
|
||||
.set_body(body);
|
||||
|
||||
#[allow(unused_mut)]
|
||||
#[allow(unused_mut)] // mut is only unused when cookies are disabled
|
||||
let mut res = HttpResponse::from(res);
|
||||
|
||||
#[cfg(feature = "cookies")]
|
||||
|
@ -357,7 +359,7 @@ impl HttpResponseBuilder {
|
|||
S: Stream<Item = Result<Bytes, E>> + 'static,
|
||||
E: Into<Box<dyn StdError>> + 'static,
|
||||
{
|
||||
self.body(AnyBody::new_boxed(BodyStream::new(stream)))
|
||||
self.body(BoxBody::new(BodyStream::new(stream)))
|
||||
}
|
||||
|
||||
/// Set a json body and generate `Response`
|
||||
|
@ -376,7 +378,7 @@ impl HttpResponseBuilder {
|
|||
self.insert_header((header::CONTENT_TYPE, mime::APPLICATION_JSON));
|
||||
}
|
||||
|
||||
self.body(AnyBody::from(body))
|
||||
self.body(body)
|
||||
}
|
||||
Err(err) => HttpResponse::from_error(JsonPayloadError::Serialize(err)),
|
||||
}
|
||||
|
@ -387,7 +389,7 @@ impl HttpResponseBuilder {
|
|||
/// `HttpResponseBuilder` can not be used after this call.
|
||||
#[inline]
|
||||
pub fn finish(&mut self) -> HttpResponse {
|
||||
self.body(AnyBody::empty())
|
||||
self.body(BoxBody::new(()))
|
||||
}
|
||||
|
||||
/// This method construct new `HttpResponseBuilder`
|
||||
|
@ -416,7 +418,7 @@ impl From<HttpResponseBuilder> for HttpResponse {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<HttpResponseBuilder> for Response<AnyBody> {
|
||||
impl From<HttpResponseBuilder> for Response<BoxBody> {
|
||||
fn from(mut builder: HttpResponseBuilder) -> Self {
|
||||
builder.finish().into()
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ use std::{
|
|||
};
|
||||
|
||||
use actix_http::{
|
||||
body::{AnyBody, BoxBody, MessageBody},
|
||||
body::{BoxBody, MessageBody},
|
||||
http::{header::HeaderMap, StatusCode},
|
||||
Extensions, Response, ResponseHead,
|
||||
};
|
||||
|
@ -26,12 +26,12 @@ use {
|
|||
use crate::{error::Error, HttpResponseBuilder};
|
||||
|
||||
/// An outgoing response.
|
||||
pub struct HttpResponse<B = AnyBody> {
|
||||
pub struct HttpResponse<B = BoxBody> {
|
||||
res: Response<B>,
|
||||
pub(crate) error: Option<Error>,
|
||||
}
|
||||
|
||||
impl HttpResponse<AnyBody> {
|
||||
impl HttpResponse<BoxBody> {
|
||||
/// Constructs a response.
|
||||
#[inline]
|
||||
pub fn new(status: StatusCode) -> Self {
|
||||
|
@ -228,9 +228,9 @@ impl<B> HttpResponse<B> {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: into_body equivalent
|
||||
// TODO: old into_body equivalent, maybe
|
||||
|
||||
pub fn into_boxed_body(self) -> HttpResponse<BoxBody>
|
||||
pub fn map_into_boxed_body(self) -> HttpResponse<BoxBody>
|
||||
where
|
||||
B: MessageBody + 'static,
|
||||
B::Error: Into<Box<dyn StdError + 'static>>,
|
||||
|
@ -281,14 +281,14 @@ impl<B> From<HttpResponse<B>> for Response<B> {
|
|||
}
|
||||
}
|
||||
|
||||
// Future is only implemented for AnyBody payload type because it's the most useful for making
|
||||
// Future is only implemented for BoxBody payload type because it's the most useful for making
|
||||
// simple handlers without async blocks. Making it generic over all MessageBody types requires a
|
||||
// future impl on Response which would cause it's body field to be, undesirably, Option<B>.
|
||||
//
|
||||
// This impl is not particularly efficient due to the Response construction and should probably
|
||||
// not be invoked if performance is important. Prefer an async fn/block in such cases.
|
||||
impl Future for HttpResponse<AnyBody> {
|
||||
type Output = Result<Response<AnyBody>, Error>;
|
||||
impl Future for HttpResponse<BoxBody> {
|
||||
type Output = Result<Response<BoxBody>, Error>;
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
if let Some(err) = self.error.take() {
|
||||
|
|
50
src/scope.rs
50
src/scope.rs
|
@ -586,12 +586,11 @@ mod tests {
|
|||
use bytes::Bytes;
|
||||
|
||||
use crate::{
|
||||
dev::AnyBody,
|
||||
guard,
|
||||
http::{header, HeaderValue, Method, StatusCode},
|
||||
middleware::DefaultHeaders,
|
||||
service::{ServiceRequest, ServiceResponse},
|
||||
test::{call_service, init_service, read_body, TestRequest},
|
||||
test::{assert_body_eq, call_service, init_service, read_body, TestRequest},
|
||||
web, App, HttpMessage, HttpRequest, HttpResponse,
|
||||
};
|
||||
|
||||
|
@ -754,20 +753,13 @@ mod tests {
|
|||
.await;
|
||||
|
||||
let req = TestRequest::with_uri("/ab-project1/path1").to_request();
|
||||
let resp = srv.call(req).await.unwrap();
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
|
||||
match resp.response().body() {
|
||||
AnyBody::Bytes(ref b) => {
|
||||
let bytes = b.clone();
|
||||
assert_eq!(bytes, Bytes::from_static(b"project: project1"));
|
||||
}
|
||||
_ => panic!(),
|
||||
}
|
||||
let res = srv.call(req).await.unwrap();
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
assert_body_eq!(res, b"project: project1");
|
||||
|
||||
let req = TestRequest::with_uri("/aa-project1/path1").to_request();
|
||||
let resp = srv.call(req).await.unwrap();
|
||||
assert_eq!(resp.status(), StatusCode::NOT_FOUND);
|
||||
let res = srv.call(req).await.unwrap();
|
||||
assert_eq!(res.status(), StatusCode::NOT_FOUND);
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
|
@ -855,16 +847,9 @@ mod tests {
|
|||
.await;
|
||||
|
||||
let req = TestRequest::with_uri("/app/project_1/path1").to_request();
|
||||
let resp = srv.call(req).await.unwrap();
|
||||
assert_eq!(resp.status(), StatusCode::CREATED);
|
||||
|
||||
match resp.response().body() {
|
||||
AnyBody::Bytes(ref b) => {
|
||||
let bytes = b.clone();
|
||||
assert_eq!(bytes, Bytes::from_static(b"project: project_1"));
|
||||
}
|
||||
_ => panic!(),
|
||||
}
|
||||
let res = srv.call(req).await.unwrap();
|
||||
assert_eq!(res.status(), StatusCode::CREATED);
|
||||
assert_body_eq!(res, b"project: project_1");
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
|
@ -883,20 +868,13 @@ mod tests {
|
|||
.await;
|
||||
|
||||
let req = TestRequest::with_uri("/app/test/1/path1").to_request();
|
||||
let resp = srv.call(req).await.unwrap();
|
||||
assert_eq!(resp.status(), StatusCode::CREATED);
|
||||
|
||||
match resp.response().body() {
|
||||
AnyBody::Bytes(ref b) => {
|
||||
let bytes = b.clone();
|
||||
assert_eq!(bytes, Bytes::from_static(b"project: test - 1"));
|
||||
}
|
||||
_ => panic!(),
|
||||
}
|
||||
let res = srv.call(req).await.unwrap();
|
||||
assert_eq!(res.status(), StatusCode::CREATED);
|
||||
assert_body_eq!(res, b"project: test - 1");
|
||||
|
||||
let req = TestRequest::with_uri("/app/test/1/path2").to_request();
|
||||
let resp = srv.call(req).await.unwrap();
|
||||
assert_eq!(resp.status(), StatusCode::NOT_FOUND);
|
||||
let res = srv.call(req).await.unwrap();
|
||||
assert_eq!(res.status(), StatusCode::NOT_FOUND);
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
use std::cell::{Ref, RefMut};
|
||||
use std::rc::Rc;
|
||||
use std::{fmt, net};
|
||||
use std::{
|
||||
cell::{Ref, RefMut},
|
||||
error::Error as StdError,
|
||||
fmt, net,
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
use actix_http::{
|
||||
body::{AnyBody, MessageBody},
|
||||
body::{BoxBody, MessageBody},
|
||||
http::{HeaderMap, Method, StatusCode, Uri, Version},
|
||||
Extensions, HttpMessage, Payload, PayloadStream, RequestHead, Response, ResponseHead,
|
||||
};
|
||||
|
@ -333,12 +336,12 @@ impl fmt::Debug for ServiceRequest {
|
|||
}
|
||||
|
||||
/// A service level response wrapper.
|
||||
pub struct ServiceResponse<B = AnyBody> {
|
||||
pub struct ServiceResponse<B = BoxBody> {
|
||||
request: HttpRequest,
|
||||
response: HttpResponse<B>,
|
||||
}
|
||||
|
||||
impl ServiceResponse<AnyBody> {
|
||||
impl ServiceResponse<BoxBody> {
|
||||
/// Create service response from the error
|
||||
pub fn from_err<E: Into<Error>>(err: E, request: HttpRequest) -> Self {
|
||||
let response = HttpResponse::from_error(err);
|
||||
|
@ -419,6 +422,14 @@ impl<B> ServiceResponse<B> {
|
|||
request: self.request,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn map_into_boxed_body(self) -> ServiceResponse<BoxBody>
|
||||
where
|
||||
B: MessageBody + 'static,
|
||||
B::Error: Into<Box<dyn StdError + 'static>>,
|
||||
{
|
||||
self.map_body(|_, body| BoxBody::new(body))
|
||||
}
|
||||
}
|
||||
|
||||
impl<B> From<ServiceResponse<B>> for HttpResponse<B> {
|
||||
|
|
24
src/test.rs
24
src/test.rs
|
@ -4,7 +4,6 @@ use std::{borrow::Cow, net::SocketAddr, rc::Rc};
|
|||
|
||||
pub use actix_http::test::TestBuffer;
|
||||
use actix_http::{
|
||||
body,
|
||||
http::{header::IntoHeaderPair, Method, StatusCode, Uri, Version},
|
||||
test::TestRequest as HttpTestRequest,
|
||||
Extensions, Request,
|
||||
|
@ -20,9 +19,10 @@ use serde::{de::DeserializeOwned, Serialize};
|
|||
use crate::cookie::{Cookie, CookieJar};
|
||||
use crate::{
|
||||
app_service::AppInitServiceState,
|
||||
body::{self, BoxBody, MessageBody},
|
||||
config::AppConfig,
|
||||
data::Data,
|
||||
dev::{AnyBody, MessageBody, Payload},
|
||||
dev::Payload,
|
||||
http::header::ContentType,
|
||||
rmap::ResourceMap,
|
||||
service::{ServiceRequest, ServiceResponse},
|
||||
|
@ -32,14 +32,14 @@ use crate::{
|
|||
|
||||
/// Create service that always responds with `HttpResponse::Ok()` and no body.
|
||||
pub fn ok_service(
|
||||
) -> impl Service<ServiceRequest, Response = ServiceResponse<AnyBody>, Error = Error> {
|
||||
) -> impl Service<ServiceRequest, Response = ServiceResponse<BoxBody>, Error = Error> {
|
||||
default_service(StatusCode::OK)
|
||||
}
|
||||
|
||||
/// Create service that always responds with given status code and no body.
|
||||
pub fn default_service(
|
||||
status_code: StatusCode,
|
||||
) -> impl Service<ServiceRequest, Response = ServiceResponse<AnyBody>, Error = Error> {
|
||||
) -> impl Service<ServiceRequest, Response = ServiceResponse<BoxBody>, Error = Error> {
|
||||
(move |req: ServiceRequest| {
|
||||
ok(req.into_response(HttpResponseBuilder::new(status_code).finish()))
|
||||
})
|
||||
|
@ -632,6 +632,22 @@ impl TestRequest {
|
|||
}
|
||||
}
|
||||
|
||||
/// Reduces boilerplate code when testing expected response payloads.
|
||||
#[cfg(test)]
|
||||
macro_rules! assert_body_eq {
|
||||
($res:ident, $expected:expr) => {
|
||||
assert_eq!(
|
||||
::actix_http::body::to_bytes($res.into_body())
|
||||
.await
|
||||
.expect("body read should have succeeded"),
|
||||
Bytes::from_static($expected),
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) use assert_body_eq;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::time::SystemTime;
|
||||
|
|
|
@ -408,11 +408,14 @@ mod tests {
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::*;
|
||||
use crate::http::{
|
||||
header::{HeaderValue, CONTENT_LENGTH, CONTENT_TYPE},
|
||||
StatusCode,
|
||||
};
|
||||
use crate::test::TestRequest;
|
||||
use crate::{
|
||||
http::{
|
||||
header::{HeaderValue, CONTENT_LENGTH, CONTENT_TYPE},
|
||||
StatusCode,
|
||||
},
|
||||
test::assert_body_eq,
|
||||
};
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug, PartialEq)]
|
||||
struct Info {
|
||||
|
@ -520,15 +523,13 @@ mod tests {
|
|||
hello: "world".to_string(),
|
||||
counter: 123,
|
||||
});
|
||||
let resp = form.respond_to(&req);
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
let res = form.respond_to(&req);
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
assert_eq!(
|
||||
resp.headers().get(CONTENT_TYPE).unwrap(),
|
||||
res.headers().get(CONTENT_TYPE).unwrap(),
|
||||
HeaderValue::from_static("application/x-www-form-urlencoded")
|
||||
);
|
||||
|
||||
use crate::responder::tests::BodyTest;
|
||||
assert_eq!(resp.body().bin_ref(), b"hello=world&counter=123");
|
||||
assert_body_eq!(res, b"hello=world&counter=123");
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
|
|
|
@ -444,7 +444,7 @@ mod tests {
|
|||
header::{self, CONTENT_LENGTH, CONTENT_TYPE},
|
||||
StatusCode,
|
||||
},
|
||||
test::{load_body, TestRequest},
|
||||
test::{assert_body_eq, load_body, TestRequest},
|
||||
};
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
|
@ -472,15 +472,13 @@ mod tests {
|
|||
let j = Json(MyObject {
|
||||
name: "test".to_string(),
|
||||
});
|
||||
let resp = j.respond_to(&req);
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
let res = j.respond_to(&req);
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
assert_eq!(
|
||||
resp.headers().get(header::CONTENT_TYPE).unwrap(),
|
||||
res.headers().get(header::CONTENT_TYPE).unwrap(),
|
||||
header::HeaderValue::from_static("application/json")
|
||||
);
|
||||
|
||||
use crate::responder::tests::BodyTest;
|
||||
assert_eq!(resp.body().bin_ref(), b"{\"name\":\"test\"}");
|
||||
assert_body_eq!(res, b"{\"name\":\"test\"}");
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
|
|
|
@ -200,13 +200,10 @@ async fn test_body_encoding_override() {
|
|||
.body(STR)
|
||||
})))
|
||||
.service(web::resource("/raw").route(web::to(|| {
|
||||
let body = actix_web::dev::AnyBody::Bytes(STR.into());
|
||||
let mut response =
|
||||
HttpResponse::with_body(actix_web::http::StatusCode::OK, body);
|
||||
|
||||
HttpResponse::with_body(actix_web::http::StatusCode::OK, STR);
|
||||
response.encoding(ContentEncoding::Deflate);
|
||||
|
||||
response
|
||||
response.map_into_boxed_body()
|
||||
})))
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue