1
0
Fork 0
mirror of https://github.com/actix/actix-web.git synced 2024-06-27 09:30:39 +00:00

remove unpin from body types (#2152)

This commit is contained in:
Rob Ede 2021-04-13 11:16:12 +01:00 committed by GitHub
parent ce50cc9523
commit edd9f14752
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 241 additions and 194 deletions

View file

@ -1,6 +1,14 @@
# Changes # Changes
## Unreleased - 2021-xx-xx ## Unreleased - 2021-xx-xx
### Added
* `impl<T: MessageBody> MessageBody for Pin<Box<T>>`. [#2152]
### Changes
* The type parameter of `Response` no longer has a default. [#2152]
* The `Message` variant of `body::Body` is now `Pin<Box<dyn MessageBody>>`. [#2152]
* `BodyStream` and `SizedStream` are no longer restricted to Unpin types. [#2152]
### Removed ### Removed
* `cookies` feature flag. [#2065] * `cookies` feature flag. [#2065]
* Top-level `cookies` mod (re-export). [#2065] * Top-level `cookies` mod (re-export). [#2065]
@ -13,6 +21,7 @@
[#2065]: https://github.com/actix/actix-web/pull/2065 [#2065]: https://github.com/actix/actix-web/pull/2065
[#2148]: https://github.com/actix/actix-web/pull/2148 [#2148]: https://github.com/actix/actix-web/pull/2148
[#2152]: https://github.com/actix/actix-web/pull/2152
## 3.0.0-beta.5 - 2021-04-02 ## 3.0.0-beta.5 - 2021-04-02

View file

@ -1,13 +1,13 @@
use std::{env, io}; use std::{env, io};
use actix_http::http::HeaderValue; use actix_http::{body::Body, http::HeaderValue};
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 _;
use log::info; use log::info;
async fn handle_request(mut req: Request) -> Result<Response, Error> { async fn handle_request(mut req: Request) -> Result<Response<Body>, 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?)

View file

@ -12,15 +12,19 @@ use crate::error::Error;
use super::{BodySize, BodyStream, MessageBody, SizedStream}; use super::{BodySize, BodyStream, MessageBody, SizedStream};
/// Represents various types of HTTP message body. /// Represents various types of HTTP message body.
// #[deprecated(since = "4.0.0", note = "Use body types directly.")]
pub enum Body { pub enum Body {
/// 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`. /// Zero sized response body. `Content-Length` header is set to `0`.
Empty, Empty,
/// Specific response body. /// Specific response body.
Bytes(Bytes), Bytes(Bytes),
/// Generic message body. /// Generic message body.
Message(Box<dyn MessageBody + Unpin>), Message(Pin<Box<dyn MessageBody>>),
} }
impl Body { impl Body {
@ -30,8 +34,8 @@ impl Body {
} }
/// Create body from generic message body. /// Create body from generic message body.
pub fn from_message<B: MessageBody + Unpin + 'static>(body: B) -> Body { pub fn from_message<B: MessageBody + 'static>(body: B) -> Body {
Body::Message(Box::new(body)) Body::Message(Box::pin(body))
} }
} }
@ -60,7 +64,7 @@ impl MessageBody for Body {
Poll::Ready(Some(Ok(mem::take(bin)))) Poll::Ready(Some(Ok(mem::take(bin))))
} }
} }
Body::Message(body) => Pin::new(&mut **body).poll_next(cx), Body::Message(body) => body.as_mut().poll_next(cx),
} }
} }
} }
@ -134,7 +138,7 @@ impl From<BytesMut> for Body {
impl<S> From<SizedStream<S>> for Body impl<S> From<SizedStream<S>> for Body
where where
S: Stream<Item = Result<Bytes, Error>> + Unpin + 'static, S: Stream<Item = Result<Bytes, Error>> + 'static,
{ {
fn from(s: SizedStream<S>) -> Body { fn from(s: SizedStream<S>) -> Body {
Body::from_message(s) Body::from_message(s)
@ -143,7 +147,7 @@ where
impl<S, E> From<BodyStream<S>> for Body impl<S, E> From<BodyStream<S>> for Body
where where
S: Stream<Item = Result<Bytes, E>> + Unpin + 'static, S: Stream<Item = Result<Bytes, E>> + 'static,
E: Into<Error> + 'static, E: Into<Error> + 'static,
{ {
fn from(s: BodyStream<S>) -> Body { fn from(s: BodyStream<S>) -> Body {

View file

@ -5,21 +5,25 @@ use std::{
use bytes::Bytes; use bytes::Bytes;
use futures_core::{ready, Stream}; use futures_core::{ready, Stream};
use pin_project_lite::pin_project;
use crate::error::Error; use crate::error::Error;
use super::{BodySize, MessageBody}; use super::{BodySize, MessageBody};
/// Streaming response wrapper. pin_project! {
/// /// Streaming response wrapper.
/// Response does not contain `Content-Length` header and appropriate transfer encoding is used. ///
pub struct BodyStream<S: Unpin> { /// Response does not contain `Content-Length` header and appropriate transfer encoding is used.
stream: S, pub struct BodyStream<S> {
#[pin]
stream: S,
}
} }
impl<S, E> BodyStream<S> impl<S, E> BodyStream<S>
where where
S: Stream<Item = Result<Bytes, E>> + Unpin, S: Stream<Item = Result<Bytes, E>>,
E: Into<Error>, E: Into<Error>,
{ {
pub fn new(stream: S) -> Self { pub fn new(stream: S) -> Self {
@ -29,7 +33,7 @@ where
impl<S, E> MessageBody for BodyStream<S> impl<S, E> MessageBody for BodyStream<S>
where where
S: Stream<Item = Result<Bytes, E>> + Unpin, S: Stream<Item = Result<Bytes, E>>,
E: Into<Error>, E: Into<Error>,
{ {
fn size(&self) -> BodySize { fn size(&self) -> BodySize {
@ -46,9 +50,9 @@ where
cx: &mut Context<'_>, cx: &mut Context<'_>,
) -> Poll<Option<Result<Bytes, Error>>> { ) -> Poll<Option<Result<Bytes, Error>>> {
loop { loop {
let stream = &mut self.as_mut().stream; let stream = self.as_mut().project().stream;
let chunk = match ready!(Pin::new(stream).poll_next(cx)) { let chunk = match ready!(stream.poll_next(cx)) {
Some(Ok(ref bytes)) if bytes.is_empty() => continue, Some(Ok(ref bytes)) if bytes.is_empty() => continue,
opt => opt.map(|res| res.map_err(Into::into)), opt => opt.map(|res| res.map_err(Into::into)),
}; };

View file

@ -52,6 +52,19 @@ impl<T: MessageBody + Unpin> MessageBody for Box<T> {
} }
} }
impl<T: MessageBody> MessageBody for Pin<Box<T>> {
fn size(&self) -> BodySize {
self.as_ref().size()
}
fn poll_next(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Option<Result<Bytes, Error>>> {
self.as_mut().poll_next(cx)
}
}
impl MessageBody for Bytes { impl MessageBody for Bytes {
fn size(&self) -> BodySize { fn size(&self) -> BodySize {
BodySize::Sized(self.len() as u64) BodySize::Sized(self.len() as u64)

View file

@ -5,23 +5,27 @@ use std::{
use bytes::Bytes; use bytes::Bytes;
use futures_core::{ready, Stream}; use futures_core::{ready, Stream};
use pin_project_lite::pin_project;
use crate::error::Error; use crate::error::Error;
use super::{BodySize, MessageBody}; use super::{BodySize, MessageBody};
/// Known sized streaming response wrapper. pin_project! {
/// /// Known sized streaming response wrapper.
/// This body implementation should be used if total size of stream is known. Data get sent as is ///
/// without using transfer encoding. /// This body implementation should be used if total size of stream is known. Data get sent as is
pub struct SizedStream<S: Unpin> { /// without using transfer encoding.
size: u64, pub struct SizedStream<S> {
stream: S, size: u64,
#[pin]
stream: S,
}
} }
impl<S> SizedStream<S> impl<S> SizedStream<S>
where where
S: Stream<Item = Result<Bytes, Error>> + Unpin, S: Stream<Item = Result<Bytes, Error>>,
{ {
pub fn new(size: u64, stream: S) -> Self { pub fn new(size: u64, stream: S) -> Self {
SizedStream { size, stream } SizedStream { size, stream }
@ -30,7 +34,7 @@ where
impl<S> MessageBody for SizedStream<S> impl<S> MessageBody for SizedStream<S>
where where
S: Stream<Item = Result<Bytes, Error>> + Unpin, S: Stream<Item = Result<Bytes, Error>>,
{ {
fn size(&self) -> BodySize { fn size(&self) -> BodySize {
BodySize::Sized(self.size as u64) BodySize::Sized(self.size as u64)
@ -46,9 +50,9 @@ where
cx: &mut Context<'_>, cx: &mut Context<'_>,
) -> Poll<Option<Result<Bytes, Error>>> { ) -> Poll<Option<Result<Bytes, Error>>> {
loop { loop {
let stream = &mut self.as_mut().stream; let stream = self.as_mut().project().stream;
let chunk = match ready!(Pin::new(stream).poll_next(cx)) { let chunk = match ready!(stream.poll_next(cx)) {
Some(Ok(ref bytes)) if bytes.is_empty() => continue, Some(Ok(ref bytes)) if bytes.is_empty() => continue,
val => val, val => val,
}; };

View file

@ -92,7 +92,7 @@ impl<B: MessageBody> Encoder<B> {
enum EncoderBody<B> { enum EncoderBody<B> {
Bytes(Bytes), Bytes(Bytes),
Stream(#[pin] B), Stream(#[pin] B),
BoxedStream(Box<dyn MessageBody + Unpin>), BoxedStream(Pin<Box<dyn MessageBody>>),
} }
impl<B: MessageBody> MessageBody for EncoderBody<B> { impl<B: MessageBody> MessageBody for EncoderBody<B> {
@ -117,9 +117,7 @@ impl<B: MessageBody> MessageBody for EncoderBody<B> {
} }
} }
EncoderBodyProj::Stream(b) => b.poll_next(cx), EncoderBodyProj::Stream(b) => b.poll_next(cx),
EncoderBodyProj::BoxedStream(ref mut b) => { EncoderBodyProj::BoxedStream(ref mut b) => b.as_mut().poll_next(cx),
Pin::new(b.as_mut()).poll_next(cx)
}
} }
} }
} }

View file

@ -62,7 +62,7 @@ pub trait ResponseError: fmt::Debug + fmt::Display {
/// Create response for error /// Create response for error
/// ///
/// Internal server error is generated by default. /// Internal server error is generated by default.
fn error_response(&self) -> Response { fn error_response(&self) -> Response<Body> {
let mut resp = Response::new(self.status_code()); let mut resp = Response::new(self.status_code());
let mut buf = BytesMut::new(); let mut buf = BytesMut::new();
let _ = write!(Writer(&mut buf), "{}", self); let _ = write!(Writer(&mut buf), "{}", self);
@ -111,7 +111,7 @@ impl From<std::convert::Infallible> for Error {
} }
/// Convert `Error` to a `Response` instance /// Convert `Error` to a `Response` instance
impl From<Error> for Response { impl From<Error> for Response<Body> {
fn from(err: Error) -> Self { fn from(err: Error) -> Self {
Response::from_error(err) Response::from_error(err)
} }
@ -127,8 +127,8 @@ impl<T: ResponseError + 'static> From<T> for Error {
} }
/// Convert Response to a Error /// Convert Response to a Error
impl From<Response> for Error { impl From<Response<Body>> for Error {
fn from(res: Response) -> Error { fn from(res: Response<Body>) -> Error {
InternalError::from_response("", res).into() InternalError::from_response("", res).into()
} }
} }
@ -454,7 +454,7 @@ pub struct InternalError<T> {
enum InternalErrorType { enum InternalErrorType {
Status(StatusCode), Status(StatusCode),
Response(RefCell<Option<Response>>), Response(RefCell<Option<Response<Body>>>),
} }
impl<T> InternalError<T> { impl<T> InternalError<T> {
@ -467,7 +467,7 @@ impl<T> InternalError<T> {
} }
/// Create `InternalError` with predefined `Response`. /// Create `InternalError` with predefined `Response`.
pub fn from_response(cause: T, response: Response) -> Self { pub fn from_response(cause: T, response: Response<Body>) -> Self {
InternalError { InternalError {
cause, cause,
status: InternalErrorType::Response(RefCell::new(Some(response))), status: InternalErrorType::Response(RefCell::new(Some(response))),
@ -510,7 +510,7 @@ where
} }
} }
fn error_response(&self) -> Response { fn error_response(&self) -> Response<Body> {
match self.status { match self.status {
InternalErrorType::Status(st) => { InternalErrorType::Status(st) => {
let mut res = Response::new(st); let mut res = Response::new(st);
@ -931,11 +931,11 @@ mod tests {
#[test] #[test]
fn test_into_response() { fn test_into_response() {
let resp: Response = ParseError::Incomplete.error_response(); let resp: Response<Body> = ParseError::Incomplete.error_response();
assert_eq!(resp.status(), StatusCode::BAD_REQUEST); assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
let err: HttpError = StatusCode::from_u16(10000).err().unwrap().into(); let err: HttpError = StatusCode::from_u16(10000).err().unwrap().into();
let resp: Response = err.error_response(); let resp: Response<Body> = err.error_response();
assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR); assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
} }
@ -966,7 +966,7 @@ mod tests {
fn test_error_http_response() { fn test_error_http_response() {
let orig = io::Error::new(io::ErrorKind::Other, "other"); let orig = io::Error::new(io::ErrorKind::Other, "other");
let e = Error::from(orig); let e = Error::from(orig);
let resp: Response = e.into(); let resp: Response<Body> = e.into();
assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR); assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
} }
@ -1023,7 +1023,7 @@ mod tests {
fn test_internal_error() { fn test_internal_error() {
let err = let err =
InternalError::from_response(ParseError::Method, Response::Ok().into()); InternalError::from_response(ParseError::Method, Response::Ok().into());
let resp: Response = err.error_response(); let resp: Response<Body> = err.error_response();
assert_eq!(resp.status(), StatusCode::OK); assert_eq!(resp.status(), StatusCode::OK);
} }
@ -1039,121 +1039,121 @@ mod tests {
#[test] #[test]
fn test_error_helpers() { fn test_error_helpers() {
let r: Response = ErrorBadRequest("err").into(); let res: Response<Body> = ErrorBadRequest("err").into();
assert_eq!(r.status(), StatusCode::BAD_REQUEST); assert_eq!(res.status(), StatusCode::BAD_REQUEST);
let r: Response = ErrorUnauthorized("err").into(); let res: Response<Body> = ErrorUnauthorized("err").into();
assert_eq!(r.status(), StatusCode::UNAUTHORIZED); assert_eq!(res.status(), StatusCode::UNAUTHORIZED);
let r: Response = ErrorPaymentRequired("err").into(); let res: Response<Body> = ErrorPaymentRequired("err").into();
assert_eq!(r.status(), StatusCode::PAYMENT_REQUIRED); assert_eq!(res.status(), StatusCode::PAYMENT_REQUIRED);
let r: Response = ErrorForbidden("err").into(); let res: Response<Body> = ErrorForbidden("err").into();
assert_eq!(r.status(), StatusCode::FORBIDDEN); assert_eq!(res.status(), StatusCode::FORBIDDEN);
let r: Response = ErrorNotFound("err").into(); let res: Response<Body> = ErrorNotFound("err").into();
assert_eq!(r.status(), StatusCode::NOT_FOUND); assert_eq!(res.status(), StatusCode::NOT_FOUND);
let r: Response = ErrorMethodNotAllowed("err").into(); let res: Response<Body> = ErrorMethodNotAllowed("err").into();
assert_eq!(r.status(), StatusCode::METHOD_NOT_ALLOWED); assert_eq!(res.status(), StatusCode::METHOD_NOT_ALLOWED);
let r: Response = ErrorNotAcceptable("err").into(); let res: Response<Body> = ErrorNotAcceptable("err").into();
assert_eq!(r.status(), StatusCode::NOT_ACCEPTABLE); assert_eq!(res.status(), StatusCode::NOT_ACCEPTABLE);
let r: Response = ErrorProxyAuthenticationRequired("err").into(); let res: Response<Body> = ErrorProxyAuthenticationRequired("err").into();
assert_eq!(r.status(), StatusCode::PROXY_AUTHENTICATION_REQUIRED); assert_eq!(res.status(), StatusCode::PROXY_AUTHENTICATION_REQUIRED);
let r: Response = ErrorRequestTimeout("err").into(); let res: Response<Body> = ErrorRequestTimeout("err").into();
assert_eq!(r.status(), StatusCode::REQUEST_TIMEOUT); assert_eq!(res.status(), StatusCode::REQUEST_TIMEOUT);
let r: Response = ErrorConflict("err").into(); let res: Response<Body> = ErrorConflict("err").into();
assert_eq!(r.status(), StatusCode::CONFLICT); assert_eq!(res.status(), StatusCode::CONFLICT);
let r: Response = ErrorGone("err").into(); let res: Response<Body> = ErrorGone("err").into();
assert_eq!(r.status(), StatusCode::GONE); assert_eq!(res.status(), StatusCode::GONE);
let r: Response = ErrorLengthRequired("err").into(); let res: Response<Body> = ErrorLengthRequired("err").into();
assert_eq!(r.status(), StatusCode::LENGTH_REQUIRED); assert_eq!(res.status(), StatusCode::LENGTH_REQUIRED);
let r: Response = ErrorPreconditionFailed("err").into(); let res: Response<Body> = ErrorPreconditionFailed("err").into();
assert_eq!(r.status(), StatusCode::PRECONDITION_FAILED); assert_eq!(res.status(), StatusCode::PRECONDITION_FAILED);
let r: Response = ErrorPayloadTooLarge("err").into(); let res: Response<Body> = ErrorPayloadTooLarge("err").into();
assert_eq!(r.status(), StatusCode::PAYLOAD_TOO_LARGE); assert_eq!(res.status(), StatusCode::PAYLOAD_TOO_LARGE);
let r: Response = ErrorUriTooLong("err").into(); let res: Response<Body> = ErrorUriTooLong("err").into();
assert_eq!(r.status(), StatusCode::URI_TOO_LONG); assert_eq!(res.status(), StatusCode::URI_TOO_LONG);
let r: Response = ErrorUnsupportedMediaType("err").into(); let res: Response<Body> = ErrorUnsupportedMediaType("err").into();
assert_eq!(r.status(), StatusCode::UNSUPPORTED_MEDIA_TYPE); assert_eq!(res.status(), StatusCode::UNSUPPORTED_MEDIA_TYPE);
let r: Response = ErrorRangeNotSatisfiable("err").into(); let res: Response<Body> = ErrorRangeNotSatisfiable("err").into();
assert_eq!(r.status(), StatusCode::RANGE_NOT_SATISFIABLE); assert_eq!(res.status(), StatusCode::RANGE_NOT_SATISFIABLE);
let r: Response = ErrorExpectationFailed("err").into(); let res: Response<Body> = ErrorExpectationFailed("err").into();
assert_eq!(r.status(), StatusCode::EXPECTATION_FAILED); assert_eq!(res.status(), StatusCode::EXPECTATION_FAILED);
let r: Response = ErrorImATeapot("err").into(); let res: Response<Body> = ErrorImATeapot("err").into();
assert_eq!(r.status(), StatusCode::IM_A_TEAPOT); assert_eq!(res.status(), StatusCode::IM_A_TEAPOT);
let r: Response = ErrorMisdirectedRequest("err").into(); let res: Response<Body> = ErrorMisdirectedRequest("err").into();
assert_eq!(r.status(), StatusCode::MISDIRECTED_REQUEST); assert_eq!(res.status(), StatusCode::MISDIRECTED_REQUEST);
let r: Response = ErrorUnprocessableEntity("err").into(); let res: Response<Body> = ErrorUnprocessableEntity("err").into();
assert_eq!(r.status(), StatusCode::UNPROCESSABLE_ENTITY); assert_eq!(res.status(), StatusCode::UNPROCESSABLE_ENTITY);
let r: Response = ErrorLocked("err").into(); let res: Response<Body> = ErrorLocked("err").into();
assert_eq!(r.status(), StatusCode::LOCKED); assert_eq!(res.status(), StatusCode::LOCKED);
let r: Response = ErrorFailedDependency("err").into(); let res: Response<Body> = ErrorFailedDependency("err").into();
assert_eq!(r.status(), StatusCode::FAILED_DEPENDENCY); assert_eq!(res.status(), StatusCode::FAILED_DEPENDENCY);
let r: Response = ErrorUpgradeRequired("err").into(); let res: Response<Body> = ErrorUpgradeRequired("err").into();
assert_eq!(r.status(), StatusCode::UPGRADE_REQUIRED); assert_eq!(res.status(), StatusCode::UPGRADE_REQUIRED);
let r: Response = ErrorPreconditionRequired("err").into(); let res: Response<Body> = ErrorPreconditionRequired("err").into();
assert_eq!(r.status(), StatusCode::PRECONDITION_REQUIRED); assert_eq!(res.status(), StatusCode::PRECONDITION_REQUIRED);
let r: Response = ErrorTooManyRequests("err").into(); let res: Response<Body> = ErrorTooManyRequests("err").into();
assert_eq!(r.status(), StatusCode::TOO_MANY_REQUESTS); assert_eq!(res.status(), StatusCode::TOO_MANY_REQUESTS);
let r: Response = ErrorRequestHeaderFieldsTooLarge("err").into(); let res: Response<Body> = ErrorRequestHeaderFieldsTooLarge("err").into();
assert_eq!(r.status(), StatusCode::REQUEST_HEADER_FIELDS_TOO_LARGE); assert_eq!(res.status(), StatusCode::REQUEST_HEADER_FIELDS_TOO_LARGE);
let r: Response = ErrorUnavailableForLegalReasons("err").into(); let res: Response<Body> = ErrorUnavailableForLegalReasons("err").into();
assert_eq!(r.status(), StatusCode::UNAVAILABLE_FOR_LEGAL_REASONS); assert_eq!(res.status(), StatusCode::UNAVAILABLE_FOR_LEGAL_REASONS);
let r: Response = ErrorInternalServerError("err").into(); let res: Response<Body> = ErrorInternalServerError("err").into();
assert_eq!(r.status(), StatusCode::INTERNAL_SERVER_ERROR); assert_eq!(res.status(), StatusCode::INTERNAL_SERVER_ERROR);
let r: Response = ErrorNotImplemented("err").into(); let res: Response<Body> = ErrorNotImplemented("err").into();
assert_eq!(r.status(), StatusCode::NOT_IMPLEMENTED); assert_eq!(res.status(), StatusCode::NOT_IMPLEMENTED);
let r: Response = ErrorBadGateway("err").into(); let res: Response<Body> = ErrorBadGateway("err").into();
assert_eq!(r.status(), StatusCode::BAD_GATEWAY); assert_eq!(res.status(), StatusCode::BAD_GATEWAY);
let r: Response = ErrorServiceUnavailable("err").into(); let res: Response<Body> = ErrorServiceUnavailable("err").into();
assert_eq!(r.status(), StatusCode::SERVICE_UNAVAILABLE); assert_eq!(res.status(), StatusCode::SERVICE_UNAVAILABLE);
let r: Response = ErrorGatewayTimeout("err").into(); let res: Response<Body> = ErrorGatewayTimeout("err").into();
assert_eq!(r.status(), StatusCode::GATEWAY_TIMEOUT); assert_eq!(res.status(), StatusCode::GATEWAY_TIMEOUT);
let r: Response = ErrorHttpVersionNotSupported("err").into(); let res: Response<Body> = ErrorHttpVersionNotSupported("err").into();
assert_eq!(r.status(), StatusCode::HTTP_VERSION_NOT_SUPPORTED); assert_eq!(res.status(), StatusCode::HTTP_VERSION_NOT_SUPPORTED);
let r: Response = ErrorVariantAlsoNegotiates("err").into(); let res: Response<Body> = ErrorVariantAlsoNegotiates("err").into();
assert_eq!(r.status(), StatusCode::VARIANT_ALSO_NEGOTIATES); assert_eq!(res.status(), StatusCode::VARIANT_ALSO_NEGOTIATES);
let r: Response = ErrorInsufficientStorage("err").into(); let res: Response<Body> = ErrorInsufficientStorage("err").into();
assert_eq!(r.status(), StatusCode::INSUFFICIENT_STORAGE); assert_eq!(res.status(), StatusCode::INSUFFICIENT_STORAGE);
let r: Response = ErrorLoopDetected("err").into(); let res: Response<Body> = ErrorLoopDetected("err").into();
assert_eq!(r.status(), StatusCode::LOOP_DETECTED); assert_eq!(res.status(), StatusCode::LOOP_DETECTED);
let r: Response = ErrorNotExtended("err").into(); let res: Response<Body> = ErrorNotExtended("err").into();
assert_eq!(r.status(), StatusCode::NOT_EXTENDED); assert_eq!(res.status(), StatusCode::NOT_EXTENDED);
let r: Response = ErrorNetworkAuthenticationRequired("err").into(); let res: Response<Body> = ErrorNetworkAuthenticationRequired("err").into();
assert_eq!(r.status(), StatusCode::NETWORK_AUTHENTICATION_REQUIRED); assert_eq!(res.status(), StatusCode::NETWORK_AUTHENTICATION_REQUIRED);
} }
} }

View file

@ -407,7 +407,7 @@ where
} }
// send expect error as response // send expect error as response
Poll::Ready(Err(err)) => { Poll::Ready(Err(err)) => {
let res: Response = err.into().into(); let res = Response::from_error(err.into());
let (res, body) = res.replace_body(()); let (res, body) = res.replace_body(());
self.as_mut().send_response(res, body.into_body())?; self.as_mut().send_response(res, body.into_body())?;
} }
@ -456,8 +456,7 @@ where
// to notify the dispatcher a new state is set and the outer loop // to notify the dispatcher a new state is set and the outer loop
// should be continue. // should be continue.
Poll::Ready(Err(err)) => { Poll::Ready(Err(err)) => {
let err = err.into(); let res = Response::from_error(err.into());
let res: Response = err.into();
let (res, body) = res.replace_body(()); let (res, body) = res.replace_body(());
return self.send_response(res, body.into_body()); return self.send_response(res, body.into_body());
} }
@ -477,7 +476,7 @@ where
Poll::Pending => Ok(()), Poll::Pending => Ok(()),
// see the comment on ExpectCall state branch's Ready(Err(err)). // see the comment on ExpectCall state branch's Ready(Err(err)).
Poll::Ready(Err(err)) => { Poll::Ready(Err(err)) => {
let res: Response = err.into().into(); let res = Response::from_error(err.into());
let (res, body) = res.replace_body(()); let (res, body) = res.replace_body(());
self.send_response(res, body.into_body()) self.send_response(res, body.into_body())
} }
@ -979,19 +978,20 @@ mod tests {
} }
} }
fn ok_service() -> impl Service<Request, Response = Response, Error = Error> { fn ok_service() -> impl Service<Request, Response = Response<Body>, Error = Error> {
fn_service(|_req: Request| ready(Ok::<_, Error>(Response::Ok().finish()))) fn_service(|_req: Request| ready(Ok::<_, Error>(Response::Ok().finish())))
} }
fn echo_path_service() -> impl Service<Request, Response = Response, Error = Error> { fn echo_path_service(
) -> impl Service<Request, Response = Response<Body>, Error = Error> {
fn_service(|req: Request| { fn_service(|req: Request| {
let path = req.path().as_bytes(); let path = req.path().as_bytes();
ready(Ok::<_, Error>(Response::Ok().body(Body::from_slice(path)))) ready(Ok::<_, Error>(Response::Ok().body(Body::from_slice(path))))
}) })
} }
fn echo_payload_service() -> impl Service<Request, Response = Response, Error = Error> fn echo_payload_service(
{ ) -> impl Service<Request, Response = Response<Body>, Error = Error> {
fn_service(|mut req: Request| { fn_service(|mut req: Request| {
Box::pin(async move { Box::pin(async move {
use futures_util::stream::StreamExt as _; use futures_util::stream::StreamExt as _;

View file

@ -252,8 +252,8 @@ where
} }
} }
Err(e) => { Err(err) => {
let res: Response = e.into().into(); let res = Response::from_error(err.into());
let (res, body) = res.replace_body(()); let (res, body) = res.replace_body(());
let mut send = send.take().unwrap(); let mut send = send.take().unwrap();

View file

@ -4,7 +4,10 @@
use http::StatusCode; use http::StatusCode;
use crate::response::{Response, ResponseBuilder}; use crate::{
body::Body,
response::{Response, ResponseBuilder},
};
macro_rules! static_resp { macro_rules! static_resp {
($name:ident, $status:expr) => { ($name:ident, $status:expr) => {
@ -15,7 +18,7 @@ macro_rules! static_resp {
}; };
} }
impl Response { impl Response<Body> {
static_resp!(Continue, StatusCode::CONTINUE); static_resp!(Continue, StatusCode::CONTINUE);
static_resp!(SwitchingProtocols, StatusCode::SWITCHING_PROTOCOLS); static_resp!(SwitchingProtocols, StatusCode::SWITCHING_PROTOCOLS);
static_resp!(Processing, StatusCode::PROCESSING); static_resp!(Processing, StatusCode::PROCESSING);

View file

@ -6,7 +6,6 @@
//! | `openssl` | TLS support via [OpenSSL]. | //! | `openssl` | TLS support via [OpenSSL]. |
//! | `rustls` | TLS support via [rustls]. | //! | `rustls` | TLS support via [rustls]. |
//! | `compress` | Payload compression support. (Deflate, Gzip & Brotli) | //! | `compress` | Payload compression support. (Deflate, Gzip & Brotli) |
//! | `secure-cookies` | Adds for secure cookies. Enables `cookies` feature. |
//! | `trust-dns` | Use [trust-dns] as the client DNS resolver. | //! | `trust-dns` | Use [trust-dns] as the client DNS resolver. |
//! //!
//! [OpenSSL]: https://crates.io/crates/openssl //! [OpenSSL]: https://crates.io/crates/openssl

View file

@ -22,7 +22,7 @@ use crate::{
}; };
/// An HTTP Response /// An HTTP Response
pub struct Response<B = Body> { pub struct Response<B> {
head: BoxedResponseHead, head: BoxedResponseHead,
body: ResponseBody<B>, body: ResponseBody<B>,
error: Option<Error>, error: Option<Error>,
@ -43,7 +43,7 @@ impl Response<Body> {
/// Constructs a response /// Constructs a response
#[inline] #[inline]
pub fn new(status: StatusCode) -> Response { pub fn new(status: StatusCode) -> Response<Body> {
Response { Response {
head: BoxedResponseHead::new(status), head: BoxedResponseHead::new(status),
body: ResponseBody::Body(Body::Empty), body: ResponseBody::Body(Body::Empty),
@ -53,7 +53,7 @@ impl Response<Body> {
/// Constructs an error response /// Constructs an error response
#[inline] #[inline]
pub fn from_error(error: Error) -> Response { pub fn from_error(error: Error) -> Response<Body> {
let mut resp = error.as_response_error().error_response(); let mut resp = error.as_response_error().error_response();
if resp.head.status == StatusCode::INTERNAL_SERVER_ERROR { if resp.head.status == StatusCode::INTERNAL_SERVER_ERROR {
error!("Internal Server Error: {:?}", error); error!("Internal Server Error: {:?}", error);
@ -238,8 +238,8 @@ impl<B: MessageBody> fmt::Debug for Response<B> {
} }
} }
impl Future for Response { impl<B: Unpin> Future for Response<B> {
type Output = Result<Response, Error>; type Output = Result<Response<B>, 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> {
Poll::Ready(Ok(Response { Poll::Ready(Ok(Response {
@ -421,7 +421,7 @@ impl ResponseBuilder {
/// ///
/// `ResponseBuilder` can not be used after this call. /// `ResponseBuilder` can not be used after this call.
#[inline] #[inline]
pub fn body<B: Into<Body>>(&mut self, body: B) -> Response { pub fn body<B: Into<Body>>(&mut self, body: B) -> Response<Body> {
self.message_body(body.into()) self.message_body(body.into())
} }
@ -446,7 +446,7 @@ impl ResponseBuilder {
/// ///
/// `ResponseBuilder` can not be used after this call. /// `ResponseBuilder` can not be used after this call.
#[inline] #[inline]
pub fn streaming<S, E>(&mut self, stream: S) -> Response pub fn streaming<S, E>(&mut self, stream: S) -> Response<Body>
where where
S: Stream<Item = Result<Bytes, E>> + Unpin + 'static, S: Stream<Item = Result<Bytes, E>> + Unpin + 'static,
E: Into<Error> + 'static, E: Into<Error> + 'static,
@ -458,7 +458,7 @@ impl ResponseBuilder {
/// ///
/// `ResponseBuilder` can not be used after this call. /// `ResponseBuilder` can not be used after this call.
#[inline] #[inline]
pub fn finish(&mut self) -> Response { pub fn finish(&mut self) -> Response<Body> {
self.body(Body::Empty) self.body(Body::Empty)
} }
@ -513,7 +513,7 @@ impl<'a> From<&'a ResponseHead> for ResponseBuilder {
} }
impl Future for ResponseBuilder { impl Future for ResponseBuilder {
type Output = Result<Response, Error>; type Output = Result<Response<Body>, 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> {
Poll::Ready(Ok(self.finish())) Poll::Ready(Ok(self.finish()))
@ -540,7 +540,7 @@ impl fmt::Debug for ResponseBuilder {
} }
/// Helper converters /// Helper converters
impl<I: Into<Response>, E: Into<Error>> From<Result<I, E>> for Response { impl<I: Into<Response<Body>>, E: Into<Error>> From<Result<I, E>> for Response<Body> {
fn from(res: Result<I, E>) -> Self { fn from(res: Result<I, E>) -> Self {
match res { match res {
Ok(val) => val.into(), Ok(val) => val.into(),
@ -549,13 +549,13 @@ impl<I: Into<Response>, E: Into<Error>> From<Result<I, E>> for Response {
} }
} }
impl From<ResponseBuilder> for Response { impl From<ResponseBuilder> for Response<Body> {
fn from(mut builder: ResponseBuilder) -> Self { fn from(mut builder: ResponseBuilder) -> Self {
builder.finish() builder.finish()
} }
} }
impl From<&'static str> for Response { impl From<&'static str> for Response<Body> {
fn from(val: &'static str) -> Self { fn from(val: &'static str) -> Self {
Response::Ok() Response::Ok()
.content_type(mime::TEXT_PLAIN_UTF_8) .content_type(mime::TEXT_PLAIN_UTF_8)
@ -563,7 +563,7 @@ impl From<&'static str> for Response {
} }
} }
impl From<&'static [u8]> for Response { impl From<&'static [u8]> for Response<Body> {
fn from(val: &'static [u8]) -> Self { fn from(val: &'static [u8]) -> Self {
Response::Ok() Response::Ok()
.content_type(mime::APPLICATION_OCTET_STREAM) .content_type(mime::APPLICATION_OCTET_STREAM)
@ -571,7 +571,7 @@ impl From<&'static [u8]> for Response {
} }
} }
impl From<String> for Response { impl From<String> for Response<Body> {
fn from(val: String) -> Self { fn from(val: String) -> Self {
Response::Ok() Response::Ok()
.content_type(mime::TEXT_PLAIN_UTF_8) .content_type(mime::TEXT_PLAIN_UTF_8)
@ -579,7 +579,7 @@ impl From<String> for Response {
} }
} }
impl<'a> From<&'a String> for Response { impl<'a> From<&'a String> for Response<Body> {
fn from(val: &'a String) -> Self { fn from(val: &'a String) -> Self {
Response::Ok() Response::Ok()
.content_type(mime::TEXT_PLAIN_UTF_8) .content_type(mime::TEXT_PLAIN_UTF_8)
@ -587,7 +587,7 @@ impl<'a> From<&'a String> for Response {
} }
} }
impl From<Bytes> for Response { impl From<Bytes> for Response<Body> {
fn from(val: Bytes) -> Self { fn from(val: Bytes) -> Self {
Response::Ok() Response::Ok()
.content_type(mime::APPLICATION_OCTET_STREAM) .content_type(mime::APPLICATION_OCTET_STREAM)
@ -595,7 +595,7 @@ impl From<Bytes> for Response {
} }
} }
impl From<BytesMut> for Response { impl From<BytesMut> for Response<Body> {
fn from(val: BytesMut) -> Self { fn from(val: BytesMut) -> Self {
Response::Ok() Response::Ok()
.content_type(mime::APPLICATION_OCTET_STREAM) .content_type(mime::APPLICATION_OCTET_STREAM)
@ -653,7 +653,7 @@ mod tests {
#[test] #[test]
fn test_into_response() { fn test_into_response() {
let resp: Response = "test".into(); let resp: Response<Body> = "test".into();
assert_eq!(resp.status(), StatusCode::OK); assert_eq!(resp.status(), StatusCode::OK);
assert_eq!( assert_eq!(
resp.headers().get(CONTENT_TYPE).unwrap(), resp.headers().get(CONTENT_TYPE).unwrap(),
@ -662,7 +662,7 @@ mod tests {
assert_eq!(resp.status(), StatusCode::OK); assert_eq!(resp.status(), StatusCode::OK);
assert_eq!(resp.body().get_ref(), b"test"); assert_eq!(resp.body().get_ref(), b"test");
let resp: Response = b"test".as_ref().into(); let resp: Response<Body> = b"test".as_ref().into();
assert_eq!(resp.status(), StatusCode::OK); assert_eq!(resp.status(), StatusCode::OK);
assert_eq!( assert_eq!(
resp.headers().get(CONTENT_TYPE).unwrap(), resp.headers().get(CONTENT_TYPE).unwrap(),
@ -671,7 +671,7 @@ mod tests {
assert_eq!(resp.status(), StatusCode::OK); assert_eq!(resp.status(), StatusCode::OK);
assert_eq!(resp.body().get_ref(), b"test"); assert_eq!(resp.body().get_ref(), b"test");
let resp: Response = "test".to_owned().into(); let resp: Response<Body> = "test".to_owned().into();
assert_eq!(resp.status(), StatusCode::OK); assert_eq!(resp.status(), StatusCode::OK);
assert_eq!( assert_eq!(
resp.headers().get(CONTENT_TYPE).unwrap(), resp.headers().get(CONTENT_TYPE).unwrap(),
@ -680,7 +680,7 @@ mod tests {
assert_eq!(resp.status(), StatusCode::OK); assert_eq!(resp.status(), StatusCode::OK);
assert_eq!(resp.body().get_ref(), b"test"); assert_eq!(resp.body().get_ref(), b"test");
let resp: Response = (&"test".to_owned()).into(); let resp: Response<Body> = (&"test".to_owned()).into();
assert_eq!(resp.status(), StatusCode::OK); assert_eq!(resp.status(), StatusCode::OK);
assert_eq!( assert_eq!(
resp.headers().get(CONTENT_TYPE).unwrap(), resp.headers().get(CONTENT_TYPE).unwrap(),
@ -690,7 +690,7 @@ mod tests {
assert_eq!(resp.body().get_ref(), b"test"); assert_eq!(resp.body().get_ref(), b"test");
let b = Bytes::from_static(b"test"); let b = Bytes::from_static(b"test");
let resp: Response = b.into(); let resp: Response<Body> = b.into();
assert_eq!(resp.status(), StatusCode::OK); assert_eq!(resp.status(), StatusCode::OK);
assert_eq!( assert_eq!(
resp.headers().get(CONTENT_TYPE).unwrap(), resp.headers().get(CONTENT_TYPE).unwrap(),
@ -700,7 +700,7 @@ mod tests {
assert_eq!(resp.body().get_ref(), b"test"); assert_eq!(resp.body().get_ref(), b"test");
let b = Bytes::from_static(b"test"); let b = Bytes::from_static(b"test");
let resp: Response = b.into(); let resp: Response<Body> = b.into();
assert_eq!(resp.status(), StatusCode::OK); assert_eq!(resp.status(), StatusCode::OK);
assert_eq!( assert_eq!(
resp.headers().get(CONTENT_TYPE).unwrap(), resp.headers().get(CONTENT_TYPE).unwrap(),
@ -710,7 +710,7 @@ mod tests {
assert_eq!(resp.body().get_ref(), b"test"); assert_eq!(resp.body().get_ref(), b"test");
let b = BytesMut::from("test"); let b = BytesMut::from("test");
let resp: Response = b.into(); let resp: Response<Body> = b.into();
assert_eq!(resp.status(), StatusCode::OK); assert_eq!(resp.status(), StatusCode::OK);
assert_eq!( assert_eq!(
resp.headers().get(CONTENT_TYPE).unwrap(), resp.headers().get(CONTENT_TYPE).unwrap(),
@ -723,7 +723,7 @@ mod tests {
#[test] #[test]
fn test_into_builder() { fn test_into_builder() {
let mut resp: Response = "test".into(); let mut resp: Response<Body> = "test".into();
assert_eq!(resp.status(), StatusCode::OK); assert_eq!(resp.status(), StatusCode::OK);
resp.headers_mut().insert( resp.headers_mut().insert(

View file

@ -9,8 +9,8 @@ use derive_more::{Display, Error, From};
use http::{header, Method, StatusCode}; use http::{header, Method, StatusCode};
use crate::{ use crate::{
error::ResponseError, header::HeaderValue, message::RequestHead, response::Response, body::Body, error::ResponseError, header::HeaderValue, message::RequestHead,
ResponseBuilder, response::Response, ResponseBuilder,
}; };
mod codec; mod codec;
@ -99,7 +99,7 @@ pub enum HandshakeError {
} }
impl ResponseError for HandshakeError { impl ResponseError for HandshakeError {
fn error_response(&self) -> Response { fn error_response(&self) -> Response<Body> {
match self { match self {
HandshakeError::GetMethodRequired => Response::MethodNotAllowed() HandshakeError::GetMethodRequired => Response::MethodNotAllowed()
.insert_header((header::ALLOW, "GET")) .insert_header((header::ALLOW, "GET"))
@ -320,17 +320,17 @@ mod tests {
#[test] #[test]
fn test_wserror_http_response() { fn test_wserror_http_response() {
let resp: Response = HandshakeError::GetMethodRequired.error_response(); let resp = HandshakeError::GetMethodRequired.error_response();
assert_eq!(resp.status(), StatusCode::METHOD_NOT_ALLOWED); assert_eq!(resp.status(), StatusCode::METHOD_NOT_ALLOWED);
let resp: Response = HandshakeError::NoWebsocketUpgrade.error_response(); let resp = HandshakeError::NoWebsocketUpgrade.error_response();
assert_eq!(resp.status(), StatusCode::BAD_REQUEST); assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
let resp: Response = HandshakeError::NoConnectionUpgrade.error_response(); let resp = HandshakeError::NoConnectionUpgrade.error_response();
assert_eq!(resp.status(), StatusCode::BAD_REQUEST); assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
let resp: Response = HandshakeError::NoVersionHeader.error_response(); let resp = HandshakeError::NoVersionHeader.error_response();
assert_eq!(resp.status(), StatusCode::BAD_REQUEST); assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
let resp: Response = HandshakeError::UnsupportedVersion.error_response(); let resp = HandshakeError::UnsupportedVersion.error_response();
assert_eq!(resp.status(), StatusCode::BAD_REQUEST); assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
let resp: Response = HandshakeError::BadWebsocketKey.error_response(); let resp = HandshakeError::BadWebsocketKey.error_response();
assert_eq!(resp.status(), StatusCode::BAD_REQUEST); assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
} }
} }

View file

@ -4,11 +4,15 @@ extern crate tls_openssl as openssl;
use std::io; use std::io;
use actix_http::error::{ErrorBadRequest, PayloadError}; use actix_http::{
use actix_http::http::header::{self, HeaderName, HeaderValue}; body::{Body, SizedStream},
use actix_http::http::{Method, StatusCode, Version}; error::{ErrorBadRequest, PayloadError},
use actix_http::HttpMessage; http::{
use actix_http::{body, Error, HttpService, Request, Response}; header::{self, HeaderName, HeaderValue},
Method, StatusCode, Version,
},
Error, HttpMessage, HttpService, Request, Response,
};
use actix_http_test::test_server; use actix_http_test::test_server;
use actix_service::{fn_service, ServiceFactoryExt}; use actix_service::{fn_service, ServiceFactoryExt};
use actix_utils::future::{err, ok, ready}; use actix_utils::future::{err, ok, ready};
@ -328,7 +332,7 @@ async fn test_h2_body_length() {
.h2(|_| { .h2(|_| {
let body = once(ok(Bytes::from_static(STR.as_ref()))); let body = once(ok(Bytes::from_static(STR.as_ref())));
ok::<_, ()>( ok::<_, ()>(
Response::Ok().body(body::SizedStream::new(STR.len() as u64, body)), Response::Ok().body(SizedStream::new(STR.len() as u64, body)),
) )
}) })
.openssl(tls_config()) .openssl(tls_config())
@ -401,7 +405,7 @@ async fn test_h2_response_http_error_handling() {
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, Error>(ErrorBadRequest("error"))) .h2(|_| err::<Response<Body>, Error>(ErrorBadRequest("error")))
.openssl(tls_config()) .openssl(tls_config())
.map_err(|_| ()) .map_err(|_| ())
}) })

View file

@ -2,10 +2,15 @@
extern crate tls_rustls as rustls; extern crate tls_rustls as rustls;
use actix_http::error::PayloadError; use actix_http::{
use actix_http::http::header::{self, HeaderName, HeaderValue}; body::{Body, SizedStream},
use actix_http::http::{Method, StatusCode, Version}; error::{self, PayloadError},
use actix_http::{body, error, Error, HttpService, Request, Response}; http::{
header::{self, HeaderName, HeaderValue},
Method, StatusCode, Version,
},
Error, HttpService, Request, Response,
};
use actix_http_test::test_server; use actix_http_test::test_server;
use actix_service::{fn_factory_with_config, fn_service}; use actix_service::{fn_factory_with_config, fn_service};
use actix_utils::future::{err, ok}; use actix_utils::future::{err, ok};
@ -344,7 +349,7 @@ async fn test_h2_body_length() {
.h2(|_| { .h2(|_| {
let body = once(ok(Bytes::from_static(STR.as_ref()))); let body = once(ok(Bytes::from_static(STR.as_ref())));
ok::<_, ()>( ok::<_, ()>(
Response::Ok().body(body::SizedStream::new(STR.len() as u64, body)), Response::Ok().body(SizedStream::new(STR.len() as u64, body)),
) )
}) })
.rustls(tls_config()) .rustls(tls_config())
@ -416,7 +421,7 @@ async fn test_h2_response_http_error_handling() {
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, Error>(error::ErrorBadRequest("error"))) .h2(|_| err::<Response<Body>, Error>(error::ErrorBadRequest("error")))
.rustls(tls_config()) .rustls(tls_config())
}) })
.await; .await;
@ -433,7 +438,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, Error>(error::ErrorBadRequest("error"))) .h1(|_| err::<Response<Body>, Error>(error::ErrorBadRequest("error")))
.rustls(tls_config()) .rustls(tls_config())
}) })
.await; .await;

View file

@ -13,7 +13,10 @@ use regex::Regex;
use actix_http::HttpMessage; use actix_http::HttpMessage;
use actix_http::{ use actix_http::{
body, error, http, http::header, Error, HttpService, KeepAlive, Request, Response, body::{Body, SizedStream},
error, http,
http::header,
Error, HttpService, KeepAlive, Request, Response,
}; };
#[actix_rt::test] #[actix_rt::test]
@ -539,7 +542,7 @@ async fn test_h1_body_length() {
.h1(|_| { .h1(|_| {
let body = once(ok(Bytes::from_static(STR.as_ref()))); let body = once(ok(Bytes::from_static(STR.as_ref())));
ok::<_, ()>( ok::<_, ()>(
Response::Ok().body(body::SizedStream::new(STR.len() as u64, body)), Response::Ok().body(SizedStream::new(STR.len() as u64, body)),
) )
}) })
.tcp() .tcp()
@ -646,7 +649,7 @@ async fn test_h1_response_http_error_handling() {
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, _>(error::ErrorBadRequest("error"))) .h1(|_| err::<Response<Body>, _>(error::ErrorBadRequest("error")))
.tcp() .tcp()
}) })
.await; .await;

View file

@ -1,6 +1,7 @@
use std::fmt; use std::fmt;
use actix_http::{ use actix_http::{
body::Body,
error::InternalError, error::InternalError,
http::{header::IntoHeaderPair, Error as HttpError, HeaderMap, StatusCode}, http::{header::IntoHeaderPair, Error as HttpError, HeaderMap, StatusCode},
}; };
@ -65,7 +66,7 @@ impl Responder for HttpResponse {
} }
} }
impl Responder for actix_http::Response { impl Responder for actix_http::Response<Body> {
#[inline] #[inline]
fn respond_to(self, _: &HttpRequest) -> HttpResponse { fn respond_to(self, _: &HttpRequest) -> HttpResponse {
HttpResponse::from(self) HttpResponse::from(self)

View file

@ -3,6 +3,7 @@ use std::{
convert::TryInto, convert::TryInto,
fmt, fmt,
future::Future, future::Future,
mem,
pin::Pin, pin::Pin,
task::{Context, Poll}, task::{Context, Poll},
}; };
@ -287,18 +288,17 @@ impl<B> From<HttpResponse<B>> for Response<B> {
} }
impl Future for HttpResponse { impl Future for HttpResponse {
type Output = Result<Response, Error>; type Output = Result<Response<Body>, Error>;
fn poll(mut self: Pin<&mut Self>, cx: &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() {
eprintln!("httpresponse future error");
return Poll::Ready(Ok(Response::from_error(err).into_body())); return Poll::Ready(Ok(Response::from_error(err).into_body()));
} }
let res = &mut self.res; Poll::Ready(Ok(mem::replace(
actix_rt::pin!(res); &mut self.res,
Response::new(StatusCode::default()),
res.poll(cx) )))
} }
} }
@ -680,7 +680,7 @@ impl From<HttpResponseBuilder> for HttpResponse {
} }
} }
impl From<HttpResponseBuilder> for Response { impl From<HttpResponseBuilder> for Response<Body> {
fn from(mut builder: HttpResponseBuilder) -> Self { fn from(mut builder: HttpResponseBuilder) -> Self {
builder.finish().into() builder.finish().into()
} }