mirror of https://github.com/fafhrd91/actix-web
Merge branch 'master' into feat/io-uring
This commit is contained in:
commit
36af057383
|
@ -141,7 +141,7 @@ jobs:
|
||||||
if: github.ref == 'refs/heads/master'
|
if: github.ref == 'refs/heads/master'
|
||||||
run: |
|
run: |
|
||||||
cargo install cargo-tarpaulin --vers "^0.13"
|
cargo install cargo-tarpaulin --vers "^0.13"
|
||||||
cargo tarpaulin --out Xml --verbose
|
cargo tarpaulin --workspace --features=rustls,openssl --out Xml --verbose
|
||||||
- name: Upload to Codecov
|
- name: Upload to Codecov
|
||||||
if: github.ref == 'refs/heads/master'
|
if: github.ref == 'refs/heads/master'
|
||||||
uses: codecov/codecov-action@v1
|
uses: codecov/codecov-action@v1
|
||||||
|
|
12
CHANGES.md
12
CHANGES.md
|
@ -1,6 +1,16 @@
|
||||||
# Changes
|
# Changes
|
||||||
|
|
||||||
## Unreleased - 2021-xx-xx
|
## Unreleased - 2021-xx-xx
|
||||||
|
### Changed
|
||||||
|
* Compress middleware's response type is now `AnyBody<Encoder<B>>`. [#2448]
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
* Relax `Unpin` bound on `S` (stream) parameter of `HttpResponseBuilder::streaming`. [#2448]
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
* `dev::ResponseBody` re-export; is function is replaced by the new `dev::AnyBody` enum. [#2446]
|
||||||
|
|
||||||
|
[#2423]: https://github.com/actix/actix-web/pull/2423
|
||||||
|
|
||||||
|
|
||||||
## 4.0.0-beta.11 - 2021-11-15
|
## 4.0.0-beta.11 - 2021-11-15
|
||||||
|
@ -23,7 +33,7 @@
|
||||||
### Changed
|
### Changed
|
||||||
* Associated type `FromRequest::Config` was removed. [#2233]
|
* Associated type `FromRequest::Config` was removed. [#2233]
|
||||||
* Inner field made private on `web::Payload`. [#2384]
|
* Inner field made private on `web::Payload`. [#2384]
|
||||||
* `Data::into_inner` and `Data::get_ref` no longer require T: Sized. [#2403]
|
* `Data::into_inner` and `Data::get_ref` no longer requires `T: Sized`. [#2403]
|
||||||
* Updated rustls to v0.20. [#2414]
|
* Updated rustls to v0.20. [#2414]
|
||||||
* Minimum supported Rust version (MSRV) is now 1.52.
|
* Minimum supported Rust version (MSRV) is now 1.52.
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,7 @@ __compress = []
|
||||||
io-uring = ["actix-server/io-uring"]
|
io-uring = ["actix-server/io-uring"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix-codec = "0.4.0"
|
actix-codec = "0.4.1"
|
||||||
actix-macros = "0.2.3"
|
actix-macros = "0.2.3"
|
||||||
actix-rt = "2.3"
|
actix-rt = "2.3"
|
||||||
actix-server = "2.0.0-beta.9"
|
actix-server = "2.0.0-beta.9"
|
||||||
|
|
|
@ -30,7 +30,7 @@ openssl = ["tls-openssl", "awc/openssl"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix-service = "2.0.0"
|
actix-service = "2.0.0"
|
||||||
actix-codec = "0.4.0"
|
actix-codec = "0.4.1"
|
||||||
actix-tls = "3.0.0-beta.7"
|
actix-tls = "3.0.0-beta.7"
|
||||||
actix-utils = "3.0.0"
|
actix-utils = "3.0.0"
|
||||||
actix-rt = "2.2"
|
actix-rt = "2.2"
|
||||||
|
|
|
@ -1,6 +1,26 @@
|
||||||
# Changes
|
# Changes
|
||||||
|
|
||||||
## Unreleased - 2021-xx-xx
|
## Unreleased - 2021-xx-xx
|
||||||
|
### Added
|
||||||
|
* `body::AnyBody::empty` for quickly creating an empty body. [#2446]
|
||||||
|
* `impl Clone` for `body::AnyBody<S> where S: Clone`. [#2448]
|
||||||
|
* `body::AnyBody::into_boxed` for quickly converting to a type-erased, boxed body type. [#2448]
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
* Rename `body::AnyBody::{Message => Body}`. [#2446]
|
||||||
|
* Rename `body::AnyBody::{from_message => new_boxed}`. [#2448]
|
||||||
|
* Rename `body::AnyBody::{from_slice => copy_from_slice}`. [#2448]
|
||||||
|
* Rename `body::{BoxAnyBody => BoxBody}`. [#2448]
|
||||||
|
* Change representation of `AnyBody` to include a type parameter in `Body` variant. Defaults to `BoxBody`. [#2448]
|
||||||
|
* `Encoder::response` now returns `AnyBody<Encoder<B>>`. [#2448]
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
* `body::AnyBody::Empty`; an empty body can now only be represented as a zero-length `Bytes` variant. [#2446]
|
||||||
|
* `body::BodySize::Empty`; an empty body can now only be represented as a `Sized(0)` variant. [#2446]
|
||||||
|
* `EncoderError::Boxed`; it is no longer required. [#2446]
|
||||||
|
* `body::ResponseBody`; is function is replaced by the new `body::AnyBody` enum. [#2446]
|
||||||
|
|
||||||
|
[#2446]: https://github.com/actix/actix-web/pull/2446
|
||||||
|
|
||||||
|
|
||||||
## 3.0.0-beta.12 - 2021-11-15
|
## 3.0.0-beta.12 - 2021-11-15
|
||||||
|
|
|
@ -43,7 +43,7 @@ __compress = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix-service = "2.0.0"
|
actix-service = "2.0.0"
|
||||||
actix-codec = "0.4.0"
|
actix-codec = "0.4.1"
|
||||||
actix-utils = "3.0.0"
|
actix-utils = "3.0.0"
|
||||||
actix-rt = "2.2"
|
actix-rt = "2.2"
|
||||||
|
|
||||||
|
@ -92,6 +92,7 @@ regex = "1.3"
|
||||||
rustls-pemfile = "0.2"
|
rustls-pemfile = "0.2"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
static_assertions = "1"
|
||||||
tls-openssl = { package = "openssl", version = "0.10.9" }
|
tls-openssl = { package = "openssl", version = "0.10.9" }
|
||||||
tls-rustls = { package = "rustls", version = "0.20.0" }
|
tls-rustls = { package = "rustls", version = "0.20.0" }
|
||||||
tokio = { version = "1.2", features = ["net", "rt"] }
|
tokio = { version = "1.2", features = ["net", "rt"] }
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
use actix_http::{body::Body, http::HeaderValue, http::StatusCode};
|
use actix_http::{body::AnyBody, http::HeaderValue, http::StatusCode};
|
||||||
use actix_http::{Error, HttpService, Request, Response};
|
use actix_http::{Error, HttpService, Request, Response};
|
||||||
use actix_server::Server;
|
use actix_server::Server;
|
||||||
use bytes::BytesMut;
|
use bytes::BytesMut;
|
||||||
use futures_util::StreamExt as _;
|
use futures_util::StreamExt as _;
|
||||||
|
|
||||||
async fn handle_request(mut req: Request) -> Result<Response<Body>, Error> {
|
async fn handle_request(mut req: Request) -> Result<Response<AnyBody>, Error> {
|
||||||
let mut body = BytesMut::new();
|
let mut body = BytesMut::new();
|
||||||
while let Some(item) = req.payload().next().await {
|
while let Some(item) = req.payload().next().await {
|
||||||
body.extend_from_slice(&item?)
|
body.extend_from_slice(&item?)
|
||||||
|
|
|
@ -8,53 +8,89 @@ use std::{
|
||||||
|
|
||||||
use bytes::{Bytes, BytesMut};
|
use bytes::{Bytes, BytesMut};
|
||||||
use futures_core::Stream;
|
use futures_core::Stream;
|
||||||
|
use pin_project::pin_project;
|
||||||
|
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
|
|
||||||
use super::{BodySize, BodyStream, MessageBody, MessageBodyMapErr, SizedStream};
|
use super::{BodySize, BodyStream, MessageBody, MessageBodyMapErr, SizedStream};
|
||||||
|
|
||||||
|
#[deprecated(since = "4.0.0", note = "Renamed to `AnyBody`.")]
|
||||||
pub type Body = AnyBody;
|
pub type Body = AnyBody;
|
||||||
|
|
||||||
/// Represents various types of HTTP message body.
|
/// Represents various types of HTTP message body.
|
||||||
pub enum AnyBody {
|
#[pin_project(project = AnyBodyProj)]
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum AnyBody<B = BoxBody> {
|
||||||
/// Empty response. `Content-Length` header is not set.
|
/// Empty response. `Content-Length` header is not set.
|
||||||
None,
|
None,
|
||||||
|
|
||||||
/// Zero sized response body. `Content-Length` header is set to `0`.
|
/// Complete, in-memory response body.
|
||||||
Empty,
|
|
||||||
|
|
||||||
/// Specific response body.
|
|
||||||
Bytes(Bytes),
|
Bytes(Bytes),
|
||||||
|
|
||||||
/// Generic message body.
|
/// Generic / Other message body.
|
||||||
Message(BoxAnyBody),
|
Body(#[pin] B),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AnyBody {
|
impl AnyBody {
|
||||||
/// Create body from slice (copy)
|
/// Constructs a new, empty body.
|
||||||
pub fn from_slice(s: &[u8]) -> Self {
|
pub fn empty() -> Self {
|
||||||
Self::Bytes(Bytes::copy_from_slice(s))
|
Self::Bytes(Bytes::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create body from generic message body.
|
/// Create boxed body from generic message body.
|
||||||
pub fn from_message<B>(body: B) -> Self
|
pub fn new_boxed<B>(body: B) -> Self
|
||||||
where
|
where
|
||||||
B: MessageBody + 'static,
|
B: MessageBody + 'static,
|
||||||
B::Error: Into<Box<dyn StdError + 'static>>,
|
B::Error: Into<Box<dyn StdError + 'static>>,
|
||||||
{
|
{
|
||||||
Self::Message(BoxAnyBody::from_body(body))
|
Self::Body(BoxBody::from_body(body))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Constructs new `AnyBody` instance from a slice of bytes by copying it.
|
||||||
|
///
|
||||||
|
/// If your bytes container is owned, it may be cheaper to use a `From` impl.
|
||||||
|
pub fn copy_from_slice(s: &[u8]) -> Self {
|
||||||
|
Self::Bytes(Bytes::copy_from_slice(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[deprecated(since = "4.0.0", note = "Renamed to `copy_from_slice`.")]
|
||||||
|
pub fn from_slice(s: &[u8]) -> Self {
|
||||||
|
Self::Bytes(Bytes::copy_from_slice(s))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MessageBody for AnyBody {
|
impl<B> AnyBody<B>
|
||||||
|
where
|
||||||
|
B: MessageBody + 'static,
|
||||||
|
B::Error: Into<Box<dyn StdError + 'static>>,
|
||||||
|
{
|
||||||
|
/// Create body from generic message body.
|
||||||
|
pub fn new(body: B) -> Self {
|
||||||
|
Self::Body(body)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_boxed(self) -> AnyBody {
|
||||||
|
match self {
|
||||||
|
Self::None => AnyBody::None,
|
||||||
|
Self::Bytes(bytes) => AnyBody::Bytes(bytes),
|
||||||
|
Self::Body(body) => AnyBody::new_boxed(body),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B> MessageBody for AnyBody<B>
|
||||||
|
where
|
||||||
|
B: MessageBody,
|
||||||
|
B::Error: Into<Box<dyn StdError>> + 'static,
|
||||||
|
{
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn size(&self) -> BodySize {
|
fn size(&self) -> BodySize {
|
||||||
match self {
|
match self {
|
||||||
AnyBody::None => BodySize::None,
|
AnyBody::None => BodySize::None,
|
||||||
AnyBody::Empty => BodySize::Empty,
|
|
||||||
AnyBody::Bytes(ref bin) => BodySize::Sized(bin.len() as u64),
|
AnyBody::Bytes(ref bin) => BodySize::Sized(bin.len() as u64),
|
||||||
AnyBody::Message(ref body) => body.size(),
|
AnyBody::Body(ref body) => body.size(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,10 +98,9 @@ impl MessageBody for AnyBody {
|
||||||
self: Pin<&mut Self>,
|
self: Pin<&mut Self>,
|
||||||
cx: &mut Context<'_>,
|
cx: &mut Context<'_>,
|
||||||
) -> Poll<Option<Result<Bytes, Self::Error>>> {
|
) -> Poll<Option<Result<Bytes, Self::Error>>> {
|
||||||
match self.get_mut() {
|
match self.project() {
|
||||||
AnyBody::None => Poll::Ready(None),
|
AnyBodyProj::None => Poll::Ready(None),
|
||||||
AnyBody::Empty => Poll::Ready(None),
|
AnyBodyProj::Bytes(bin) => {
|
||||||
AnyBody::Bytes(ref mut bin) => {
|
|
||||||
let len = bin.len();
|
let len = bin.len();
|
||||||
if len == 0 {
|
if len == 0 {
|
||||||
Poll::Ready(None)
|
Poll::Ready(None)
|
||||||
|
@ -74,8 +109,7 @@ impl MessageBody for AnyBody {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AnyBody::Message(body) => body
|
AnyBodyProj::Body(body) => body
|
||||||
.as_pin_mut()
|
|
||||||
.poll_next(cx)
|
.poll_next(cx)
|
||||||
.map_err(|err| Error::new_body().with_cause(err)),
|
.map_err(|err| Error::new_body().with_cause(err)),
|
||||||
}
|
}
|
||||||
|
@ -83,63 +117,61 @@ impl MessageBody for AnyBody {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for AnyBody {
|
impl PartialEq for AnyBody {
|
||||||
fn eq(&self, other: &Body) -> bool {
|
fn eq(&self, other: &AnyBody) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
AnyBody::None => matches!(*other, AnyBody::None),
|
AnyBody::None => matches!(*other, AnyBody::None),
|
||||||
AnyBody::Empty => matches!(*other, AnyBody::Empty),
|
|
||||||
AnyBody::Bytes(ref b) => match *other {
|
AnyBody::Bytes(ref b) => match *other {
|
||||||
AnyBody::Bytes(ref b2) => b == b2,
|
AnyBody::Bytes(ref b2) => b == b2,
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
AnyBody::Message(_) => false,
|
AnyBody::Body(_) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for AnyBody {
|
impl<S: fmt::Debug> fmt::Debug for AnyBody<S> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
AnyBody::None => write!(f, "AnyBody::None"),
|
AnyBody::None => write!(f, "AnyBody::None"),
|
||||||
AnyBody::Empty => write!(f, "AnyBody::Empty"),
|
AnyBody::Bytes(ref bytes) => write!(f, "AnyBody::Bytes({:?})", bytes),
|
||||||
AnyBody::Bytes(ref b) => write!(f, "AnyBody::Bytes({:?})", b),
|
AnyBody::Body(ref stream) => write!(f, "AnyBody::Message({:?})", stream),
|
||||||
AnyBody::Message(_) => write!(f, "AnyBody::Message(_)"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&'static str> for AnyBody {
|
impl From<&'static str> for AnyBody {
|
||||||
fn from(s: &'static str) -> Body {
|
fn from(string: &'static str) -> AnyBody {
|
||||||
AnyBody::Bytes(Bytes::from_static(s.as_ref()))
|
AnyBody::Bytes(Bytes::from_static(string.as_ref()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&'static [u8]> for AnyBody {
|
impl From<&'static [u8]> for AnyBody {
|
||||||
fn from(s: &'static [u8]) -> Body {
|
fn from(bytes: &'static [u8]) -> AnyBody {
|
||||||
AnyBody::Bytes(Bytes::from_static(s))
|
AnyBody::Bytes(Bytes::from_static(bytes))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Vec<u8>> for AnyBody {
|
impl From<Vec<u8>> for AnyBody {
|
||||||
fn from(vec: Vec<u8>) -> Body {
|
fn from(vec: Vec<u8>) -> AnyBody {
|
||||||
AnyBody::Bytes(Bytes::from(vec))
|
AnyBody::Bytes(Bytes::from(vec))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<String> for AnyBody {
|
impl From<String> for AnyBody {
|
||||||
fn from(s: String) -> Body {
|
fn from(string: String) -> AnyBody {
|
||||||
s.into_bytes().into()
|
string.into_bytes().into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&'_ String> for AnyBody {
|
impl From<&'_ String> for AnyBody {
|
||||||
fn from(s: &String) -> Body {
|
fn from(string: &String) -> AnyBody {
|
||||||
AnyBody::Bytes(Bytes::copy_from_slice(AsRef::<[u8]>::as_ref(&s)))
|
AnyBody::Bytes(Bytes::copy_from_slice(AsRef::<[u8]>::as_ref(&string)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Cow<'_, str>> for AnyBody {
|
impl From<Cow<'_, str>> for AnyBody {
|
||||||
fn from(s: Cow<'_, str>) -> Body {
|
fn from(string: Cow<'_, str>) -> AnyBody {
|
||||||
match s {
|
match string {
|
||||||
Cow::Owned(s) => AnyBody::from(s),
|
Cow::Owned(s) => AnyBody::from(s),
|
||||||
Cow::Borrowed(s) => {
|
Cow::Borrowed(s) => {
|
||||||
AnyBody::Bytes(Bytes::copy_from_slice(AsRef::<[u8]>::as_ref(s)))
|
AnyBody::Bytes(Bytes::copy_from_slice(AsRef::<[u8]>::as_ref(s)))
|
||||||
|
@ -149,14 +181,24 @@ impl From<Cow<'_, str>> for AnyBody {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Bytes> for AnyBody {
|
impl From<Bytes> for AnyBody {
|
||||||
fn from(s: Bytes) -> Body {
|
fn from(bytes: Bytes) -> Self {
|
||||||
AnyBody::Bytes(s)
|
AnyBody::Bytes(bytes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<BytesMut> for AnyBody {
|
impl From<BytesMut> for AnyBody {
|
||||||
fn from(s: BytesMut) -> Body {
|
fn from(bytes: BytesMut) -> Self {
|
||||||
AnyBody::Bytes(s.freeze())
|
AnyBody::Bytes(bytes.freeze())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S, E> From<SizedStream<S>> for AnyBody<SizedStream<S>>
|
||||||
|
where
|
||||||
|
S: Stream<Item = Result<Bytes, E>> + 'static,
|
||||||
|
E: Into<Box<dyn StdError>> + 'static,
|
||||||
|
{
|
||||||
|
fn from(stream: SizedStream<S>) -> Self {
|
||||||
|
AnyBody::new(stream)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,8 +207,18 @@ where
|
||||||
S: Stream<Item = Result<Bytes, E>> + 'static,
|
S: Stream<Item = Result<Bytes, E>> + 'static,
|
||||||
E: Into<Box<dyn StdError>> + 'static,
|
E: Into<Box<dyn StdError>> + 'static,
|
||||||
{
|
{
|
||||||
fn from(s: SizedStream<S>) -> Body {
|
fn from(stream: SizedStream<S>) -> Self {
|
||||||
AnyBody::from_message(s)
|
AnyBody::new_boxed(stream)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S, E> From<BodyStream<S>> for AnyBody<BodyStream<S>>
|
||||||
|
where
|
||||||
|
S: Stream<Item = Result<Bytes, E>> + 'static,
|
||||||
|
E: Into<Box<dyn StdError>> + 'static,
|
||||||
|
{
|
||||||
|
fn from(stream: BodyStream<S>) -> Self {
|
||||||
|
AnyBody::new(stream)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,15 +227,15 @@ where
|
||||||
S: Stream<Item = Result<Bytes, E>> + 'static,
|
S: Stream<Item = Result<Bytes, E>> + 'static,
|
||||||
E: Into<Box<dyn StdError>> + 'static,
|
E: Into<Box<dyn StdError>> + 'static,
|
||||||
{
|
{
|
||||||
fn from(s: BodyStream<S>) -> Body {
|
fn from(stream: BodyStream<S>) -> Self {
|
||||||
AnyBody::from_message(s)
|
AnyBody::new_boxed(stream)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A boxed message body with boxed errors.
|
/// A boxed message body with boxed errors.
|
||||||
pub struct BoxAnyBody(Pin<Box<dyn MessageBody<Error = Box<dyn StdError + 'static>>>>);
|
pub struct BoxBody(Pin<Box<dyn MessageBody<Error = Box<dyn StdError>>>>);
|
||||||
|
|
||||||
impl BoxAnyBody {
|
impl BoxBody {
|
||||||
/// Boxes a `MessageBody` and any errors it generates.
|
/// Boxes a `MessageBody` and any errors it generates.
|
||||||
pub fn from_body<B>(body: B) -> Self
|
pub fn from_body<B>(body: B) -> Self
|
||||||
where
|
where
|
||||||
|
@ -197,18 +249,18 @@ impl BoxAnyBody {
|
||||||
/// Returns a mutable pinned reference to the inner message body type.
|
/// Returns a mutable pinned reference to the inner message body type.
|
||||||
pub fn as_pin_mut(
|
pub fn as_pin_mut(
|
||||||
&mut self,
|
&mut self,
|
||||||
) -> Pin<&mut (dyn MessageBody<Error = Box<dyn StdError + 'static>>)> {
|
) -> Pin<&mut (dyn MessageBody<Error = Box<dyn StdError>>)> {
|
||||||
self.0.as_mut()
|
self.0.as_mut()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for BoxAnyBody {
|
impl fmt::Debug for BoxBody {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
f.write_str("BoxAnyBody(dyn MessageBody)")
|
f.write_str("BoxAnyBody(dyn MessageBody)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MessageBody for BoxAnyBody {
|
impl MessageBody for BoxBody {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn size(&self) -> BodySize {
|
fn size(&self) -> BodySize {
|
||||||
|
@ -225,3 +277,52 @@ impl MessageBody for BoxAnyBody {
|
||||||
.map_err(|err| Error::new_body().with_cause(err))
|
.map_err(|err| Error::new_body().with_cause(err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::marker::PhantomPinned;
|
||||||
|
|
||||||
|
use static_assertions::{assert_impl_all, assert_not_impl_all};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use crate::body::to_bytes;
|
||||||
|
|
||||||
|
struct PinType(PhantomPinned);
|
||||||
|
|
||||||
|
impl MessageBody for PinType {
|
||||||
|
type Error = crate::Error;
|
||||||
|
|
||||||
|
fn size(&self) -> BodySize {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn poll_next(
|
||||||
|
self: Pin<&mut Self>,
|
||||||
|
_cx: &mut Context<'_>,
|
||||||
|
) -> Poll<Option<Result<Bytes, Self::Error>>> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_impl_all!(AnyBody<()>: MessageBody, fmt::Debug, Send, Sync, Unpin);
|
||||||
|
assert_impl_all!(AnyBody<AnyBody<()>>: MessageBody, fmt::Debug, Send, Sync, Unpin);
|
||||||
|
assert_impl_all!(AnyBody<Bytes>: MessageBody, fmt::Debug, Send, Sync, Unpin);
|
||||||
|
assert_impl_all!(AnyBody: MessageBody, fmt::Debug, Unpin);
|
||||||
|
assert_impl_all!(BoxBody: MessageBody, fmt::Debug, Unpin);
|
||||||
|
assert_impl_all!(AnyBody<PinType>: MessageBody);
|
||||||
|
|
||||||
|
assert_not_impl_all!(AnyBody: Send, Sync, Unpin);
|
||||||
|
assert_not_impl_all!(BoxBody: Send, Sync, Unpin);
|
||||||
|
assert_not_impl_all!(AnyBody<PinType>: Send, Sync, Unpin);
|
||||||
|
|
||||||
|
#[actix_rt::test]
|
||||||
|
async fn nested_boxed_body() {
|
||||||
|
let body = AnyBody::copy_from_slice(&[1, 2, 3]);
|
||||||
|
let boxed_body = BoxBody::from_body(BoxBody::from_body(body));
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
to_bytes(boxed_body).await.unwrap(),
|
||||||
|
Bytes::from(vec![1, 2, 3]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -75,10 +75,22 @@ mod tests {
|
||||||
use derive_more::{Display, Error};
|
use derive_more::{Display, Error};
|
||||||
use futures_core::ready;
|
use futures_core::ready;
|
||||||
use futures_util::{stream, FutureExt as _};
|
use futures_util::{stream, FutureExt as _};
|
||||||
|
use static_assertions::{assert_impl_all, assert_not_impl_all};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::body::to_bytes;
|
use crate::body::to_bytes;
|
||||||
|
|
||||||
|
assert_impl_all!(BodyStream<stream::Empty<Result<Bytes, crate::Error>>>: MessageBody);
|
||||||
|
assert_impl_all!(BodyStream<stream::Empty<Result<Bytes, &'static str>>>: MessageBody);
|
||||||
|
assert_impl_all!(BodyStream<stream::Repeat<Result<Bytes, &'static str>>>: MessageBody);
|
||||||
|
assert_impl_all!(BodyStream<stream::Empty<Result<Bytes, Infallible>>>: MessageBody);
|
||||||
|
assert_impl_all!(BodyStream<stream::Repeat<Result<Bytes, Infallible>>>: MessageBody);
|
||||||
|
|
||||||
|
assert_not_impl_all!(BodyStream<stream::Empty<Bytes>>: MessageBody);
|
||||||
|
assert_not_impl_all!(BodyStream<stream::Repeat<Bytes>>: MessageBody);
|
||||||
|
// crate::Error is not Clone
|
||||||
|
assert_not_impl_all!(BodyStream<stream::Repeat<Result<Bytes, crate::Error>>>: MessageBody);
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn skips_empty_chunks() {
|
async fn skips_empty_chunks() {
|
||||||
let body = BodyStream::new(stream::iter(
|
let body = BodyStream::new(stream::iter(
|
||||||
|
@ -124,6 +136,30 @@ mod tests {
|
||||||
assert!(matches!(to_bytes(body).await, Err(StreamErr)));
|
assert!(matches!(to_bytes(body).await, Err(StreamErr)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[actix_rt::test]
|
||||||
|
async fn stream_string_error() {
|
||||||
|
// `&'static str` does not impl `Error`
|
||||||
|
// but it does impl `Into<Box<dyn Error>>`
|
||||||
|
|
||||||
|
let body = BodyStream::new(stream::once(async { Err("stringy error") }));
|
||||||
|
assert!(matches!(to_bytes(body).await, Err("stringy error")));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[actix_rt::test]
|
||||||
|
async fn stream_boxed_error() {
|
||||||
|
// `Box<dyn Error>` does not impl `Error`
|
||||||
|
// but it does impl `Into<Box<dyn Error>>`
|
||||||
|
|
||||||
|
let body = BodyStream::new(stream::once(async {
|
||||||
|
Err(Box::<dyn StdError>::from("stringy error"))
|
||||||
|
}));
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
to_bytes(body).await.unwrap_err().to_string(),
|
||||||
|
"stringy error"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn stream_delayed_error() {
|
async fn stream_delayed_error() {
|
||||||
let body =
|
let body =
|
||||||
|
|
|
@ -31,7 +31,7 @@ impl MessageBody for () {
|
||||||
type Error = Infallible;
|
type Error = Infallible;
|
||||||
|
|
||||||
fn size(&self) -> BodySize {
|
fn size(&self) -> BodySize {
|
||||||
BodySize::Empty
|
BodySize::Sized(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll_next(
|
fn poll_next(
|
||||||
|
|
|
@ -11,15 +11,14 @@ use futures_core::ready;
|
||||||
mod body;
|
mod body;
|
||||||
mod body_stream;
|
mod body_stream;
|
||||||
mod message_body;
|
mod message_body;
|
||||||
mod response_body;
|
|
||||||
mod size;
|
mod size;
|
||||||
mod sized_stream;
|
mod sized_stream;
|
||||||
|
|
||||||
pub use self::body::{AnyBody, Body, BoxAnyBody};
|
#[allow(deprecated)]
|
||||||
|
pub use self::body::{AnyBody, Body, BoxBody};
|
||||||
pub use self::body_stream::BodyStream;
|
pub use self::body_stream::BodyStream;
|
||||||
pub use self::message_body::MessageBody;
|
pub use self::message_body::MessageBody;
|
||||||
pub(crate) use self::message_body::MessageBodyMapErr;
|
pub(crate) use self::message_body::MessageBodyMapErr;
|
||||||
pub use self::response_body::ResponseBody;
|
|
||||||
pub use self::size::BodySize;
|
pub use self::size::BodySize;
|
||||||
pub use self::sized_stream::SizedStream;
|
pub use self::sized_stream::SizedStream;
|
||||||
|
|
||||||
|
@ -33,7 +32,7 @@ pub use self::sized_stream::SizedStream;
|
||||||
/// use bytes::Bytes;
|
/// use bytes::Bytes;
|
||||||
///
|
///
|
||||||
/// # async fn test_to_bytes() {
|
/// # async fn test_to_bytes() {
|
||||||
/// let body = Body::Empty;
|
/// let body = Body::None;
|
||||||
/// let bytes = to_bytes(body).await.unwrap();
|
/// let bytes = to_bytes(body).await.unwrap();
|
||||||
/// assert!(bytes.is_empty());
|
/// assert!(bytes.is_empty());
|
||||||
///
|
///
|
||||||
|
@ -44,8 +43,9 @@ pub use self::sized_stream::SizedStream;
|
||||||
/// ```
|
/// ```
|
||||||
pub async fn to_bytes<B: MessageBody>(body: B) -> Result<Bytes, B::Error> {
|
pub async fn to_bytes<B: MessageBody>(body: B) -> Result<Bytes, B::Error> {
|
||||||
let cap = match body.size() {
|
let cap = match body.size() {
|
||||||
BodySize::None | BodySize::Empty | BodySize::Sized(0) => return Ok(Bytes::new()),
|
BodySize::None | BodySize::Sized(0) => return Ok(Bytes::new()),
|
||||||
BodySize::Sized(size) => size as usize,
|
BodySize::Sized(size) => size as usize,
|
||||||
|
// good enough first guess for chunk size
|
||||||
BodySize::Stream => 32_768,
|
BodySize::Stream => 32_768,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -77,10 +77,10 @@ mod tests {
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
impl Body {
|
impl AnyBody {
|
||||||
pub(crate) fn get_ref(&self) -> &[u8] {
|
pub(crate) fn get_ref(&self) -> &[u8] {
|
||||||
match *self {
|
match *self {
|
||||||
Body::Bytes(ref bin) => bin,
|
AnyBody::Bytes(ref bin) => bin,
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,9 +88,9 @@ mod tests {
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_static_str() {
|
async fn test_static_str() {
|
||||||
assert_eq!(Body::from("").size(), BodySize::Sized(0));
|
assert_eq!(AnyBody::from("").size(), BodySize::Sized(0));
|
||||||
assert_eq!(Body::from("test").size(), BodySize::Sized(4));
|
assert_eq!(AnyBody::from("test").size(), BodySize::Sized(4));
|
||||||
assert_eq!(Body::from("test").get_ref(), b"test");
|
assert_eq!(AnyBody::from("test").get_ref(), b"test");
|
||||||
|
|
||||||
assert_eq!("test".size(), BodySize::Sized(4));
|
assert_eq!("test".size(), BodySize::Sized(4));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -104,13 +104,16 @@ mod tests {
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_static_bytes() {
|
async fn test_static_bytes() {
|
||||||
assert_eq!(Body::from(b"test".as_ref()).size(), BodySize::Sized(4));
|
assert_eq!(AnyBody::from(b"test".as_ref()).size(), BodySize::Sized(4));
|
||||||
assert_eq!(Body::from(b"test".as_ref()).get_ref(), b"test");
|
assert_eq!(AnyBody::from(b"test".as_ref()).get_ref(), b"test");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Body::from_slice(b"test".as_ref()).size(),
|
AnyBody::copy_from_slice(b"test".as_ref()).size(),
|
||||||
BodySize::Sized(4)
|
BodySize::Sized(4)
|
||||||
);
|
);
|
||||||
assert_eq!(Body::from_slice(b"test".as_ref()).get_ref(), b"test");
|
assert_eq!(
|
||||||
|
AnyBody::copy_from_slice(b"test".as_ref()).get_ref(),
|
||||||
|
b"test"
|
||||||
|
);
|
||||||
let sb = Bytes::from(&b"test"[..]);
|
let sb = Bytes::from(&b"test"[..]);
|
||||||
pin!(sb);
|
pin!(sb);
|
||||||
|
|
||||||
|
@ -123,8 +126,8 @@ mod tests {
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_vec() {
|
async fn test_vec() {
|
||||||
assert_eq!(Body::from(Vec::from("test")).size(), BodySize::Sized(4));
|
assert_eq!(AnyBody::from(Vec::from("test")).size(), BodySize::Sized(4));
|
||||||
assert_eq!(Body::from(Vec::from("test")).get_ref(), b"test");
|
assert_eq!(AnyBody::from(Vec::from("test")).get_ref(), b"test");
|
||||||
let test_vec = Vec::from("test");
|
let test_vec = Vec::from("test");
|
||||||
pin!(test_vec);
|
pin!(test_vec);
|
||||||
|
|
||||||
|
@ -141,8 +144,8 @@ mod tests {
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_bytes() {
|
async fn test_bytes() {
|
||||||
let b = Bytes::from("test");
|
let b = Bytes::from("test");
|
||||||
assert_eq!(Body::from(b.clone()).size(), BodySize::Sized(4));
|
assert_eq!(AnyBody::from(b.clone()).size(), BodySize::Sized(4));
|
||||||
assert_eq!(Body::from(b.clone()).get_ref(), b"test");
|
assert_eq!(AnyBody::from(b.clone()).get_ref(), b"test");
|
||||||
pin!(b);
|
pin!(b);
|
||||||
|
|
||||||
assert_eq!(b.size(), BodySize::Sized(4));
|
assert_eq!(b.size(), BodySize::Sized(4));
|
||||||
|
@ -155,8 +158,8 @@ mod tests {
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_bytes_mut() {
|
async fn test_bytes_mut() {
|
||||||
let b = BytesMut::from("test");
|
let b = BytesMut::from("test");
|
||||||
assert_eq!(Body::from(b.clone()).size(), BodySize::Sized(4));
|
assert_eq!(AnyBody::from(b.clone()).size(), BodySize::Sized(4));
|
||||||
assert_eq!(Body::from(b.clone()).get_ref(), b"test");
|
assert_eq!(AnyBody::from(b.clone()).get_ref(), b"test");
|
||||||
pin!(b);
|
pin!(b);
|
||||||
|
|
||||||
assert_eq!(b.size(), BodySize::Sized(4));
|
assert_eq!(b.size(), BodySize::Sized(4));
|
||||||
|
@ -169,10 +172,10 @@ mod tests {
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_string() {
|
async fn test_string() {
|
||||||
let b = "test".to_owned();
|
let b = "test".to_owned();
|
||||||
assert_eq!(Body::from(b.clone()).size(), BodySize::Sized(4));
|
assert_eq!(AnyBody::from(b.clone()).size(), BodySize::Sized(4));
|
||||||
assert_eq!(Body::from(b.clone()).get_ref(), b"test");
|
assert_eq!(AnyBody::from(b.clone()).get_ref(), b"test");
|
||||||
assert_eq!(Body::from(&b).size(), BodySize::Sized(4));
|
assert_eq!(AnyBody::from(&b).size(), BodySize::Sized(4));
|
||||||
assert_eq!(Body::from(&b).get_ref(), b"test");
|
assert_eq!(AnyBody::from(&b).get_ref(), b"test");
|
||||||
pin!(b);
|
pin!(b);
|
||||||
|
|
||||||
assert_eq!(b.size(), BodySize::Sized(4));
|
assert_eq!(b.size(), BodySize::Sized(4));
|
||||||
|
@ -184,7 +187,7 @@ mod tests {
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_unit() {
|
async fn test_unit() {
|
||||||
assert_eq!(().size(), BodySize::Empty);
|
assert_eq!(().size(), BodySize::Sized(0));
|
||||||
assert!(poll_fn(|cx| Pin::new(&mut ()).poll_next(cx))
|
assert!(poll_fn(|cx| Pin::new(&mut ()).poll_next(cx))
|
||||||
.await
|
.await
|
||||||
.is_none());
|
.is_none());
|
||||||
|
@ -194,40 +197,43 @@ mod tests {
|
||||||
async fn test_box_and_pin() {
|
async fn test_box_and_pin() {
|
||||||
let val = Box::new(());
|
let val = Box::new(());
|
||||||
pin!(val);
|
pin!(val);
|
||||||
assert_eq!(val.size(), BodySize::Empty);
|
assert_eq!(val.size(), BodySize::Sized(0));
|
||||||
assert!(poll_fn(|cx| val.as_mut().poll_next(cx)).await.is_none());
|
assert!(poll_fn(|cx| val.as_mut().poll_next(cx)).await.is_none());
|
||||||
|
|
||||||
let mut val = Box::pin(());
|
let mut val = Box::pin(());
|
||||||
assert_eq!(val.size(), BodySize::Empty);
|
assert_eq!(val.size(), BodySize::Sized(0));
|
||||||
assert!(poll_fn(|cx| val.as_mut().poll_next(cx)).await.is_none());
|
assert!(poll_fn(|cx| val.as_mut().poll_next(cx)).await.is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_body_eq() {
|
async fn test_body_eq() {
|
||||||
assert!(
|
assert!(
|
||||||
Body::Bytes(Bytes::from_static(b"1"))
|
AnyBody::Bytes(Bytes::from_static(b"1"))
|
||||||
== Body::Bytes(Bytes::from_static(b"1"))
|
== AnyBody::Bytes(Bytes::from_static(b"1"))
|
||||||
);
|
);
|
||||||
assert!(Body::Bytes(Bytes::from_static(b"1")) != Body::None);
|
assert!(AnyBody::Bytes(Bytes::from_static(b"1")) != AnyBody::None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_body_debug() {
|
async fn test_body_debug() {
|
||||||
assert!(format!("{:?}", Body::None).contains("Body::None"));
|
assert!(format!("{:?}", AnyBody::<BoxBody>::None).contains("Body::None"));
|
||||||
assert!(format!("{:?}", Body::Empty).contains("Body::Empty"));
|
assert!(format!("{:?}", AnyBody::from(Bytes::from_static(b"1"))).contains('1'));
|
||||||
assert!(format!("{:?}", Body::Bytes(Bytes::from_static(b"1"))).contains('1'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_serde_json() {
|
async fn test_serde_json() {
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Body::from(serde_json::to_vec(&Value::String("test".to_owned())).unwrap())
|
AnyBody::from(
|
||||||
|
serde_json::to_vec(&Value::String("test".to_owned())).unwrap()
|
||||||
|
)
|
||||||
.size(),
|
.size(),
|
||||||
BodySize::Sized(6)
|
BodySize::Sized(6)
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Body::from(serde_json::to_vec(&json!({"test-key":"test-value"})).unwrap())
|
AnyBody::from(
|
||||||
|
serde_json::to_vec(&json!({"test-key":"test-value"})).unwrap()
|
||||||
|
)
|
||||||
.size(),
|
.size(),
|
||||||
BodySize::Sized(25)
|
BodySize::Sized(25)
|
||||||
);
|
);
|
||||||
|
@ -252,11 +258,11 @@ mod tests {
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_to_bytes() {
|
async fn test_to_bytes() {
|
||||||
let body = Body::Empty;
|
let body = AnyBody::empty();
|
||||||
let bytes = to_bytes(body).await.unwrap();
|
let bytes = to_bytes(body).await.unwrap();
|
||||||
assert!(bytes.is_empty());
|
assert!(bytes.is_empty());
|
||||||
|
|
||||||
let body = Body::Bytes(Bytes::from_static(b"123"));
|
let body = AnyBody::copy_from_slice(b"123");
|
||||||
let bytes = to_bytes(body).await.unwrap();
|
let bytes = to_bytes(body).await.unwrap();
|
||||||
assert_eq!(bytes, b"123"[..]);
|
assert_eq!(bytes, b"123"[..]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,84 +0,0 @@
|
||||||
use std::{
|
|
||||||
mem,
|
|
||||||
pin::Pin,
|
|
||||||
task::{Context, Poll},
|
|
||||||
};
|
|
||||||
|
|
||||||
use bytes::Bytes;
|
|
||||||
use futures_core::Stream;
|
|
||||||
use pin_project::pin_project;
|
|
||||||
|
|
||||||
use crate::error::Error;
|
|
||||||
|
|
||||||
use super::{Body, BodySize, MessageBody};
|
|
||||||
|
|
||||||
#[pin_project(project = ResponseBodyProj)]
|
|
||||||
pub enum ResponseBody<B> {
|
|
||||||
Body(#[pin] B),
|
|
||||||
Other(Body),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ResponseBody<Body> {
|
|
||||||
pub fn into_body<B>(self) -> ResponseBody<B> {
|
|
||||||
match self {
|
|
||||||
ResponseBody::Body(b) => ResponseBody::Other(b),
|
|
||||||
ResponseBody::Other(b) => ResponseBody::Other(b),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<B> ResponseBody<B> {
|
|
||||||
pub fn take_body(&mut self) -> ResponseBody<B> {
|
|
||||||
mem::replace(self, ResponseBody::Other(Body::None))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<B: MessageBody> ResponseBody<B> {
|
|
||||||
pub fn as_ref(&self) -> Option<&B> {
|
|
||||||
if let ResponseBody::Body(ref b) = self {
|
|
||||||
Some(b)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<B> MessageBody for ResponseBody<B>
|
|
||||||
where
|
|
||||||
B: MessageBody,
|
|
||||||
B::Error: Into<Error>,
|
|
||||||
{
|
|
||||||
type Error = Error;
|
|
||||||
|
|
||||||
fn size(&self) -> BodySize {
|
|
||||||
match self {
|
|
||||||
ResponseBody::Body(ref body) => body.size(),
|
|
||||||
ResponseBody::Other(ref body) => body.size(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn poll_next(
|
|
||||||
self: Pin<&mut Self>,
|
|
||||||
cx: &mut Context<'_>,
|
|
||||||
) -> Poll<Option<Result<Bytes, Self::Error>>> {
|
|
||||||
Stream::poll_next(self, cx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<B> Stream for ResponseBody<B>
|
|
||||||
where
|
|
||||||
B: MessageBody,
|
|
||||||
B::Error: Into<Error>,
|
|
||||||
{
|
|
||||||
type Item = Result<Bytes, Error>;
|
|
||||||
|
|
||||||
fn poll_next(
|
|
||||||
self: Pin<&mut Self>,
|
|
||||||
cx: &mut Context<'_>,
|
|
||||||
) -> Poll<Option<Self::Item>> {
|
|
||||||
match self.project() {
|
|
||||||
ResponseBodyProj::Body(body) => body.poll_next(cx).map_err(Into::into),
|
|
||||||
ResponseBodyProj::Other(body) => Pin::new(body).poll_next(cx),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -6,14 +6,9 @@ pub enum BodySize {
|
||||||
/// Will skip writing Content-Length header.
|
/// Will skip writing Content-Length header.
|
||||||
None,
|
None,
|
||||||
|
|
||||||
/// Zero size body.
|
|
||||||
///
|
|
||||||
/// Will write `Content-Length: 0` header.
|
|
||||||
Empty,
|
|
||||||
|
|
||||||
/// Known size body.
|
/// Known size body.
|
||||||
///
|
///
|
||||||
/// Will write `Content-Length: N` header. `Sized(0)` is treated the same as `Empty`.
|
/// Will write `Content-Length: N` header.
|
||||||
Sized(u64),
|
Sized(u64),
|
||||||
|
|
||||||
/// Unknown size body.
|
/// Unknown size body.
|
||||||
|
@ -25,16 +20,17 @@ pub enum BodySize {
|
||||||
impl BodySize {
|
impl BodySize {
|
||||||
/// Returns true if size hint indicates no or empty body.
|
/// Returns true if size hint indicates no or empty body.
|
||||||
///
|
///
|
||||||
|
/// Streams will return false because it cannot be known without reading the stream.
|
||||||
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use actix_http::body::BodySize;
|
/// # use actix_http::body::BodySize;
|
||||||
/// assert!(BodySize::None.is_eof());
|
/// assert!(BodySize::None.is_eof());
|
||||||
/// assert!(BodySize::Empty.is_eof());
|
|
||||||
/// assert!(BodySize::Sized(0).is_eof());
|
/// assert!(BodySize::Sized(0).is_eof());
|
||||||
///
|
///
|
||||||
/// assert!(!BodySize::Sized(64).is_eof());
|
/// assert!(!BodySize::Sized(64).is_eof());
|
||||||
/// assert!(!BodySize::Stream.is_eof());
|
/// assert!(!BodySize::Stream.is_eof());
|
||||||
/// ```
|
/// ```
|
||||||
pub fn is_eof(&self) -> bool {
|
pub fn is_eof(&self) -> bool {
|
||||||
matches!(self, BodySize::None | BodySize::Empty | BodySize::Sized(0))
|
matches!(self, BodySize::None | BodySize::Sized(0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,10 +72,22 @@ mod tests {
|
||||||
use actix_rt::pin;
|
use actix_rt::pin;
|
||||||
use actix_utils::future::poll_fn;
|
use actix_utils::future::poll_fn;
|
||||||
use futures_util::stream;
|
use futures_util::stream;
|
||||||
|
use static_assertions::{assert_impl_all, assert_not_impl_all};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::body::to_bytes;
|
use crate::body::to_bytes;
|
||||||
|
|
||||||
|
assert_impl_all!(SizedStream<stream::Empty<Result<Bytes, crate::Error>>>: MessageBody);
|
||||||
|
assert_impl_all!(SizedStream<stream::Empty<Result<Bytes, &'static str>>>: MessageBody);
|
||||||
|
assert_impl_all!(SizedStream<stream::Repeat<Result<Bytes, &'static str>>>: MessageBody);
|
||||||
|
assert_impl_all!(SizedStream<stream::Empty<Result<Bytes, Infallible>>>: MessageBody);
|
||||||
|
assert_impl_all!(SizedStream<stream::Repeat<Result<Bytes, Infallible>>>: MessageBody);
|
||||||
|
|
||||||
|
assert_not_impl_all!(SizedStream<stream::Empty<Bytes>>: MessageBody);
|
||||||
|
assert_not_impl_all!(SizedStream<stream::Repeat<Bytes>>: MessageBody);
|
||||||
|
// crate::Error is not Clone
|
||||||
|
assert_not_impl_all!(SizedStream<stream::Repeat<Result<Bytes, crate::Error>>>: MessageBody);
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn skips_empty_chunks() {
|
async fn skips_empty_chunks() {
|
||||||
let body = SizedStream::new(
|
let body = SizedStream::new(
|
||||||
|
@ -119,4 +131,37 @@ mod tests {
|
||||||
|
|
||||||
assert_eq!(to_bytes(body).await.ok(), Some(Bytes::from("12")));
|
assert_eq!(to_bytes(body).await.ok(), Some(Bytes::from("12")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[actix_rt::test]
|
||||||
|
async fn stream_string_error() {
|
||||||
|
// `&'static str` does not impl `Error`
|
||||||
|
// but it does impl `Into<Box<dyn Error>>`
|
||||||
|
|
||||||
|
let body = SizedStream::new(0, stream::once(async { Err("stringy error") }));
|
||||||
|
assert_eq!(to_bytes(body).await, Ok(Bytes::new()));
|
||||||
|
|
||||||
|
let body = SizedStream::new(1, stream::once(async { Err("stringy error") }));
|
||||||
|
assert!(matches!(to_bytes(body).await, Err("stringy error")));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[actix_rt::test]
|
||||||
|
async fn stream_boxed_error() {
|
||||||
|
// `Box<dyn Error>` does not impl `Error`
|
||||||
|
// but it does impl `Into<Box<dyn Error>>`
|
||||||
|
|
||||||
|
let body = SizedStream::new(
|
||||||
|
0,
|
||||||
|
stream::once(async { Err(Box::<dyn StdError>::from("stringy error")) }),
|
||||||
|
);
|
||||||
|
assert_eq!(to_bytes(body).await.unwrap(), Bytes::new());
|
||||||
|
|
||||||
|
let body = SizedStream::new(
|
||||||
|
1,
|
||||||
|
stream::once(async { Err(Box::<dyn StdError>::from("stringy error")) }),
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
to_bytes(body).await.unwrap_err().to_string(),
|
||||||
|
"stringy error"
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ use flate2::write::{GzEncoder, ZlibEncoder};
|
||||||
use zstd::stream::write::Encoder as ZstdEncoder;
|
use zstd::stream::write::Encoder as ZstdEncoder;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
body::{Body, BodySize, BoxAnyBody, MessageBody, ResponseBody},
|
body::{AnyBody, BodySize, MessageBody},
|
||||||
http::{
|
http::{
|
||||||
header::{ContentEncoding, CONTENT_ENCODING},
|
header::{ContentEncoding, CONTENT_ENCODING},
|
||||||
HeaderValue, StatusCode,
|
HeaderValue, StatusCode,
|
||||||
|
@ -50,8 +50,8 @@ impl<B: MessageBody> Encoder<B> {
|
||||||
pub fn response(
|
pub fn response(
|
||||||
encoding: ContentEncoding,
|
encoding: ContentEncoding,
|
||||||
head: &mut ResponseHead,
|
head: &mut ResponseHead,
|
||||||
body: ResponseBody<B>,
|
body: AnyBody<B>,
|
||||||
) -> ResponseBody<Encoder<B>> {
|
) -> AnyBody<Encoder<B>> {
|
||||||
let can_encode = !(head.headers().contains_key(&CONTENT_ENCODING)
|
let can_encode = !(head.headers().contains_key(&CONTENT_ENCODING)
|
||||||
|| head.status == StatusCode::SWITCHING_PROTOCOLS
|
|| head.status == StatusCode::SWITCHING_PROTOCOLS
|
||||||
|| head.status == StatusCode::NO_CONTENT
|
|| head.status == StatusCode::NO_CONTENT
|
||||||
|
@ -59,19 +59,15 @@ impl<B: MessageBody> Encoder<B> {
|
||||||
|| encoding == ContentEncoding::Auto);
|
|| encoding == ContentEncoding::Auto);
|
||||||
|
|
||||||
let body = match body {
|
let body = match body {
|
||||||
ResponseBody::Other(b) => match b {
|
AnyBody::None => return AnyBody::None,
|
||||||
Body::None => return ResponseBody::Other(Body::None),
|
AnyBody::Bytes(buf) => {
|
||||||
Body::Empty => return ResponseBody::Other(Body::Empty),
|
|
||||||
Body::Bytes(buf) => {
|
|
||||||
if can_encode {
|
if can_encode {
|
||||||
EncoderBody::Bytes(buf)
|
EncoderBody::Bytes(buf)
|
||||||
} else {
|
} else {
|
||||||
return ResponseBody::Other(Body::Bytes(buf));
|
return AnyBody::Bytes(buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Body::Message(stream) => EncoderBody::BoxedStream(stream),
|
AnyBody::Body(body) => EncoderBody::Stream(body),
|
||||||
},
|
|
||||||
ResponseBody::Body(stream) => EncoderBody::Stream(stream),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if can_encode {
|
if can_encode {
|
||||||
|
@ -79,7 +75,8 @@ impl<B: MessageBody> Encoder<B> {
|
||||||
if let Some(enc) = ContentEncoder::encoder(encoding) {
|
if let Some(enc) = ContentEncoder::encoder(encoding) {
|
||||||
update_head(encoding, head);
|
update_head(encoding, head);
|
||||||
head.no_chunking(false);
|
head.no_chunking(false);
|
||||||
return ResponseBody::Body(Encoder {
|
|
||||||
|
return AnyBody::Body(Encoder {
|
||||||
body,
|
body,
|
||||||
eof: false,
|
eof: false,
|
||||||
fut: None,
|
fut: None,
|
||||||
|
@ -88,7 +85,7 @@ impl<B: MessageBody> Encoder<B> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ResponseBody::Body(Encoder {
|
AnyBody::Body(Encoder {
|
||||||
body,
|
body,
|
||||||
eof: false,
|
eof: false,
|
||||||
fut: None,
|
fut: None,
|
||||||
|
@ -101,7 +98,6 @@ impl<B: MessageBody> Encoder<B> {
|
||||||
enum EncoderBody<B> {
|
enum EncoderBody<B> {
|
||||||
Bytes(Bytes),
|
Bytes(Bytes),
|
||||||
Stream(#[pin] B),
|
Stream(#[pin] B),
|
||||||
BoxedStream(BoxAnyBody),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B> MessageBody for EncoderBody<B>
|
impl<B> MessageBody for EncoderBody<B>
|
||||||
|
@ -114,7 +110,6 @@ where
|
||||||
match self {
|
match self {
|
||||||
EncoderBody::Bytes(ref b) => b.size(),
|
EncoderBody::Bytes(ref b) => b.size(),
|
||||||
EncoderBody::Stream(ref b) => b.size(),
|
EncoderBody::Stream(ref b) => b.size(),
|
||||||
EncoderBody::BoxedStream(ref b) => b.size(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,9 +126,6 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EncoderBodyProj::Stream(b) => b.poll_next(cx).map_err(EncoderError::Body),
|
EncoderBodyProj::Stream(b) => b.poll_next(cx).map_err(EncoderError::Body),
|
||||||
EncoderBodyProj::BoxedStream(ref mut b) => {
|
|
||||||
b.as_pin_mut().poll_next(cx).map_err(EncoderError::Boxed)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -349,9 +341,6 @@ pub enum EncoderError<E> {
|
||||||
#[display(fmt = "body")]
|
#[display(fmt = "body")]
|
||||||
Body(E),
|
Body(E),
|
||||||
|
|
||||||
#[display(fmt = "boxed")]
|
|
||||||
Boxed(Box<dyn StdError>),
|
|
||||||
|
|
||||||
#[display(fmt = "blocking")]
|
#[display(fmt = "blocking")]
|
||||||
Blocking(BlockingError),
|
Blocking(BlockingError),
|
||||||
|
|
||||||
|
@ -363,7 +352,6 @@ impl<E: StdError + 'static> StdError for EncoderError<E> {
|
||||||
fn source(&self) -> Option<&(dyn StdError + 'static)> {
|
fn source(&self) -> Option<&(dyn StdError + 'static)> {
|
||||||
match self {
|
match self {
|
||||||
EncoderError::Body(err) => Some(err),
|
EncoderError::Body(err) => Some(err),
|
||||||
EncoderError::Boxed(err) => Some(&**err),
|
|
||||||
EncoderError::Blocking(err) => Some(err),
|
EncoderError::Blocking(err) => Some(err),
|
||||||
EncoderError::Io(err) => Some(err),
|
EncoderError::Io(err) => Some(err),
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,10 +5,7 @@ use std::{error::Error as StdError, fmt, io, str::Utf8Error, string::FromUtf8Err
|
||||||
use derive_more::{Display, Error, From};
|
use derive_more::{Display, Error, From};
|
||||||
use http::{uri::InvalidUri, StatusCode};
|
use http::{uri::InvalidUri, StatusCode};
|
||||||
|
|
||||||
use crate::{
|
use crate::{body::AnyBody, ws, Response};
|
||||||
body::{AnyBody, Body},
|
|
||||||
ws, Response,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub use http::Error as HttpError;
|
pub use http::Error as HttpError;
|
||||||
|
|
||||||
|
@ -29,6 +26,11 @@ impl Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn with_cause(mut self, cause: impl Into<Box<dyn StdError>>) -> Self {
|
||||||
|
self.inner.cause = Some(cause.into());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn new_http() -> Self {
|
pub(crate) fn new_http() -> Self {
|
||||||
Self::new(Kind::Http)
|
Self::new(Kind::Http)
|
||||||
}
|
}
|
||||||
|
@ -49,14 +51,12 @@ impl Error {
|
||||||
Self::new(Kind::SendResponse)
|
Self::new(Kind::SendResponse)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: remove allow
|
#[allow(unused)] // reserved for future use (TODO: remove allow when being used)
|
||||||
#[allow(dead_code)]
|
|
||||||
pub(crate) fn new_io() -> Self {
|
pub(crate) fn new_io() -> Self {
|
||||||
Self::new(Kind::Io)
|
Self::new(Kind::Io)
|
||||||
}
|
}
|
||||||
|
|
||||||
// used in encoder behind feature flag so ignore unused warning
|
#[allow(unused)] // used in encoder behind feature flag so ignore unused warning
|
||||||
#[allow(unused)]
|
|
||||||
pub(crate) fn new_encoder() -> Self {
|
pub(crate) fn new_encoder() -> Self {
|
||||||
Self::new(Kind::Encoder)
|
Self::new(Kind::Encoder)
|
||||||
}
|
}
|
||||||
|
@ -64,11 +64,6 @@ impl Error {
|
||||||
pub(crate) fn new_ws() -> Self {
|
pub(crate) fn new_ws() -> Self {
|
||||||
Self::new(Kind::Ws)
|
Self::new(Kind::Ws)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn with_cause(mut self, cause: impl Into<Box<dyn StdError>>) -> Self {
|
|
||||||
self.inner.cause = Some(cause.into());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Error> for Response<AnyBody> {
|
impl From<Error> for Response<AnyBody> {
|
||||||
|
@ -78,12 +73,12 @@ impl From<Error> for Response<AnyBody> {
|
||||||
_ => StatusCode::INTERNAL_SERVER_ERROR,
|
_ => StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
};
|
};
|
||||||
|
|
||||||
Response::new(status_code).set_body(Body::from(err.to_string()))
|
Response::new(status_code).set_body(AnyBody::from(err.to_string()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Display)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Display)]
|
||||||
pub enum Kind {
|
pub(crate) enum Kind {
|
||||||
#[display(fmt = "error processing HTTP")]
|
#[display(fmt = "error processing HTTP")]
|
||||||
Http,
|
Http,
|
||||||
|
|
||||||
|
|
|
@ -325,7 +325,7 @@ where
|
||||||
) -> Result<(), DispatchError> {
|
) -> Result<(), DispatchError> {
|
||||||
let size = self.as_mut().send_response_inner(message, &body)?;
|
let size = self.as_mut().send_response_inner(message, &body)?;
|
||||||
let state = match size {
|
let state = match size {
|
||||||
BodySize::None | BodySize::Empty => State::None,
|
BodySize::None | BodySize::Sized(0) => State::None,
|
||||||
_ => State::SendPayload(body),
|
_ => State::SendPayload(body),
|
||||||
};
|
};
|
||||||
self.project().state.set(state);
|
self.project().state.set(state);
|
||||||
|
@ -339,7 +339,7 @@ where
|
||||||
) -> Result<(), DispatchError> {
|
) -> Result<(), DispatchError> {
|
||||||
let size = self.as_mut().send_response_inner(message, &body)?;
|
let size = self.as_mut().send_response_inner(message, &body)?;
|
||||||
let state = match size {
|
let state = match size {
|
||||||
BodySize::None | BodySize::Empty => State::None,
|
BodySize::None | BodySize::Sized(0) => State::None,
|
||||||
_ => State::SendErrorPayload(body),
|
_ => State::SendErrorPayload(body),
|
||||||
};
|
};
|
||||||
self.project().state.set(state);
|
self.project().state.set(state);
|
||||||
|
@ -380,7 +380,7 @@ where
|
||||||
// send_response would update InnerDispatcher state to SendPayload or
|
// send_response would update InnerDispatcher state to SendPayload or
|
||||||
// None(If response body is empty).
|
// None(If response body is empty).
|
||||||
// continue loop to poll it.
|
// continue loop to poll it.
|
||||||
self.as_mut().send_error_response(res, AnyBody::Empty)?;
|
self.as_mut().send_error_response(res, AnyBody::empty())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// return with upgrade request and poll it exclusively.
|
// return with upgrade request and poll it exclusively.
|
||||||
|
@ -772,7 +772,7 @@ where
|
||||||
trace!("Slow request timeout");
|
trace!("Slow request timeout");
|
||||||
let _ = self.as_mut().send_error_response(
|
let _ = self.as_mut().send_error_response(
|
||||||
Response::with_body(StatusCode::REQUEST_TIMEOUT, ()),
|
Response::with_body(StatusCode::REQUEST_TIMEOUT, ()),
|
||||||
AnyBody::Empty,
|
AnyBody::empty(),
|
||||||
);
|
);
|
||||||
this = self.project();
|
this = self.project();
|
||||||
this.flags.insert(Flags::STARTED | Flags::SHUTDOWN);
|
this.flags.insert(Flags::STARTED | Flags::SHUTDOWN);
|
||||||
|
@ -1077,7 +1077,7 @@ mod tests {
|
||||||
fn_service(|req: Request| {
|
fn_service(|req: Request| {
|
||||||
let path = req.path().as_bytes();
|
let path = req.path().as_bytes();
|
||||||
ready(Ok::<_, Error>(
|
ready(Ok::<_, Error>(
|
||||||
Response::ok().set_body(AnyBody::from_slice(path)),
|
Response::ok().set_body(AnyBody::copy_from_slice(path)),
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,13 +93,10 @@ pub(crate) trait MessageType: Sized {
|
||||||
dst.put_slice(b"\r\n");
|
dst.put_slice(b"\r\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BodySize::Empty => {
|
BodySize::Sized(0) if camel_case => {
|
||||||
if camel_case {
|
dst.put_slice(b"\r\nContent-Length: 0\r\n")
|
||||||
dst.put_slice(b"\r\nContent-Length: 0\r\n");
|
|
||||||
} else {
|
|
||||||
dst.put_slice(b"\r\ncontent-length: 0\r\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
BodySize::Sized(0) => dst.put_slice(b"\r\ncontent-length: 0\r\n"),
|
||||||
BodySize::Sized(len) => helpers::write_content_length(len, dst),
|
BodySize::Sized(len) => helpers::write_content_length(len, dst),
|
||||||
BodySize::None => dst.put_slice(b"\r\n"),
|
BodySize::None => dst.put_slice(b"\r\n"),
|
||||||
}
|
}
|
||||||
|
@ -336,7 +333,7 @@ impl<T: MessageType> MessageEncoder<T> {
|
||||||
// transfer encoding
|
// transfer encoding
|
||||||
if !head {
|
if !head {
|
||||||
self.te = match length {
|
self.te = match length {
|
||||||
BodySize::Empty => TransferEncoding::empty(),
|
BodySize::Sized(0) => TransferEncoding::empty(),
|
||||||
BodySize::Sized(len) => TransferEncoding::length(len),
|
BodySize::Sized(len) => TransferEncoding::length(len),
|
||||||
BodySize::Stream => {
|
BodySize::Stream => {
|
||||||
if message.chunked() && !stream {
|
if message.chunked() && !stream {
|
||||||
|
@ -553,7 +550,7 @@ mod tests {
|
||||||
let _ = head.encode_headers(
|
let _ = head.encode_headers(
|
||||||
&mut bytes,
|
&mut bytes,
|
||||||
Version::HTTP_11,
|
Version::HTTP_11,
|
||||||
BodySize::Empty,
|
BodySize::Sized(0),
|
||||||
ConnectionType::Close,
|
ConnectionType::Close,
|
||||||
&ServiceConfig::default(),
|
&ServiceConfig::default(),
|
||||||
);
|
);
|
||||||
|
@ -624,7 +621,7 @@ mod tests {
|
||||||
let _ = head.encode_headers(
|
let _ = head.encode_headers(
|
||||||
&mut bytes,
|
&mut bytes,
|
||||||
Version::HTTP_11,
|
Version::HTTP_11,
|
||||||
BodySize::Empty,
|
BodySize::Sized(0),
|
||||||
ConnectionType::Close,
|
ConnectionType::Close,
|
||||||
&ServiceConfig::default(),
|
&ServiceConfig::default(),
|
||||||
);
|
);
|
||||||
|
|
|
@ -285,9 +285,11 @@ fn prepare_response(
|
||||||
|
|
||||||
let _ = match size {
|
let _ = match size {
|
||||||
BodySize::None | BodySize::Stream => None,
|
BodySize::None | BodySize::Stream => None,
|
||||||
BodySize::Empty => res
|
|
||||||
|
BodySize::Sized(0) => res
|
||||||
.headers_mut()
|
.headers_mut()
|
||||||
.insert(CONTENT_LENGTH, HeaderValue::from_static("0")),
|
.insert(CONTENT_LENGTH, HeaderValue::from_static("0")),
|
||||||
|
|
||||||
BodySize::Sized(len) => {
|
BodySize::Sized(len) => {
|
||||||
let mut buf = itoa::Buffer::new();
|
let mut buf = itoa::Buffer::new();
|
||||||
|
|
||||||
|
|
|
@ -195,6 +195,7 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
// copy of encoding from actix-web headers
|
// copy of encoding from actix-web headers
|
||||||
|
#[allow(clippy::enum_variant_names)] // allow Encoding prefix on EncodingExt
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
pub enum Encoding {
|
pub enum Encoding {
|
||||||
Chunked,
|
Chunked,
|
||||||
|
|
|
@ -28,7 +28,7 @@ impl Response<AnyBody> {
|
||||||
pub fn new(status: StatusCode) -> Self {
|
pub fn new(status: StatusCode) -> Self {
|
||||||
Response {
|
Response {
|
||||||
head: BoxedResponseHead::new(status),
|
head: BoxedResponseHead::new(status),
|
||||||
body: AnyBody::Empty,
|
body: AnyBody::empty(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -262,7 +262,7 @@ impl ResponseBuilder {
|
||||||
S: Stream<Item = Result<Bytes, E>> + 'static,
|
S: Stream<Item = Result<Bytes, E>> + 'static,
|
||||||
E: Into<Box<dyn StdError>> + 'static,
|
E: Into<Box<dyn StdError>> + 'static,
|
||||||
{
|
{
|
||||||
self.body(AnyBody::from_message(BodyStream::new(stream)))
|
self.body(AnyBody::new_boxed(BodyStream::new(stream)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate response with an empty body.
|
/// Generate response with an empty body.
|
||||||
|
@ -270,7 +270,7 @@ impl ResponseBuilder {
|
||||||
/// This `ResponseBuilder` will be left in a useless state.
|
/// This `ResponseBuilder` will be left in a useless state.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn finish(&mut self) -> Response<AnyBody> {
|
pub fn finish(&mut self) -> Response<AnyBody> {
|
||||||
self.body(AnyBody::Empty)
|
self.body(AnyBody::empty())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create an owned `ResponseBuilder`, leaving the original in a useless state.
|
/// Create an owned `ResponseBuilder`, leaving the original in a useless state.
|
||||||
|
@ -357,7 +357,7 @@ impl fmt::Debug for ResponseBuilder {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::body::Body;
|
use crate::body::AnyBody;
|
||||||
use crate::http::header::{HeaderName, HeaderValue, CONTENT_TYPE};
|
use crate::http::header::{HeaderName, HeaderValue, CONTENT_TYPE};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -390,13 +390,13 @@ mod tests {
|
||||||
fn test_content_type() {
|
fn test_content_type() {
|
||||||
let resp = Response::build(StatusCode::OK)
|
let resp = Response::build(StatusCode::OK)
|
||||||
.content_type("text/plain")
|
.content_type("text/plain")
|
||||||
.body(Body::Empty);
|
.body(AnyBody::empty());
|
||||||
assert_eq!(resp.headers().get(CONTENT_TYPE).unwrap(), "text/plain")
|
assert_eq!(resp.headers().get(CONTENT_TYPE).unwrap(), "text/plain")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_into_builder() {
|
fn test_into_builder() {
|
||||||
let mut resp: Response<Body> = "test".into();
|
let mut resp: Response<AnyBody> = "test".into();
|
||||||
assert_eq!(resp.status(), StatusCode::OK);
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
|
|
||||||
resp.headers_mut().insert(
|
resp.headers_mut().insert(
|
||||||
|
|
|
@ -210,7 +210,6 @@ pub fn handshake_response(req: &RequestHead) -> ResponseBuilder {
|
||||||
|
|
||||||
Response::build(StatusCode::SWITCHING_PROTOCOLS)
|
Response::build(StatusCode::SWITCHING_PROTOCOLS)
|
||||||
.upgrade("websocket")
|
.upgrade("websocket")
|
||||||
.insert_header((header::TRANSFER_ENCODING, "chunked"))
|
|
||||||
.insert_header((
|
.insert_header((
|
||||||
header::SEC_WEBSOCKET_ACCEPT,
|
header::SEC_WEBSOCKET_ACCEPT,
|
||||||
// key is known to be header value safe ascii
|
// key is known to be header value safe ascii
|
||||||
|
|
|
@ -5,7 +5,7 @@ extern crate tls_openssl as openssl;
|
||||||
use std::{convert::Infallible, io};
|
use std::{convert::Infallible, io};
|
||||||
|
|
||||||
use actix_http::{
|
use actix_http::{
|
||||||
body::{AnyBody, Body, SizedStream},
|
body::{AnyBody, SizedStream},
|
||||||
error::PayloadError,
|
error::PayloadError,
|
||||||
http::{
|
http::{
|
||||||
header::{self, HeaderValue},
|
header::{self, HeaderValue},
|
||||||
|
@ -409,7 +409,7 @@ impl From<BadRequest> for Response<AnyBody> {
|
||||||
async fn test_h2_service_error() {
|
async fn test_h2_service_error() {
|
||||||
let mut srv = test_server(move || {
|
let mut srv = test_server(move || {
|
||||||
HttpService::build()
|
HttpService::build()
|
||||||
.h2(|_| err::<Response<Body>, _>(BadRequest))
|
.h2(|_| err::<Response<AnyBody>, _>(BadRequest))
|
||||||
.openssl(tls_config())
|
.openssl(tls_config())
|
||||||
.map_err(|_| ())
|
.map_err(|_| ())
|
||||||
})
|
})
|
||||||
|
|
|
@ -10,7 +10,7 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use actix_http::{
|
use actix_http::{
|
||||||
body::{AnyBody, Body, SizedStream},
|
body::{AnyBody, SizedStream},
|
||||||
error::PayloadError,
|
error::PayloadError,
|
||||||
http::{
|
http::{
|
||||||
header::{self, HeaderName, HeaderValue},
|
header::{self, HeaderName, HeaderValue},
|
||||||
|
@ -477,7 +477,7 @@ impl From<BadRequest> for Response<AnyBody> {
|
||||||
async fn test_h2_service_error() {
|
async fn test_h2_service_error() {
|
||||||
let mut srv = test_server(move || {
|
let mut srv = test_server(move || {
|
||||||
HttpService::build()
|
HttpService::build()
|
||||||
.h2(|_| err::<Response<Body>, _>(BadRequest))
|
.h2(|_| err::<Response<AnyBody>, _>(BadRequest))
|
||||||
.rustls(tls_config())
|
.rustls(tls_config())
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
|
@ -494,7 +494,7 @@ async fn test_h2_service_error() {
|
||||||
async fn test_h1_service_error() {
|
async fn test_h1_service_error() {
|
||||||
let mut srv = test_server(move || {
|
let mut srv = test_server(move || {
|
||||||
HttpService::build()
|
HttpService::build()
|
||||||
.h1(|_| err::<Response<Body>, _>(BadRequest))
|
.h1(|_| err::<Response<AnyBody>, _>(BadRequest))
|
||||||
.rustls(tls_config())
|
.rustls(tls_config())
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
|
|
|
@ -6,7 +6,7 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use actix_http::{
|
use actix_http::{
|
||||||
body::{AnyBody, Body, SizedStream},
|
body::{AnyBody, SizedStream},
|
||||||
header, http, Error, HttpMessage, HttpService, KeepAlive, Request, Response,
|
header, http, Error, HttpMessage, HttpService, KeepAlive, Request, Response,
|
||||||
StatusCode,
|
StatusCode,
|
||||||
};
|
};
|
||||||
|
@ -724,7 +724,7 @@ impl From<BadRequest> for Response<AnyBody> {
|
||||||
async fn test_h1_service_error() {
|
async fn test_h1_service_error() {
|
||||||
let mut srv = test_server(|| {
|
let mut srv = test_server(|| {
|
||||||
HttpService::build()
|
HttpService::build()
|
||||||
.h1(|_| err::<Response<Body>, _>(BadRequest))
|
.h1(|_| err::<Response<AnyBody>, _>(BadRequest))
|
||||||
.tcp()
|
.tcp()
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
|
|
|
@ -28,7 +28,7 @@ rustls = ["tls-rustls", "actix-http/rustls", "awc/rustls"]
|
||||||
openssl = ["tls-openssl", "actix-http/openssl", "awc/openssl"]
|
openssl = ["tls-openssl", "actix-http/openssl", "awc/openssl"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix-codec = "0.4.0"
|
actix-codec = "0.4.1"
|
||||||
actix-http = "3.0.0-beta.12"
|
actix-http = "3.0.0-beta.12"
|
||||||
actix-http-test = "3.0.0-beta.6"
|
actix-http-test = "3.0.0-beta.6"
|
||||||
actix-service = "2.0.0"
|
actix-service = "2.0.0"
|
||||||
|
|
|
@ -15,7 +15,7 @@ path = "src/lib.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix = { version = "0.12.0", default-features = false }
|
actix = { version = "0.12.0", default-features = false }
|
||||||
actix-codec = "0.4.0"
|
actix-codec = "0.4.1"
|
||||||
actix-http = "3.0.0-beta.12"
|
actix-http = "3.0.0-beta.12"
|
||||||
actix-web = { version = "4.0.0-beta.11", default-features = false }
|
actix-web = { version = "4.0.0-beta.11", default-features = false }
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
|
|
||||||
## 3.0.0-beta.10 - 2021-11-15
|
## 3.0.0-beta.10 - 2021-11-15
|
||||||
|
* No significant changes from `3.0.0-beta.9`.
|
||||||
|
|
||||||
|
|
||||||
## 3.0.0-beta.9 - 2021-10-20
|
## 3.0.0-beta.9 - 2021-10-20
|
||||||
|
|
|
@ -53,7 +53,7 @@ trust-dns = ["trust-dns-resolver"]
|
||||||
__compress = []
|
__compress = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix-codec = "0.4.0"
|
actix-codec = "0.4.1"
|
||||||
actix-service = "2.0.0"
|
actix-service = "2.0.0"
|
||||||
actix-http = "3.0.0-beta.12"
|
actix-http = "3.0.0-beta.12"
|
||||||
actix-rt = { version = "2.1", default-features = false }
|
actix-rt = { version = "2.1", default-features = false }
|
||||||
|
|
|
@ -70,7 +70,7 @@ where
|
||||||
// RFC: https://tools.ietf.org/html/rfc7231#section-5.1.1
|
// RFC: https://tools.ietf.org/html/rfc7231#section-5.1.1
|
||||||
let is_expect = if head.as_ref().headers.contains_key(EXPECT) {
|
let is_expect = if head.as_ref().headers.contains_key(EXPECT) {
|
||||||
match body.size() {
|
match body.size() {
|
||||||
BodySize::None | BodySize::Empty | BodySize::Sized(0) => {
|
BodySize::None | BodySize::Sized(0) => {
|
||||||
let keep_alive = framed.codec_ref().keepalive();
|
let keep_alive = framed.codec_ref().keepalive();
|
||||||
framed.io_mut().on_release(keep_alive);
|
framed.io_mut().on_release(keep_alive);
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ where
|
||||||
if do_send {
|
if do_send {
|
||||||
// send request body
|
// send request body
|
||||||
match body.size() {
|
match body.size() {
|
||||||
BodySize::None | BodySize::Empty | BodySize::Sized(0) => {}
|
BodySize::None | BodySize::Sized(0) => {}
|
||||||
_ => send_body(body, pin_framed.as_mut()).await?,
|
_ => send_body(body, pin_framed.as_mut()).await?,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -36,10 +36,7 @@ where
|
||||||
|
|
||||||
let head_req = head.as_ref().method == Method::HEAD;
|
let head_req = head.as_ref().method == Method::HEAD;
|
||||||
let length = body.size();
|
let length = body.size();
|
||||||
let eof = matches!(
|
let eof = matches!(length, BodySize::None | BodySize::Sized(0));
|
||||||
length,
|
|
||||||
BodySize::None | BodySize::Empty | BodySize::Sized(0)
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut req = Request::new(());
|
let mut req = Request::new(());
|
||||||
*req.uri_mut() = head.as_ref().uri.clone();
|
*req.uri_mut() = head.as_ref().uri.clone();
|
||||||
|
@ -52,13 +49,11 @@ where
|
||||||
// Content length
|
// Content length
|
||||||
let _ = match length {
|
let _ = match length {
|
||||||
BodySize::None => None,
|
BodySize::None => None,
|
||||||
BodySize::Stream => {
|
|
||||||
skip_len = false;
|
BodySize::Sized(0) => req
|
||||||
None
|
|
||||||
}
|
|
||||||
BodySize::Empty => req
|
|
||||||
.headers_mut()
|
.headers_mut()
|
||||||
.insert(CONTENT_LENGTH, HeaderValue::from_static("0")),
|
.insert(CONTENT_LENGTH, HeaderValue::from_static("0")),
|
||||||
|
|
||||||
BodySize::Sized(len) => {
|
BodySize::Sized(len) => {
|
||||||
let mut buf = itoa::Buffer::new();
|
let mut buf = itoa::Buffer::new();
|
||||||
|
|
||||||
|
@ -67,6 +62,11 @@ where
|
||||||
HeaderValue::from_str(buf.format(len)).unwrap(),
|
HeaderValue::from_str(buf.format(len)).unwrap(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BodySize::Stream => {
|
||||||
|
skip_len = false;
|
||||||
|
None
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Extracting extra headers from RequestHeadType. HeaderMap::new() does not allocate.
|
// Extracting extra headers from RequestHeadType. HeaderMap::new() does not allocate.
|
||||||
|
|
|
@ -8,7 +8,7 @@ use std::{
|
||||||
|
|
||||||
use actix_codec::Framed;
|
use actix_codec::Framed;
|
||||||
use actix_http::{
|
use actix_http::{
|
||||||
body::Body, h1::ClientCodec, Payload, RequestHead, RequestHeadType, ResponseHead,
|
body::AnyBody, h1::ClientCodec, Payload, RequestHead, RequestHeadType, ResponseHead,
|
||||||
};
|
};
|
||||||
use actix_service::Service;
|
use actix_service::Service;
|
||||||
use futures_core::{future::LocalBoxFuture, ready};
|
use futures_core::{future::LocalBoxFuture, ready};
|
||||||
|
@ -30,7 +30,7 @@ pub type BoxConnectorService = Rc<
|
||||||
pub type BoxedSocket = Box<dyn ConnectionIo>;
|
pub type BoxedSocket = Box<dyn ConnectionIo>;
|
||||||
|
|
||||||
pub enum ConnectRequest {
|
pub enum ConnectRequest {
|
||||||
Client(RequestHeadType, Body, Option<net::SocketAddr>),
|
Client(RequestHeadType, AnyBody, Option<net::SocketAddr>),
|
||||||
Tunnel(RequestHead, Option<net::SocketAddr>),
|
Tunnel(RequestHead, Option<net::SocketAddr>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ use futures_core::Stream;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use actix_http::{
|
use actix_http::{
|
||||||
body::Body,
|
body::AnyBody,
|
||||||
http::{header::IntoHeaderValue, Error as HttpError, HeaderMap, HeaderName, Method, Uri},
|
http::{header::IntoHeaderValue, Error as HttpError, HeaderMap, HeaderName, Method, Uri},
|
||||||
RequestHead,
|
RequestHead,
|
||||||
};
|
};
|
||||||
|
@ -45,7 +45,7 @@ impl FrozenClientRequest {
|
||||||
/// Send a body.
|
/// Send a body.
|
||||||
pub fn send_body<B>(&self, body: B) -> SendClientRequest
|
pub fn send_body<B>(&self, body: B) -> SendClientRequest
|
||||||
where
|
where
|
||||||
B: Into<Body>,
|
B: Into<AnyBody>,
|
||||||
{
|
{
|
||||||
RequestSender::Rc(self.head.clone(), None).send_body(
|
RequestSender::Rc(self.head.clone(), None).send_body(
|
||||||
self.addr,
|
self.addr,
|
||||||
|
@ -158,7 +158,7 @@ impl FrozenSendBuilder {
|
||||||
/// Complete request construction and send a body.
|
/// Complete request construction and send a body.
|
||||||
pub fn send_body<B>(self, body: B) -> SendClientRequest
|
pub fn send_body<B>(self, body: B) -> SendClientRequest
|
||||||
where
|
where
|
||||||
B: Into<Body>,
|
B: Into<AnyBody>,
|
||||||
{
|
{
|
||||||
if let Some(e) = self.err {
|
if let Some(e) = self.err {
|
||||||
return e.into();
|
return e.into();
|
||||||
|
|
|
@ -8,7 +8,7 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use actix_http::{
|
use actix_http::{
|
||||||
body::Body,
|
body::AnyBody,
|
||||||
http::{header, Method, StatusCode, Uri},
|
http::{header, Method, StatusCode, Uri},
|
||||||
RequestHead, RequestHeadType,
|
RequestHead, RequestHeadType,
|
||||||
};
|
};
|
||||||
|
@ -95,7 +95,7 @@ where
|
||||||
};
|
};
|
||||||
|
|
||||||
let body_opt = match body {
|
let body_opt = match body {
|
||||||
Body::Bytes(ref b) => Some(b.clone()),
|
AnyBody::Bytes(ref b) => Some(b.clone()),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -192,14 +192,14 @@ where
|
||||||
let body_new = if is_redirect {
|
let body_new = if is_redirect {
|
||||||
// try to reuse body
|
// try to reuse body
|
||||||
match body {
|
match body {
|
||||||
Some(ref bytes) => Body::Bytes(bytes.clone()),
|
Some(ref bytes) => AnyBody::Bytes(bytes.clone()),
|
||||||
// TODO: should this be Body::Empty or Body::None.
|
// TODO: should this be AnyBody::Empty or AnyBody::None.
|
||||||
_ => Body::Empty,
|
_ => AnyBody::empty(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
body = None;
|
body = None;
|
||||||
// remove body
|
// remove body
|
||||||
Body::None
|
AnyBody::None
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut headers = headers.take().unwrap();
|
let mut headers = headers.take().unwrap();
|
||||||
|
|
|
@ -5,7 +5,7 @@ use futures_core::Stream;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use actix_http::{
|
use actix_http::{
|
||||||
body::Body,
|
body::AnyBody,
|
||||||
http::{
|
http::{
|
||||||
header::{self, IntoHeaderPair},
|
header::{self, IntoHeaderPair},
|
||||||
ConnectionType, Error as HttpError, HeaderMap, HeaderValue, Method, Uri, Version,
|
ConnectionType, Error as HttpError, HeaderMap, HeaderValue, Method, Uri, Version,
|
||||||
|
@ -350,7 +350,7 @@ impl ClientRequest {
|
||||||
/// Complete request construction and send body.
|
/// Complete request construction and send body.
|
||||||
pub fn send_body<B>(self, body: B) -> SendClientRequest
|
pub fn send_body<B>(self, body: B) -> SendClientRequest
|
||||||
where
|
where
|
||||||
B: Into<Body>,
|
B: Into<AnyBody>,
|
||||||
{
|
{
|
||||||
let slf = match self.prep_for_sending() {
|
let slf = match self.prep_for_sending() {
|
||||||
Ok(slf) => slf,
|
Ok(slf) => slf,
|
||||||
|
|
|
@ -9,7 +9,7 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use actix_http::{
|
use actix_http::{
|
||||||
body::{Body, BodyStream},
|
body::{AnyBody, BodyStream},
|
||||||
http::{
|
http::{
|
||||||
header::{self, HeaderMap, HeaderName, IntoHeaderValue},
|
header::{self, HeaderMap, HeaderName, IntoHeaderValue},
|
||||||
Error as HttpError,
|
Error as HttpError,
|
||||||
|
@ -196,7 +196,7 @@ impl RequestSender {
|
||||||
body: B,
|
body: B,
|
||||||
) -> SendClientRequest
|
) -> SendClientRequest
|
||||||
where
|
where
|
||||||
B: Into<Body>,
|
B: Into<AnyBody>,
|
||||||
{
|
{
|
||||||
let req = match self {
|
let req = match self {
|
||||||
RequestSender::Owned(head) => {
|
RequestSender::Owned(head) => {
|
||||||
|
@ -236,7 +236,7 @@ impl RequestSender {
|
||||||
response_decompress,
|
response_decompress,
|
||||||
timeout,
|
timeout,
|
||||||
config,
|
config,
|
||||||
Body::Bytes(Bytes::from(body)),
|
AnyBody::Bytes(Bytes::from(body)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,7 +265,7 @@ impl RequestSender {
|
||||||
response_decompress,
|
response_decompress,
|
||||||
timeout,
|
timeout,
|
||||||
config,
|
config,
|
||||||
Body::Bytes(Bytes::from(body)),
|
AnyBody::Bytes(Bytes::from(body)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,7 +286,7 @@ impl RequestSender {
|
||||||
response_decompress,
|
response_decompress,
|
||||||
timeout,
|
timeout,
|
||||||
config,
|
config,
|
||||||
Body::from_message(BodyStream::new(stream)),
|
AnyBody::new_boxed(BodyStream::new(stream)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,7 +297,7 @@ impl RequestSender {
|
||||||
timeout: Option<Duration>,
|
timeout: Option<Duration>,
|
||||||
config: &ClientConfig,
|
config: &ClientConfig,
|
||||||
) -> SendClientRequest {
|
) -> SendClientRequest {
|
||||||
self.send_body(addr, response_decompress, timeout, config, Body::Empty)
|
self.send_body(addr, response_decompress, timeout, config, AnyBody::empty())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_header_if_none<V>(&mut self, key: HeaderName, value: V) -> Result<(), HttpError>
|
fn set_header_if_none<V>(&mut self, key: HeaderName, value: V) -> Result<(), HttpError>
|
||||||
|
|
|
@ -4,7 +4,7 @@ use std::future::Future;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use actix_http::body::{Body, MessageBody};
|
use actix_http::body::{AnyBody, MessageBody};
|
||||||
use actix_http::{Extensions, Request};
|
use actix_http::{Extensions, Request};
|
||||||
use actix_service::boxed::{self, BoxServiceFactory};
|
use actix_service::boxed::{self, BoxServiceFactory};
|
||||||
use actix_service::{
|
use actix_service::{
|
||||||
|
@ -39,7 +39,7 @@ pub struct App<T, B> {
|
||||||
_phantom: PhantomData<B>,
|
_phantom: PhantomData<B>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl App<AppEntry, Body> {
|
impl App<AppEntry, AnyBody> {
|
||||||
/// Create application builder. Application can be configured with a builder-like pattern.
|
/// Create application builder. Application can be configured with a builder-like pattern.
|
||||||
#[allow(clippy::new_without_default)]
|
#[allow(clippy::new_without_default)]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
|
|
|
@ -14,7 +14,8 @@ pub use crate::types::form::UrlEncoded;
|
||||||
pub use crate::types::json::JsonBody;
|
pub use crate::types::json::JsonBody;
|
||||||
pub use crate::types::readlines::Readlines;
|
pub use crate::types::readlines::Readlines;
|
||||||
|
|
||||||
pub use actix_http::body::{AnyBody, Body, BodySize, MessageBody, ResponseBody, SizedStream};
|
#[allow(deprecated)]
|
||||||
|
pub use actix_http::body::{AnyBody, Body, BodySize, MessageBody, SizedStream};
|
||||||
|
|
||||||
#[cfg(feature = "__compress")]
|
#[cfg(feature = "__compress")]
|
||||||
pub use actix_http::encoding::Decoder as Decompress;
|
pub use actix_http::encoding::Decoder as Decompress;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::{cell::RefCell, fmt, io::Write as _};
|
use std::{cell::RefCell, fmt, io::Write as _};
|
||||||
|
|
||||||
use actix_http::{body::Body, header, StatusCode};
|
use actix_http::{body::AnyBody, header, StatusCode};
|
||||||
use bytes::{BufMut as _, BytesMut};
|
use bytes::{BufMut as _, BytesMut};
|
||||||
|
|
||||||
use crate::{Error, HttpRequest, HttpResponse, Responder, ResponseError};
|
use crate::{Error, HttpRequest, HttpResponse, Responder, ResponseError};
|
||||||
|
@ -88,7 +88,7 @@ where
|
||||||
header::CONTENT_TYPE,
|
header::CONTENT_TYPE,
|
||||||
header::HeaderValue::from_static("text/plain; charset=utf-8"),
|
header::HeaderValue::from_static("text/plain; charset=utf-8"),
|
||||||
);
|
);
|
||||||
res.set_body(Body::from(buf.into_inner()))
|
res.set_body(AnyBody::from(buf.into_inner()))
|
||||||
}
|
}
|
||||||
|
|
||||||
InternalErrorType::Response(ref resp) => {
|
InternalErrorType::Response(ref resp) => {
|
||||||
|
|
|
@ -7,7 +7,7 @@ use std::{
|
||||||
task::{Context, Poll},
|
task::{Context, Poll},
|
||||||
};
|
};
|
||||||
|
|
||||||
use actix_http::body::{Body, MessageBody};
|
use actix_http::body::{AnyBody, MessageBody};
|
||||||
use actix_service::{Service, Transform};
|
use actix_service::{Service, Transform};
|
||||||
use futures_core::{future::LocalBoxFuture, ready};
|
use futures_core::{future::LocalBoxFuture, ready};
|
||||||
|
|
||||||
|
@ -124,7 +124,7 @@ where
|
||||||
B::Error: Into<Box<dyn StdError + 'static>>,
|
B::Error: Into<Box<dyn StdError + 'static>>,
|
||||||
{
|
{
|
||||||
fn map_body(self) -> ServiceResponse {
|
fn map_body(self) -> ServiceResponse {
|
||||||
self.map_body(|_, body| Body::from_message(body))
|
self.map_body(|_, body| AnyBody::new_boxed(body))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,13 +10,14 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use actix_http::{
|
use actix_http::{
|
||||||
body::{MessageBody, ResponseBody},
|
body::{AnyBody, MessageBody},
|
||||||
encoding::Encoder,
|
encoding::Encoder,
|
||||||
http::header::{ContentEncoding, ACCEPT_ENCODING},
|
http::header::{ContentEncoding, ACCEPT_ENCODING},
|
||||||
StatusCode,
|
StatusCode,
|
||||||
};
|
};
|
||||||
use actix_service::{Service, Transform};
|
use actix_service::{Service, Transform};
|
||||||
use actix_utils::future::{ok, Either, Ready};
|
use actix_utils::future::{ok, Either, Ready};
|
||||||
|
use bytes::Bytes;
|
||||||
use futures_core::ready;
|
use futures_core::ready;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use pin_project::pin_project;
|
use pin_project::pin_project;
|
||||||
|
@ -61,7 +62,7 @@ where
|
||||||
B: MessageBody,
|
B: MessageBody,
|
||||||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||||
{
|
{
|
||||||
type Response = ServiceResponse<ResponseBody<Encoder<B>>>;
|
type Response = ServiceResponse<AnyBody<Encoder<B>>>;
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
type Transform = CompressMiddleware<S>;
|
type Transform = CompressMiddleware<S>;
|
||||||
type InitError = ();
|
type InitError = ();
|
||||||
|
@ -110,7 +111,7 @@ where
|
||||||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||||
B: MessageBody,
|
B: MessageBody,
|
||||||
{
|
{
|
||||||
type Response = ServiceResponse<ResponseBody<Encoder<B>>>;
|
type Response = ServiceResponse<AnyBody<Encoder<B>>>;
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
type Future = Either<CompressResponse<S, B>, Ready<Result<Self::Response, Self::Error>>>;
|
type Future = Either<CompressResponse<S, B>, Ready<Result<Self::Response, Self::Error>>>;
|
||||||
|
|
||||||
|
@ -142,15 +143,19 @@ where
|
||||||
|
|
||||||
// There is an HTTP header but we cannot match what client as asked for
|
// There is an HTTP header but we cannot match what client as asked for
|
||||||
Some(Err(_)) => {
|
Some(Err(_)) => {
|
||||||
let res = HttpResponse::with_body(
|
let res = HttpResponse::new(StatusCode::NOT_ACCEPTABLE);
|
||||||
StatusCode::NOT_ACCEPTABLE,
|
|
||||||
SUPPORTED_ALGORITHM_NAMES.as_str(),
|
|
||||||
);
|
|
||||||
let enc = ContentEncoding::Identity;
|
|
||||||
|
|
||||||
Either::right(ok(req.into_response(res.map_body(move |head, body| {
|
let res: HttpResponse<AnyBody<Encoder<B>>> = res.map_body(move |head, _| {
|
||||||
Encoder::response(enc, head, ResponseBody::Other(body.into()))
|
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)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -172,7 +177,7 @@ where
|
||||||
B: MessageBody,
|
B: MessageBody,
|
||||||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||||
{
|
{
|
||||||
type Output = Result<ServiceResponse<ResponseBody<Encoder<B>>>, Error>;
|
type Output = Result<ServiceResponse<AnyBody<Encoder<B>>>, Error>;
|
||||||
|
|
||||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
let this = self.project();
|
let this = self.project();
|
||||||
|
@ -186,7 +191,7 @@ where
|
||||||
};
|
};
|
||||||
|
|
||||||
Poll::Ready(Ok(resp.map_body(move |head, body| {
|
Poll::Ready(Ok(resp.map_body(move |head, body| {
|
||||||
Encoder::response(enc, head, ResponseBody::Body(body))
|
Encoder::response(enc, head, AnyBody::Body(body))
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
Err(e) => Poll::Ready(Err(e)),
|
Err(e) => Poll::Ready(Err(e)),
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use actix_http::{
|
use actix_http::{
|
||||||
body::Body,
|
body::AnyBody,
|
||||||
http::{header::IntoHeaderPair, Error as HttpError, HeaderMap, StatusCode},
|
http::{header::IntoHeaderPair, Error as HttpError, HeaderMap, StatusCode},
|
||||||
};
|
};
|
||||||
use bytes::{Bytes, BytesMut};
|
use bytes::{Bytes, BytesMut};
|
||||||
|
@ -65,7 +65,7 @@ impl Responder for HttpResponse {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Responder for actix_http::Response<Body> {
|
impl Responder for actix_http::Response<AnyBody> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn respond_to(self, _: &HttpRequest) -> HttpResponse {
|
fn respond_to(self, _: &HttpRequest) -> HttpResponse {
|
||||||
HttpResponse::from(self)
|
HttpResponse::from(self)
|
||||||
|
@ -232,7 +232,7 @@ pub(crate) mod tests {
|
||||||
use bytes::{Bytes, BytesMut};
|
use bytes::{Bytes, BytesMut};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::dev::{Body, ResponseBody};
|
use crate::dev::AnyBody;
|
||||||
use crate::http::{header::CONTENT_TYPE, HeaderValue, StatusCode};
|
use crate::http::{header::CONTENT_TYPE, HeaderValue, StatusCode};
|
||||||
use crate::test::{init_service, TestRequest};
|
use crate::test::{init_service, TestRequest};
|
||||||
use crate::{error, web, App};
|
use crate::{error, web, App};
|
||||||
|
@ -254,7 +254,7 @@ pub(crate) mod tests {
|
||||||
let resp = srv.call(req).await.unwrap();
|
let resp = srv.call(req).await.unwrap();
|
||||||
assert_eq!(resp.status(), StatusCode::OK);
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
match resp.response().body() {
|
match resp.response().body() {
|
||||||
Body::Bytes(ref b) => {
|
AnyBody::Bytes(ref b) => {
|
||||||
let bytes = b.clone();
|
let bytes = b.clone();
|
||||||
assert_eq!(bytes, Bytes::from_static(b"some"));
|
assert_eq!(bytes, Bytes::from_static(b"some"));
|
||||||
}
|
}
|
||||||
|
@ -264,42 +264,21 @@ pub(crate) mod tests {
|
||||||
|
|
||||||
pub(crate) trait BodyTest {
|
pub(crate) trait BodyTest {
|
||||||
fn bin_ref(&self) -> &[u8];
|
fn bin_ref(&self) -> &[u8];
|
||||||
fn body(&self) -> &Body;
|
fn body(&self) -> &AnyBody;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BodyTest for Body {
|
impl BodyTest for AnyBody {
|
||||||
fn bin_ref(&self) -> &[u8] {
|
fn bin_ref(&self) -> &[u8] {
|
||||||
match self {
|
match self {
|
||||||
Body::Bytes(ref bin) => bin,
|
AnyBody::Bytes(ref bin) => bin,
|
||||||
_ => unreachable!("bug in test impl"),
|
_ => unreachable!("bug in test impl"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn body(&self) -> &Body {
|
fn body(&self) -> &AnyBody {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BodyTest for ResponseBody<Body> {
|
|
||||||
fn bin_ref(&self) -> &[u8] {
|
|
||||||
match self {
|
|
||||||
ResponseBody::Body(ref b) => match b {
|
|
||||||
Body::Bytes(ref bin) => bin,
|
|
||||||
_ => unreachable!("bug in test impl"),
|
|
||||||
},
|
|
||||||
ResponseBody::Other(ref b) => match b {
|
|
||||||
Body::Bytes(ref bin) => bin,
|
|
||||||
_ => unreachable!("bug in test impl"),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn body(&self) -> &Body {
|
|
||||||
match self {
|
|
||||||
ResponseBody::Body(ref b) => b,
|
|
||||||
ResponseBody::Other(ref b) => b,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_responder() {
|
async fn test_responder() {
|
||||||
let req = TestRequest::default().to_http_request();
|
let req = TestRequest::default().to_http_request();
|
||||||
|
|
|
@ -357,7 +357,7 @@ impl HttpResponseBuilder {
|
||||||
S: Stream<Item = Result<Bytes, E>> + 'static,
|
S: Stream<Item = Result<Bytes, E>> + 'static,
|
||||||
E: Into<Box<dyn StdError>> + 'static,
|
E: Into<Box<dyn StdError>> + 'static,
|
||||||
{
|
{
|
||||||
self.body(AnyBody::from_message(BodyStream::new(stream)))
|
self.body(AnyBody::new_boxed(BodyStream::new(stream)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a json body and generate `Response`
|
/// Set a json body and generate `Response`
|
||||||
|
@ -387,7 +387,7 @@ impl HttpResponseBuilder {
|
||||||
/// `HttpResponseBuilder` can not be used after this call.
|
/// `HttpResponseBuilder` can not be used after this call.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn finish(&mut self) -> HttpResponse {
|
pub fn finish(&mut self) -> HttpResponse {
|
||||||
self.body(AnyBody::Empty)
|
self.body(AnyBody::empty())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This method construct new `HttpResponseBuilder`
|
/// This method construct new `HttpResponseBuilder`
|
||||||
|
@ -436,7 +436,7 @@ mod tests {
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
dev::Body,
|
dev::AnyBody,
|
||||||
http::{
|
http::{
|
||||||
header::{self, HeaderValue, CONTENT_TYPE},
|
header::{self, HeaderValue, CONTENT_TYPE},
|
||||||
StatusCode,
|
StatusCode,
|
||||||
|
@ -475,7 +475,7 @@ mod tests {
|
||||||
fn test_content_type() {
|
fn test_content_type() {
|
||||||
let resp = HttpResponseBuilder::new(StatusCode::OK)
|
let resp = HttpResponseBuilder::new(StatusCode::OK)
|
||||||
.content_type("text/plain")
|
.content_type("text/plain")
|
||||||
.body(Body::Empty);
|
.body(AnyBody::empty());
|
||||||
assert_eq!(resp.headers().get(CONTENT_TYPE).unwrap(), "text/plain")
|
assert_eq!(resp.headers().get(CONTENT_TYPE).unwrap(), "text/plain")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,13 +87,12 @@ impl HttpResponse {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::dev::Body;
|
|
||||||
use crate::http::StatusCode;
|
use crate::http::StatusCode;
|
||||||
use crate::HttpResponse;
|
use crate::HttpResponse;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_build() {
|
fn test_build() {
|
||||||
let resp = HttpResponse::Ok().body(Body::Empty);
|
let resp = HttpResponse::Ok().finish();
|
||||||
assert_eq!(resp.status(), StatusCode::OK);
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use actix_http::{
|
use actix_http::{
|
||||||
body::{AnyBody, Body, MessageBody},
|
body::{AnyBody, MessageBody},
|
||||||
http::{header::HeaderMap, StatusCode},
|
http::{header::HeaderMap, StatusCode},
|
||||||
Extensions, Response, ResponseHead,
|
Extensions, Response, ResponseHead,
|
||||||
};
|
};
|
||||||
|
@ -227,6 +227,9 @@ impl<B> HttpResponse<B> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: into_body equivalent
|
||||||
|
// TODO: into_boxed_body
|
||||||
|
|
||||||
/// Extract response body
|
/// Extract response body
|
||||||
pub fn into_body(self) -> B {
|
pub fn into_body(self) -> B {
|
||||||
self.res.into_body()
|
self.res.into_body()
|
||||||
|
@ -270,14 +273,14 @@ impl<B> From<HttpResponse<B>> for Response<B> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Future is only implemented for Body payload type because it's the most useful for making simple
|
// Future is only implemented for AnyBody payload type because it's the most useful for making
|
||||||
// handlers without async blocks. Making it generic over all MessageBody types requires a future
|
// simple handlers without async blocks. Making it generic over all MessageBody types requires a
|
||||||
// impl on Response which would cause it's body field to be, undesirably, Option<B>.
|
// 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
|
// 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.
|
// not be invoked if performance is important. Prefer an async fn/block in such cases.
|
||||||
impl Future for HttpResponse<Body> {
|
impl Future for HttpResponse<AnyBody> {
|
||||||
type Output = Result<Response<Body>, Error>;
|
type Output = Result<Response<AnyBody>, Error>;
|
||||||
|
|
||||||
fn poll(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
if let Some(err) = self.error.take() {
|
if let Some(err) = self.error.take() {
|
||||||
|
|
|
@ -580,7 +580,7 @@ mod tests {
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
dev::Body,
|
dev::AnyBody,
|
||||||
guard,
|
guard,
|
||||||
http::{header, HeaderValue, Method, StatusCode},
|
http::{header, HeaderValue, Method, StatusCode},
|
||||||
middleware::DefaultHeaders,
|
middleware::DefaultHeaders,
|
||||||
|
@ -752,7 +752,7 @@ mod tests {
|
||||||
assert_eq!(resp.status(), StatusCode::OK);
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
|
|
||||||
match resp.response().body() {
|
match resp.response().body() {
|
||||||
Body::Bytes(ref b) => {
|
AnyBody::Bytes(ref b) => {
|
||||||
let bytes = b.clone();
|
let bytes = b.clone();
|
||||||
assert_eq!(bytes, Bytes::from_static(b"project: project1"));
|
assert_eq!(bytes, Bytes::from_static(b"project: project1"));
|
||||||
}
|
}
|
||||||
|
@ -853,7 +853,7 @@ mod tests {
|
||||||
assert_eq!(resp.status(), StatusCode::CREATED);
|
assert_eq!(resp.status(), StatusCode::CREATED);
|
||||||
|
|
||||||
match resp.response().body() {
|
match resp.response().body() {
|
||||||
Body::Bytes(ref b) => {
|
AnyBody::Bytes(ref b) => {
|
||||||
let bytes = b.clone();
|
let bytes = b.clone();
|
||||||
assert_eq!(bytes, Bytes::from_static(b"project: project_1"));
|
assert_eq!(bytes, Bytes::from_static(b"project: project_1"));
|
||||||
}
|
}
|
||||||
|
@ -881,7 +881,7 @@ mod tests {
|
||||||
assert_eq!(resp.status(), StatusCode::CREATED);
|
assert_eq!(resp.status(), StatusCode::CREATED);
|
||||||
|
|
||||||
match resp.response().body() {
|
match resp.response().body() {
|
||||||
Body::Bytes(ref b) => {
|
AnyBody::Bytes(ref b) => {
|
||||||
let bytes = b.clone();
|
let bytes = b.clone();
|
||||||
assert_eq!(bytes, Bytes::from_static(b"project: test - 1"));
|
assert_eq!(bytes, Bytes::from_static(b"project: test - 1"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ use crate::{
|
||||||
app_service::AppInitServiceState,
|
app_service::AppInitServiceState,
|
||||||
config::AppConfig,
|
config::AppConfig,
|
||||||
data::Data,
|
data::Data,
|
||||||
dev::{Body, MessageBody, Payload},
|
dev::{AnyBody, MessageBody, Payload},
|
||||||
http::header::ContentType,
|
http::header::ContentType,
|
||||||
rmap::ResourceMap,
|
rmap::ResourceMap,
|
||||||
service::{ServiceRequest, ServiceResponse},
|
service::{ServiceRequest, ServiceResponse},
|
||||||
|
@ -32,14 +32,14 @@ use crate::{
|
||||||
|
|
||||||
/// Create service that always responds with `HttpResponse::Ok()` and no body.
|
/// Create service that always responds with `HttpResponse::Ok()` and no body.
|
||||||
pub fn ok_service(
|
pub fn ok_service(
|
||||||
) -> impl Service<ServiceRequest, Response = ServiceResponse<Body>, Error = Error> {
|
) -> impl Service<ServiceRequest, Response = ServiceResponse<AnyBody>, Error = Error> {
|
||||||
default_service(StatusCode::OK)
|
default_service(StatusCode::OK)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create service that always responds with given status code and no body.
|
/// Create service that always responds with given status code and no body.
|
||||||
pub fn default_service(
|
pub fn default_service(
|
||||||
status_code: StatusCode,
|
status_code: StatusCode,
|
||||||
) -> impl Service<ServiceRequest, Response = ServiceResponse<Body>, Error = Error> {
|
) -> impl Service<ServiceRequest, Response = ServiceResponse<AnyBody>, Error = Error> {
|
||||||
(move |req: ServiceRequest| {
|
(move |req: ServiceRequest| {
|
||||||
ok(req.into_response(HttpResponseBuilder::new(status_code).finish()))
|
ok(req.into_response(HttpResponseBuilder::new(status_code).finish()))
|
||||||
})
|
})
|
||||||
|
|
|
@ -200,7 +200,7 @@ async fn test_body_encoding_override() {
|
||||||
.body(STR)
|
.body(STR)
|
||||||
})))
|
})))
|
||||||
.service(web::resource("/raw").route(web::to(|| {
|
.service(web::resource("/raw").route(web::to(|| {
|
||||||
let body = actix_web::dev::Body::Bytes(STR.into());
|
let body = actix_web::dev::AnyBody::Bytes(STR.into());
|
||||||
let mut response =
|
let mut response =
|
||||||
HttpResponse::with_body(actix_web::http::StatusCode::OK, body);
|
HttpResponse::with_body(actix_web::http::StatusCode::OK, body);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue