relax bound on MessageBody::Error to Debug

This commit is contained in:
Rob Ede 2021-12-16 23:34:07 +00:00
parent 44b7302845
commit 35d279e594
No known key found for this signature in database
GPG Key ID: 97C636207D3EF933
24 changed files with 104 additions and 119 deletions

View File

@ -1,5 +1,5 @@
use std::{ use std::{
error::Error as StdError, fmt,
pin::Pin, pin::Pin,
task::{Context, Poll}, task::{Context, Poll},
}; };
@ -25,7 +25,7 @@ pin_project! {
impl<S, E> BodyStream<S> impl<S, E> BodyStream<S>
where where
S: Stream<Item = Result<Bytes, E>>, S: Stream<Item = Result<Bytes, E>>,
E: Into<Box<dyn StdError>> + 'static, E: fmt::Debug + 'static,
{ {
#[inline] #[inline]
pub fn new(stream: S) -> Self { pub fn new(stream: S) -> Self {
@ -36,7 +36,7 @@ where
impl<S, E> MessageBody for BodyStream<S> impl<S, E> MessageBody for BodyStream<S>
where where
S: Stream<Item = Result<Bytes, E>>, S: Stream<Item = Result<Bytes, E>>,
E: Into<Box<dyn StdError>> + 'static, E: fmt::Debug + 'static,
{ {
type Error = E; type Error = E;
@ -150,21 +150,6 @@ mod tests {
assert!(matches!(to_bytes(body).await, 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 = BodyStream::new(stream::iter(vec![Ok(Bytes::from("1")), Err(StreamErr)])); let body = BodyStream::new(stream::iter(vec![Ok(Bytes::from("1")), Err(StreamErr)]));

View File

@ -1,5 +1,4 @@
use std::{ use std::{
error::Error as StdError,
fmt, fmt,
pin::Pin, pin::Pin,
task::{Context, Poll}, task::{Context, Poll},
@ -8,23 +7,28 @@ use std::{
use bytes::Bytes; use bytes::Bytes;
use super::{BodySize, MessageBody, MessageBodyMapErr}; use super::{BodySize, MessageBody, MessageBodyMapErr};
use crate::Error;
/// A boxed message body with boxed errors. /// A boxed message body with boxed errors.
pub struct BoxBody(Pin<Box<dyn MessageBody<Error = Box<dyn StdError>>>>); pub struct BoxBody(Pin<Box<dyn MessageBody<Error = Box<dyn fmt::Debug>>>>);
impl BoxBody { impl BoxBody {
/// Boxes a `MessageBody` and any errors it generates. /// Boxes a `MessageBody` and any errors it generates.
#[inline]
pub fn new<B>(body: B) -> Self pub fn new<B>(body: B) -> Self
where where
B: MessageBody + 'static, B: MessageBody + 'static,
{ {
let body = MessageBodyMapErr::new(body, Into::into); fn box_it<T: fmt::Debug + 'static>(it: T) -> Box<dyn fmt::Debug> {
Box::new(it)
}
let body = MessageBodyMapErr::new(body, box_it);
Self(Box::pin(body)) Self(Box::pin(body))
} }
/// 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(&mut self) -> Pin<&mut (dyn MessageBody<Error = Box<dyn StdError>>)> { #[inline]
pub fn as_pin_mut(&mut self) -> Pin<&mut (dyn MessageBody<Error = Box<dyn fmt::Debug>>)> {
self.0.as_mut() self.0.as_mut()
} }
} }
@ -36,22 +40,22 @@ impl fmt::Debug for BoxBody {
} }
impl MessageBody for BoxBody { impl MessageBody for BoxBody {
type Error = Error; type Error = Box<dyn fmt::Debug>;
#[inline]
fn size(&self) -> BodySize { fn size(&self) -> BodySize {
self.0.size() self.0.size()
} }
#[inline]
fn poll_next( fn poll_next(
mut self: Pin<&mut Self>, mut self: Pin<&mut Self>,
cx: &mut Context<'_>, cx: &mut Context<'_>,
) -> Poll<Option<Result<Bytes, Self::Error>>> { ) -> Poll<Option<Result<Bytes, Self::Error>>> {
self.0 self.0.as_mut().poll_next(cx)
.as_mut()
.poll_next(cx)
.map_err(|err| Error::new_body().with_cause(err))
} }
#[inline]
fn is_complete_body(&self) -> bool { fn is_complete_body(&self) -> bool {
self.0.is_complete_body() self.0.is_complete_body()
} }

View File

@ -66,10 +66,10 @@ where
match self.project() { match self.project() {
EitherBodyProj::Left { body } => body EitherBodyProj::Left { body } => body
.poll_next(cx) .poll_next(cx)
.map_err(|err| Error::new_body().with_cause(err)), .map_err(|err| Error::new_body().with_cause(format!("{:?}", err))),
EitherBodyProj::Right { body } => body EitherBodyProj::Right { body } => body
.poll_next(cx) .poll_next(cx)
.map_err(|err| Error::new_body().with_cause(err)), .map_err(|err| Error::new_body().with_cause(format!("{:?}", err))),
} }
} }

View File

@ -2,8 +2,7 @@
use std::{ use std::{
convert::Infallible, convert::Infallible,
error::Error as StdError, fmt, mem,
mem,
pin::Pin, pin::Pin,
task::{Context, Poll}, task::{Context, Poll},
}; };
@ -17,9 +16,11 @@ use super::BodySize;
/// An interface types that can converted to bytes and used as response bodies. /// An interface types that can converted to bytes and used as response bodies.
// TODO: examples // TODO: examples
pub trait MessageBody { pub trait MessageBody {
// TODO: consider this bound to only fmt::Display since the error type is not really used /// The type of error that will be returned if streaming response fails.
// and there is an impl for Into<Box<StdError>> on String ///
type Error: Into<Box<dyn StdError>>; /// Since it is not appropriate to generate a response mid-stream, it only requires `Debug` for
/// internal logging.
type Error: fmt::Debug + 'static;
/// Body size hint. /// Body size hint.
fn size(&self) -> BodySize; fn size(&self) -> BodySize;
@ -450,7 +451,7 @@ impl<B, F, E> MessageBody for MessageBodyMapErr<B, F>
where where
B: MessageBody, B: MessageBody,
F: FnOnce(B::Error) -> E, F: FnOnce(B::Error) -> E,
E: Into<Box<dyn StdError>>, E: fmt::Debug + 'static,
{ {
type Error = E; type Error = E;

View File

@ -1,5 +1,5 @@
use std::{ use std::{
error::Error as StdError, fmt,
pin::Pin, pin::Pin,
task::{Context, Poll}, task::{Context, Poll},
}; };
@ -25,7 +25,7 @@ pin_project! {
impl<S, E> SizedStream<S> impl<S, E> SizedStream<S>
where where
S: Stream<Item = Result<Bytes, E>>, S: Stream<Item = Result<Bytes, E>>,
E: Into<Box<dyn StdError>> + 'static, E: fmt::Debug + 'static,
{ {
#[inline] #[inline]
pub fn new(size: u64, stream: S) -> Self { pub fn new(size: u64, stream: S) -> Self {
@ -38,7 +38,7 @@ where
impl<S, E> MessageBody for SizedStream<S> impl<S, E> MessageBody for SizedStream<S>
where where
S: Stream<Item = Result<Bytes, E>>, S: Stream<Item = Result<Bytes, E>>,
E: Into<Box<dyn StdError>> + 'static, E: fmt::Debug + 'static,
{ {
type Error = E; type Error = E;
@ -147,25 +147,4 @@ mod tests {
let body = SizedStream::new(1, stream::once(async { Err("stringy error") })); let body = SizedStream::new(1, stream::once(async { Err("stringy error") }));
assert!(matches!(to_bytes(body).await, 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"
);
}
} }

View File

@ -129,7 +129,7 @@ where
} }
EncoderBodyProj::Stream { body } => body EncoderBodyProj::Stream { body } => body
.poll_next(cx) .poll_next(cx)
.map_err(|err| EncoderError::Body(err.into())), .map_err(|err| EncoderError::Body(format!("{:?}", err).into())),
} }
} }

View File

@ -335,28 +335,27 @@ impl From<PayloadError> for Error {
#[derive(Debug, Display, Error, From)] #[derive(Debug, Display, Error, From)]
#[non_exhaustive] #[non_exhaustive]
pub enum DispatchError { pub enum DispatchError {
/// Service error /// Service error.
// FIXME: display and error type // FIXME: display and error type
#[display(fmt = "Service Error")] #[display(fmt = "Service Error")]
Service(#[error(not(source))] Response<BoxBody>), Service(#[error(not(source))] Response<BoxBody>),
/// Body error /// Body error.
// FIXME: display and error type
#[display(fmt = "Body Error")] #[display(fmt = "Body Error")]
Body(#[error(not(source))] Box<dyn StdError>), ResponseBody(#[error(not(source))] Box<dyn fmt::Debug>),
/// Upgrade service error /// Upgrade service error.
Upgrade, Upgrade,
/// An `io::Error` that occurred while trying to read or write to a network stream. /// An `io::Error` that occurred while trying to read or write to a network stream.
#[display(fmt = "IO error: {}", _0)] #[display(fmt = "IO error")]
Io(io::Error), Io(io::Error),
/// Http request parse error. /// Request parse error.
#[display(fmt = "Parse error: {}", _0)] #[display(fmt = "Request parse error")]
Parse(ParseError), Parse(ParseError),
/// Http/2 error /// HTTP/2 error.
#[display(fmt = "{}", _0)] #[display(fmt = "{}", _0)]
H2(h2::Error), H2(h2::Error),
@ -364,23 +363,23 @@ pub enum DispatchError {
#[display(fmt = "The first request did not complete within the specified timeout")] #[display(fmt = "The first request did not complete within the specified timeout")]
SlowRequestTimeout, SlowRequestTimeout,
/// Disconnect timeout. Makes sense for ssl streams. /// Disconnect timeout. Makes sense for TLS streams.
#[display(fmt = "Connection shutdown timeout")] #[display(fmt = "Connection shutdown timeout")]
DisconnectTimeout, DisconnectTimeout,
/// Payload is not consumed /// Payload is not consumed.
#[display(fmt = "Task is completed but request's payload is not consumed")] #[display(fmt = "Task is completed but request's payload is not consumed")]
PayloadIsNotConsumed, PayloadIsNotConsumed,
/// Malformed request /// Malformed request.
#[display(fmt = "Malformed request")] #[display(fmt = "Malformed request")]
MalformedRequest, MalformedRequest,
/// Internal error /// Internal error.
#[display(fmt = "Internal error")] #[display(fmt = "Internal error")]
InternalError, InternalError,
/// Unknown error /// Unknown error.
#[display(fmt = "Unknown error")] #[display(fmt = "Unknown error")]
Unknown, Unknown,
} }

View File

@ -426,7 +426,7 @@ where
} }
Poll::Ready(Some(Err(err))) => { Poll::Ready(Some(Err(err))) => {
return Err(DispatchError::Body(err.into())) return Err(DispatchError::ResponseBody(Box::new(err)))
} }
Poll::Pending => return Ok(PollResponse::DoNothing), Poll::Pending => return Ok(PollResponse::DoNothing),
@ -458,7 +458,7 @@ where
} }
Poll::Ready(Some(Err(err))) => { Poll::Ready(Some(Err(err))) => {
return Err(DispatchError::Service(err.into())) return Err(DispatchError::ResponseBody(err))
} }
Poll::Pending => return Ok(PollResponse::DoNothing), Poll::Pending => return Ok(PollResponse::DoNothing),

View File

@ -1,6 +1,5 @@
use std::{ use std::{
cmp, cmp, fmt,
error::Error as StdError,
future::Future, future::Future,
marker::PhantomData, marker::PhantomData,
net, net,
@ -14,6 +13,7 @@ use actix_rt::time::{sleep, Sleep};
use actix_service::Service; use actix_service::Service;
use actix_utils::future::poll_fn; use actix_utils::future::poll_fn;
use bytes::{Bytes, BytesMut}; use bytes::{Bytes, BytesMut};
use derive_more::{Display, Error};
use futures_core::ready; use futures_core::ready;
use h2::{ use h2::{
server::{Connection, SendResponse}, server::{Connection, SendResponse},
@ -187,10 +187,25 @@ where
} }
} }
#[derive(Debug, Display, Error)]
enum DispatchError { enum DispatchError {
/// Send response head failed.
#[display(fmt = "Send response head failed")]
SendResponse(h2::Error), SendResponse(h2::Error),
/// Send response data failed.
#[display(fmt = "Send response data failed")]
SendData(h2::Error), SendData(h2::Error),
ResponseBody(Box<dyn StdError>),
/// Receiving body chunk failed.
#[display(fmt = "Receiving body chunk failed")]
ResponseBody(#[error(not(source))] Box<dyn fmt::Debug>),
}
impl DispatchError {
fn response_body<E: fmt::Debug + 'static>(err: E) -> Self {
Self::ResponseBody(Box::new(err))
}
} }
async fn handle_response<B>( async fn handle_response<B>(
@ -221,7 +236,7 @@ where
actix_rt::pin!(body); actix_rt::pin!(body);
while let Some(res) = poll_fn(|cx| body.as_mut().poll_next(cx)).await { while let Some(res) = poll_fn(|cx| body.as_mut().poll_next(cx)).await {
let mut chunk = res.map_err(|err| DispatchError::ResponseBody(err.into()))?; let mut chunk = res.map_err(DispatchError::response_body)?;
'send: loop { 'send: loop {
let chunk_size = cmp::min(chunk.len(), CHUNK_SIZE); let chunk_size = cmp::min(chunk.len(), CHUNK_SIZE);

View File

@ -11,8 +11,6 @@ use pin_project_lite::pin_project;
use actix_http::body::{BodySize, BodyStream, BoxBody, MessageBody, SizedStream}; use actix_http::body::{BodySize, BodyStream, BoxBody, MessageBody, SizedStream};
use crate::BoxError;
pin_project! { pin_project! {
/// Represents various types of HTTP message body. /// Represents various types of HTTP message body.
#[derive(Clone)] #[derive(Clone)]
@ -117,7 +115,9 @@ where
} }
} }
AnyBodyProj::Body { body } => body.poll_next(cx).map_err(|err| err.into()), AnyBodyProj::Body { body } => body
.poll_next(cx)
.map_err(|err| format!("{:?}", err).into()),
} }
} }
} }
@ -213,7 +213,7 @@ impl<B> From<BytesMut> for AnyBody<B> {
impl<S, E> From<SizedStream<S>> for AnyBody impl<S, E> From<SizedStream<S>> for AnyBody
where where
S: Stream<Item = Result<Bytes, E>> + 'static, S: Stream<Item = Result<Bytes, E>> + 'static,
E: Into<BoxError> + 'static, E: fmt::Debug + 'static,
{ {
fn from(stream: SizedStream<S>) -> Self { fn from(stream: SizedStream<S>) -> Self {
AnyBody::new_boxed(stream) AnyBody::new_boxed(stream)
@ -223,7 +223,7 @@ where
impl<S, E> From<BodyStream<S>> for AnyBody impl<S, E> From<BodyStream<S>> for AnyBody
where where
S: Stream<Item = Result<Bytes, E>> + 'static, S: Stream<Item = Result<Bytes, E>> + 'static,
E: Into<BoxError> + 'static, E: fmt::Debug + 'static,
{ {
fn from(stream: BodyStream<S>) -> Self { fn from(stream: BodyStream<S>) -> Self {
AnyBody::new_boxed(stream) AnyBody::new_boxed(stream)

View File

@ -1,4 +1,4 @@
use std::{convert::TryFrom, net, rc::Rc, time::Duration}; use std::{convert::TryFrom, fmt, net, rc::Rc, time::Duration};
use bytes::Bytes; use bytes::Bytes;
use futures_core::Stream; use futures_core::Stream;
@ -13,7 +13,7 @@ use actix_http::{
use crate::{ use crate::{
any_body::AnyBody, any_body::AnyBody,
sender::{RequestSender, SendClientRequest}, sender::{RequestSender, SendClientRequest},
BoxError, ClientConfig, ClientConfig,
}; };
/// `FrozenClientRequest` struct represents cloneable client request. /// `FrozenClientRequest` struct represents cloneable client request.
@ -83,7 +83,7 @@ impl FrozenClientRequest {
pub fn send_stream<S, E>(&self, stream: S) -> SendClientRequest pub fn send_stream<S, E>(&self, stream: S) -> SendClientRequest
where where
S: Stream<Item = Result<Bytes, E>> + Unpin + 'static, S: Stream<Item = Result<Bytes, E>> + Unpin + 'static,
E: Into<BoxError> + 'static, E: fmt::Debug + 'static,
{ {
RequestSender::Rc(self.head.clone(), None).send_stream( RequestSender::Rc(self.head.clone(), None).send_stream(
self.addr, self.addr,
@ -208,7 +208,7 @@ impl FrozenSendBuilder {
pub fn send_stream<S, E>(self, stream: S) -> SendClientRequest pub fn send_stream<S, E>(self, stream: S) -> SendClientRequest
where where
S: Stream<Item = Result<Bytes, E>> + Unpin + 'static, S: Stream<Item = Result<Bytes, E>> + Unpin + 'static,
E: Into<BoxError> + 'static, E: fmt::Debug + 'static,
{ {
if let Some(e) = self.err { if let Some(e) = self.err {
return e.into(); return e.into();

View File

@ -15,7 +15,7 @@ use crate::{
error::{FreezeRequestError, InvalidUrl}, error::{FreezeRequestError, InvalidUrl},
frozen::FrozenClientRequest, frozen::FrozenClientRequest,
sender::{PrepForSendingError, RequestSender, SendClientRequest}, sender::{PrepForSendingError, RequestSender, SendClientRequest},
BoxError, ClientConfig, ClientConfig,
}; };
#[cfg(feature = "cookies")] #[cfg(feature = "cookies")]
@ -394,7 +394,7 @@ impl ClientRequest {
pub fn send_stream<S, E>(self, stream: S) -> SendClientRequest pub fn send_stream<S, E>(self, stream: S) -> SendClientRequest
where where
S: Stream<Item = Result<Bytes, E>> + Unpin + 'static, S: Stream<Item = Result<Bytes, E>> + Unpin + 'static,
E: Into<BoxError> + 'static, E: fmt::Debug + 'static,
{ {
let slf = match self.prep_for_sending() { let slf = match self.prep_for_sending() {
Ok(slf) => slf, Ok(slf) => slf,

View File

@ -1,4 +1,5 @@
use std::{ use std::{
fmt,
future::Future, future::Future,
net, net,
pin::Pin, pin::Pin,
@ -25,7 +26,7 @@ use actix_http::{encoding::Decoder, header::ContentEncoding, Payload, PayloadStr
use crate::{ use crate::{
any_body::AnyBody, any_body::AnyBody,
error::{FreezeRequestError, InvalidUrl, SendRequestError}, error::{FreezeRequestError, InvalidUrl, SendRequestError},
BoxError, ClientConfig, ClientResponse, ConnectRequest, ConnectResponse, ClientConfig, ClientResponse, ConnectRequest, ConnectResponse,
}; };
#[derive(Debug, From)] #[derive(Debug, From)]
@ -275,7 +276,7 @@ impl RequestSender {
) -> SendClientRequest ) -> SendClientRequest
where where
S: Stream<Item = Result<Bytes, E>> + Unpin + 'static, S: Stream<Item = Result<Bytes, E>> + Unpin + 'static,
E: Into<BoxError> + 'static, E: fmt::Debug + 'static,
{ {
self.send_body( self.send_body(
addr, addr,

View File

@ -3,6 +3,8 @@
//! Most users will not have to interact with the types in this module, but it is useful for those //! Most users will not have to interact with the types in this module, but it is useful for those
//! writing extractors, middleware, libraries, or interacting with the service API directly. //! writing extractors, middleware, libraries, or interacting with the service API directly.
use std::fmt;
pub use crate::config::{AppConfig, AppService}; pub use crate::config::{AppConfig, AppService};
#[doc(hidden)] #[doc(hidden)]
pub use crate::handler::Handler; pub use crate::handler::Handler;
@ -114,7 +116,7 @@ pub(crate) enum AnyBody {
} }
impl crate::body::MessageBody for AnyBody { impl crate::body::MessageBody for AnyBody {
type Error = crate::BoxError; type Error = Box<dyn fmt::Debug>;
/// Body size hint. /// Body size hint.
fn size(&self) -> crate::body::BodySize { fn size(&self) -> crate::body::BodySize {

View File

@ -1,11 +1,11 @@
use std::future::Future; use std::{fmt, future::Future};
use actix_service::{boxed, fn_service}; use actix_service::{boxed, fn_service};
use crate::{ use crate::{
body::MessageBody, body::MessageBody,
service::{BoxedHttpServiceFactory, ServiceRequest, ServiceResponse}, service::{BoxedHttpServiceFactory, ServiceRequest, ServiceResponse},
BoxError, FromRequest, HttpResponse, Responder, FromRequest, HttpResponse, Responder,
}; };
/// A request handler is an async function that accepts zero or more parameters that can be /// A request handler is an async function that accepts zero or more parameters that can be
@ -31,7 +31,7 @@ where
R: Future, R: Future,
R::Output: Responder, R::Output: Responder,
<R::Output as Responder>::Body: MessageBody, <R::Output as Responder>::Body: MessageBody,
<<R::Output as Responder>::Body as MessageBody>::Error: Into<BoxError>, <<R::Output as Responder>::Body as MessageBody>::Error: fmt::Debug,
{ {
boxed::factory(fn_service(move |req: ServiceRequest| { boxed::factory(fn_service(move |req: ServiceRequest| {
let handler = handler.clone(); let handler = handler.clone();

View File

@ -113,5 +113,3 @@ pub use crate::route::Route;
pub use crate::scope::Scope; pub use crate::scope::Scope;
pub use crate::server::HttpServer; pub use crate::server::HttpServer;
pub use crate::types::Either; pub use crate::types::Either;
pub(crate) type BoxError = Box<dyn std::error::Error>;

View File

@ -325,9 +325,8 @@ pin_project! {
impl<B> MessageBody for StreamLog<B> impl<B> MessageBody for StreamLog<B>
where where
B: MessageBody, B: MessageBody,
B::Error: Into<Error>,
{ {
type Error = Error; type Error = B::Error;
fn size(&self) -> BodySize { fn size(&self) -> BodySize {
self.body.size() self.body.size()
@ -344,7 +343,7 @@ where
*this.size += chunk.len(); *this.size += chunk.len();
Poll::Ready(Some(Ok(chunk))) Poll::Ready(Some(Ok(chunk)))
} }
Some(Err(err)) => Poll::Ready(Some(Err(err.into()))), Some(Err(err)) => Poll::Ready(Some(Err(err))),
None => Poll::Ready(None), None => Poll::Ready(None),
} }
} }

View File

@ -20,7 +20,7 @@ use crate::{
BoxedHttpService, BoxedHttpServiceFactory, HttpServiceFactory, ServiceRequest, BoxedHttpService, BoxedHttpServiceFactory, HttpServiceFactory, ServiceRequest,
ServiceResponse, ServiceResponse,
}, },
BoxError, Error, FromRequest, HttpResponse, Responder, Error, FromRequest, HttpResponse, Responder,
}; };
/// *Resource* is an entry in resources table which corresponds to requested URL. /// *Resource* is an entry in resources table which corresponds to requested URL.
@ -239,7 +239,7 @@ where
R: Future + 'static, R: Future + 'static,
R::Output: Responder + 'static, R::Output: Responder + 'static,
<R::Output as Responder>::Body: MessageBody, <R::Output as Responder>::Body: MessageBody,
<<R::Output as Responder>::Body as MessageBody>::Error: Into<BoxError>, <<R::Output as Responder>::Body as MessageBody>::Error: fmt::Debug,
{ {
self.routes.push(Route::new().to(handler)); self.routes.push(Route::new().to(handler));
self self

View File

@ -1,6 +1,7 @@
use std::{ use std::{
cell::{Ref, RefMut}, cell::{Ref, RefMut},
convert::TryInto, convert::TryInto,
fmt,
future::Future, future::Future,
pin::Pin, pin::Pin,
task::{Context, Poll}, task::{Context, Poll},
@ -23,7 +24,7 @@ use cookie::{Cookie, CookieJar};
use crate::{ use crate::{
error::{Error, JsonPayloadError}, error::{Error, JsonPayloadError},
BoxError, HttpResponse, HttpResponse,
}; };
/// An HTTP response builder. /// An HTTP response builder.
@ -349,7 +350,7 @@ impl HttpResponseBuilder {
pub fn streaming<S, E>(&mut self, stream: S) -> HttpResponse pub fn streaming<S, E>(&mut self, stream: S) -> HttpResponse
where where
S: Stream<Item = Result<Bytes, E>> + 'static, S: Stream<Item = Result<Bytes, E>> + 'static,
E: Into<BoxError> + 'static, E: fmt::Debug + 'static,
{ {
self.body(BodyStream::new(stream)) self.body(BodyStream::new(stream))
} }

View File

@ -1,3 +1,5 @@
use std::fmt;
use actix_http::{ use actix_http::{
body::{EitherBody, MessageBody}, body::{EitherBody, MessageBody},
error::HttpError, error::HttpError,
@ -6,7 +8,7 @@ use actix_http::{
StatusCode, StatusCode,
}; };
use crate::{BoxError, HttpRequest, HttpResponse, Responder}; use crate::{HttpRequest, HttpResponse, Responder};
/// Allows overriding status code and headers for a [`Responder`]. /// Allows overriding status code and headers for a [`Responder`].
/// ///
@ -143,7 +145,7 @@ impl<R: Responder> CustomizeResponder<R> {
impl<T> Responder for CustomizeResponder<T> impl<T> Responder for CustomizeResponder<T>
where where
T: Responder, T: Responder,
<T::Body as MessageBody>::Error: Into<BoxError>, <T::Body as MessageBody>::Error: fmt::Debug,
{ {
type Body = EitherBody<T::Body>; type Body = EitherBody<T::Body>;

View File

@ -1,4 +1,4 @@
use std::borrow::Cow; use std::{borrow::Cow, fmt};
use actix_http::{ use actix_http::{
body::{BoxBody, EitherBody, MessageBody}, body::{BoxBody, EitherBody, MessageBody},
@ -7,7 +7,7 @@ use actix_http::{
}; };
use bytes::{Bytes, BytesMut}; use bytes::{Bytes, BytesMut};
use crate::{BoxError, Error, HttpRequest, HttpResponse, HttpResponseBuilder}; use crate::{Error, HttpRequest, HttpResponse, HttpResponseBuilder};
use super::CustomizeResponder; use super::CustomizeResponder;
@ -96,7 +96,7 @@ impl Responder for actix_http::ResponseBuilder {
impl<T> Responder for Option<T> impl<T> Responder for Option<T>
where where
T: Responder, T: Responder,
<T::Body as MessageBody>::Error: Into<BoxError>, <T::Body as MessageBody>::Error: fmt::Debug,
{ {
type Body = EitherBody<T::Body>; type Body = EitherBody<T::Body>;
@ -111,7 +111,7 @@ where
impl<T, E> Responder for Result<T, E> impl<T, E> Responder for Result<T, E>
where where
T: Responder, T: Responder,
<T::Body as MessageBody>::Error: Into<BoxError>, <T::Body as MessageBody>::Error: fmt::Debug,
E: Into<Error>, E: Into<Error>,
{ {
type Body = EitherBody<T::Body>; type Body = EitherBody<T::Body>;

View File

@ -1,4 +1,4 @@
use std::{future::Future, mem, rc::Rc}; use std::{fmt, future::Future, mem, rc::Rc};
use actix_http::Method; use actix_http::Method;
use actix_service::{ use actix_service::{
@ -12,7 +12,7 @@ use crate::{
guard::{self, Guard}, guard::{self, Guard},
handler::{handler_service, Handler}, handler::{handler_service, Handler},
service::{BoxedHttpServiceFactory, ServiceRequest, ServiceResponse}, service::{BoxedHttpServiceFactory, ServiceRequest, ServiceResponse},
BoxError, Error, FromRequest, HttpResponse, Responder, Error, FromRequest, HttpResponse, Responder,
}; };
/// Resource route definition /// Resource route definition
@ -183,7 +183,7 @@ impl Route {
R: Future + 'static, R: Future + 'static,
R::Output: Responder + 'static, R::Output: Responder + 'static,
<R::Output as Responder>::Body: MessageBody, <R::Output as Responder>::Body: MessageBody,
<<R::Output as Responder>::Body as MessageBody>::Error: Into<BoxError>, <<R::Output as Responder>::Body as MessageBody>::Error: fmt::Debug,
{ {
self.service = handler_service(handler); self.service = handler_service(handler);
self self

View File

@ -470,7 +470,6 @@ impl<B> From<ServiceResponse<B>> for Response<B> {
impl<B> fmt::Debug for ServiceResponse<B> impl<B> fmt::Debug for ServiceResponse<B>
where where
B: MessageBody, B: MessageBody,
B::Error: Into<Error>,
{ {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let res = writeln!( let res = writeln!(

View File

@ -1,6 +1,6 @@
//! Essentials helper functions and types for application registration. //! Essentials helper functions and types for application registration.
use std::{error::Error as StdError, future::Future}; use std::{fmt, future::Future};
use actix_http::Method; use actix_http::Method;
use actix_router::IntoPatterns; use actix_router::IntoPatterns;
@ -146,7 +146,7 @@ where
R: Future + 'static, R: Future + 'static,
R::Output: Responder + 'static, R::Output: Responder + 'static,
<R::Output as Responder>::Body: MessageBody + 'static, <R::Output as Responder>::Body: MessageBody + 'static,
<<R::Output as Responder>::Body as MessageBody>::Error: Into<Box<dyn StdError + 'static>>, <<R::Output as Responder>::Body as MessageBody>::Error: fmt::Debug,
{ {
Route::new().to(handler) Route::new().to(handler)
} }