1
0
Fork 0
mirror of https://github.com/actix/actix-web.git synced 2024-12-30 12:00:38 +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
## 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
* `cookies` feature flag. [#2065]
* Top-level `cookies` mod (re-export). [#2065]
@ -13,6 +21,7 @@
[#2065]: https://github.com/actix/actix-web/pull/2065
[#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

View file

@ -1,13 +1,13 @@
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_server::Server;
use bytes::BytesMut;
use futures_util::StreamExt as _;
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();
while let Some(item) = req.payload().next().await {
body.extend_from_slice(&item?)

View file

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

View file

@ -5,21 +5,25 @@ use std::{
use bytes::Bytes;
use futures_core::{ready, Stream};
use pin_project_lite::pin_project;
use crate::error::Error;
use super::{BodySize, MessageBody};
/// Streaming response wrapper.
///
/// Response does not contain `Content-Length` header and appropriate transfer encoding is used.
pub struct BodyStream<S: Unpin> {
stream: S,
pin_project! {
/// Streaming response wrapper.
///
/// Response does not contain `Content-Length` header and appropriate transfer encoding is used.
pub struct BodyStream<S> {
#[pin]
stream: S,
}
}
impl<S, E> BodyStream<S>
where
S: Stream<Item = Result<Bytes, E>> + Unpin,
S: Stream<Item = Result<Bytes, E>>,
E: Into<Error>,
{
pub fn new(stream: S) -> Self {
@ -29,7 +33,7 @@ where
impl<S, E> MessageBody for BodyStream<S>
where
S: Stream<Item = Result<Bytes, E>> + Unpin,
S: Stream<Item = Result<Bytes, E>>,
E: Into<Error>,
{
fn size(&self) -> BodySize {
@ -46,9 +50,9 @@ where
cx: &mut Context<'_>,
) -> Poll<Option<Result<Bytes, Error>>> {
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,
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 {
fn size(&self) -> BodySize {
BodySize::Sized(self.len() as u64)

View file

@ -5,23 +5,27 @@ use std::{
use bytes::Bytes;
use futures_core::{ready, Stream};
use pin_project_lite::pin_project;
use crate::error::Error;
use super::{BodySize, MessageBody};
/// 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.
pub struct SizedStream<S: Unpin> {
size: u64,
stream: S,
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.
pub struct SizedStream<S> {
size: u64,
#[pin]
stream: S,
}
}
impl<S> SizedStream<S>
where
S: Stream<Item = Result<Bytes, Error>> + Unpin,
S: Stream<Item = Result<Bytes, Error>>,
{
pub fn new(size: u64, stream: S) -> Self {
SizedStream { size, stream }
@ -30,7 +34,7 @@ where
impl<S> MessageBody for SizedStream<S>
where
S: Stream<Item = Result<Bytes, Error>> + Unpin,
S: Stream<Item = Result<Bytes, Error>>,
{
fn size(&self) -> BodySize {
BodySize::Sized(self.size as u64)
@ -46,9 +50,9 @@ where
cx: &mut Context<'_>,
) -> Poll<Option<Result<Bytes, Error>>> {
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,
val => val,
};

View file

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

View file

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

View file

@ -407,7 +407,7 @@ where
}
// send expect error as response
Poll::Ready(Err(err)) => {
let res: Response = err.into().into();
let res = Response::from_error(err.into());
let (res, body) = res.replace_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
// should be continue.
Poll::Ready(Err(err)) => {
let err = err.into();
let res: Response = err.into();
let res = Response::from_error(err.into());
let (res, body) = res.replace_body(());
return self.send_response(res, body.into_body());
}
@ -477,7 +476,7 @@ where
Poll::Pending => Ok(()),
// see the comment on ExpectCall state branch's 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(());
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 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| {
let path = req.path().as_bytes();
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| {
Box::pin(async move {
use futures_util::stream::StreamExt as _;

View file

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

View file

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

View file

@ -6,7 +6,6 @@
//! | `openssl` | TLS support via [OpenSSL]. |
//! | `rustls` | TLS support via [rustls]. |
//! | `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. |
//!
//! [OpenSSL]: https://crates.io/crates/openssl

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,6 +1,7 @@
use std::fmt;
use actix_http::{
body::Body,
error::InternalError,
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]
fn respond_to(self, _: &HttpRequest) -> HttpResponse {
HttpResponse::from(self)

View file

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