mirror of https://github.com/fafhrd91/actix-web
responder body type temp
This commit is contained in:
parent
e4e2cef2e1
commit
81d6fb4d65
|
@ -6,8 +6,7 @@ use std::{
|
||||||
task::{Context, Poll},
|
task::{Context, Poll},
|
||||||
};
|
};
|
||||||
|
|
||||||
use actix_web::error::Error;
|
use actix_web::{error::Error, web::Bytes};
|
||||||
use bytes::Bytes;
|
|
||||||
use futures_core::{ready, Stream};
|
use futures_core::{ready, Stream};
|
||||||
use pin_project_lite::pin_project;
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ use std::os::unix::fs::MetadataExt;
|
||||||
use actix_http::body::AnyBody;
|
use actix_http::body::AnyBody;
|
||||||
use actix_service::{Service, ServiceFactory};
|
use actix_service::{Service, ServiceFactory};
|
||||||
use actix_web::{
|
use actix_web::{
|
||||||
|
body::BoxBody,
|
||||||
dev::{
|
dev::{
|
||||||
AppService, BodyEncoding, HttpServiceFactory, ResourceDef, ServiceRequest,
|
AppService, BodyEncoding, HttpServiceFactory, ResourceDef, ServiceRequest,
|
||||||
ServiceResponse, SizedStream,
|
ServiceResponse, SizedStream,
|
||||||
|
@ -394,7 +395,7 @@ impl NamedFile {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an `HttpResponse` with file as a streaming body.
|
/// Creates an `HttpResponse` with file as a streaming body.
|
||||||
pub fn into_response(self, req: &HttpRequest) -> HttpResponse {
|
pub fn into_response(self, req: &HttpRequest) -> HttpResponse<BoxBody> {
|
||||||
if self.status_code != StatusCode::OK {
|
if self.status_code != StatusCode::OK {
|
||||||
let mut res = HttpResponse::build(self.status_code);
|
let mut res = HttpResponse::build(self.status_code);
|
||||||
|
|
||||||
|
@ -598,7 +599,10 @@ impl DerefMut for NamedFile {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Responder for NamedFile {
|
impl Responder for NamedFile {
|
||||||
fn respond_to(self, req: &HttpRequest) -> HttpResponse {
|
// TODO: can be improved
|
||||||
|
type Body = BoxBody;
|
||||||
|
|
||||||
|
fn respond_to(self, req: &HttpRequest) -> HttpResponse<Self::Body> {
|
||||||
self.into_response(req)
|
self.into_response(req)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,10 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn either_body_works() {
|
fn type_parameter_inference() {
|
||||||
let _body = EitherBody::new(());
|
let _body: EitherBody<(), _> = EitherBody::new(());
|
||||||
|
|
||||||
|
let _body: EitherBody<_, ()> = EitherBody::left(());
|
||||||
|
let _body: EitherBody<(), _> = EitherBody::right(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,8 @@ use pin_project_lite::pin_project;
|
||||||
|
|
||||||
use super::BodySize;
|
use super::BodySize;
|
||||||
|
|
||||||
/// An interface for response bodies.
|
/// An interface types that can converted to bytes and used as response bodies.
|
||||||
|
// TODO: examples
|
||||||
pub trait MessageBody {
|
pub trait MessageBody {
|
||||||
type Error;
|
type Error;
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ pub enum BodySize {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BodySize {
|
impl BodySize {
|
||||||
/// Returns true if size hint indicates no or empty body.
|
/// Returns true if size hint indicates omitted or empty body.
|
||||||
///
|
///
|
||||||
/// Streams will return false because it cannot be known without reading the stream.
|
/// Streams will return false because it cannot be known without reading the stream.
|
||||||
///
|
///
|
||||||
|
|
|
@ -109,7 +109,9 @@ impl<T> Responder for InternalError<T>
|
||||||
where
|
where
|
||||||
T: fmt::Debug + fmt::Display + 'static,
|
T: fmt::Debug + fmt::Display + 'static,
|
||||||
{
|
{
|
||||||
fn respond_to(self, _: &HttpRequest) -> HttpResponse {
|
type Body = BoxBody;
|
||||||
|
|
||||||
|
fn respond_to(self, _: &HttpRequest) -> HttpResponse<Self::Body> {
|
||||||
HttpResponse::from_error(self)
|
HttpResponse::from_error(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ use actix_service::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
body::EitherBody,
|
||||||
service::{ServiceRequest, ServiceResponse},
|
service::{ServiceRequest, ServiceResponse},
|
||||||
Error, FromRequest, HttpResponse, Responder,
|
Error, FromRequest, HttpResponse, Responder,
|
||||||
};
|
};
|
||||||
|
@ -26,7 +27,13 @@ where
|
||||||
|
|
||||||
pub fn handler_service<F, T, R>(
|
pub fn handler_service<F, T, R>(
|
||||||
handler: F,
|
handler: F,
|
||||||
) -> BoxServiceFactory<(), ServiceRequest, ServiceResponse, Error, ()>
|
) -> BoxServiceFactory<
|
||||||
|
(),
|
||||||
|
ServiceRequest,
|
||||||
|
ServiceResponse<EitherBody<<R::Output as Responder>::Body>>,
|
||||||
|
Error,
|
||||||
|
(),
|
||||||
|
>
|
||||||
where
|
where
|
||||||
F: Handler<T, R>,
|
F: Handler<T, R>,
|
||||||
T: FromRequest,
|
T: FromRequest,
|
||||||
|
@ -35,12 +42,21 @@ where
|
||||||
{
|
{
|
||||||
boxed::factory(fn_service(move |req: ServiceRequest| {
|
boxed::factory(fn_service(move |req: ServiceRequest| {
|
||||||
let handler = handler.clone();
|
let handler = handler.clone();
|
||||||
|
|
||||||
async move {
|
async move {
|
||||||
let (req, mut payload) = req.into_parts();
|
let (req, mut payload) = req.into_parts();
|
||||||
let res = match T::from_request(&req, &mut payload).await {
|
let res = match T::from_request(&req, &mut payload).await {
|
||||||
Err(err) => HttpResponse::from_error(err),
|
Err(err) => {
|
||||||
Ok(data) => handler.call(data).await.respond_to(&req),
|
HttpResponse::from_error(err).map_body(|_, body| EitherBody::right(body))
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(data) => handler
|
||||||
|
.call(data)
|
||||||
|
.await
|
||||||
|
.respond_to(&req)
|
||||||
|
.map_body(|_, body| EitherBody::left(body)),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(ServiceResponse::new(req, res))
|
Ok(ServiceResponse::new(req, res))
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
use std::cell::RefCell;
|
use std::{cell::RefCell, error::Error as StdError, fmt, future::Future, rc::Rc};
|
||||||
use std::fmt;
|
|
||||||
use std::future::Future;
|
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
use actix_http::Extensions;
|
use actix_http::Extensions;
|
||||||
use actix_router::{IntoPatterns, Patterns};
|
use actix_router::{IntoPatterns, Patterns};
|
||||||
|
@ -13,6 +10,7 @@ use futures_core::future::LocalBoxFuture;
|
||||||
use futures_util::future::join_all;
|
use futures_util::future::join_all;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
body::MessageBody,
|
||||||
data::Data,
|
data::Data,
|
||||||
dev::{ensure_leading_slash, AppService, ResourceDef},
|
dev::{ensure_leading_slash, AppService, ResourceDef},
|
||||||
guard::Guard,
|
guard::Guard,
|
||||||
|
@ -241,6 +239,9 @@ where
|
||||||
I: FromRequest + 'static,
|
I: FromRequest + 'static,
|
||||||
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 as MessageBody>::Error:
|
||||||
|
Into<Box<dyn StdError + 'static>>,
|
||||||
{
|
{
|
||||||
self.routes.push(Route::new().to(handler));
|
self.routes.push(Route::new().to(handler));
|
||||||
self
|
self
|
||||||
|
|
121
src/responder.rs
121
src/responder.rs
|
@ -1,5 +1,7 @@
|
||||||
|
use std::error::Error as StdError;
|
||||||
|
|
||||||
use actix_http::{
|
use actix_http::{
|
||||||
body::BoxBody,
|
body::{BoxBody, EitherBody, MessageBody},
|
||||||
http::{header::IntoHeaderPair, Error as HttpError, HeaderMap, StatusCode},
|
http::{header::IntoHeaderPair, Error as HttpError, HeaderMap, StatusCode},
|
||||||
};
|
};
|
||||||
use bytes::{Bytes, BytesMut};
|
use bytes::{Bytes, BytesMut};
|
||||||
|
@ -10,8 +12,10 @@ use crate::{Error, HttpRequest, HttpResponse, HttpResponseBuilder};
|
||||||
///
|
///
|
||||||
/// Any types that implement this trait can be used in the return type of a handler.
|
/// Any types that implement this trait can be used in the return type of a handler.
|
||||||
pub trait Responder {
|
pub trait Responder {
|
||||||
|
type Body: MessageBody + 'static;
|
||||||
|
|
||||||
/// Convert self to `HttpResponse`.
|
/// Convert self to `HttpResponse`.
|
||||||
fn respond_to(self, req: &HttpRequest) -> HttpResponse<BoxBody>;
|
fn respond_to(self, req: &HttpRequest) -> HttpResponse<Self::Body>;
|
||||||
|
|
||||||
/// Override a status code for a Responder.
|
/// Override a status code for a Responder.
|
||||||
///
|
///
|
||||||
|
@ -57,38 +61,56 @@ pub trait Responder {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Responder for HttpResponse {
|
impl Responder for HttpResponse {
|
||||||
|
type Body = BoxBody;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn respond_to(self, _: &HttpRequest) -> HttpResponse<BoxBody> {
|
fn respond_to(self, _: &HttpRequest) -> HttpResponse<Self::Body> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Responder for actix_http::Response<BoxBody> {
|
impl Responder for actix_http::Response<BoxBody> {
|
||||||
|
type Body = BoxBody;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn respond_to(self, _: &HttpRequest) -> HttpResponse<BoxBody> {
|
fn respond_to(self, _: &HttpRequest) -> HttpResponse<Self::Body> {
|
||||||
HttpResponse::from(self)
|
HttpResponse::from(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Responder for HttpResponseBuilder {
|
impl Responder for HttpResponseBuilder {
|
||||||
|
type Body = BoxBody;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn respond_to(mut self, _: &HttpRequest) -> HttpResponse<BoxBody> {
|
fn respond_to(mut self, _: &HttpRequest) -> HttpResponse<Self::Body> {
|
||||||
self.finish()
|
self.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Responder for actix_http::ResponseBuilder {
|
impl Responder for actix_http::ResponseBuilder {
|
||||||
|
type Body = BoxBody;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn respond_to(mut self, req: &HttpRequest) -> HttpResponse<BoxBody> {
|
fn respond_to(mut self, req: &HttpRequest) -> HttpResponse<Self::Body> {
|
||||||
self.finish().map_into_boxed_body().respond_to(req)
|
self.finish().map_into_boxed_body().respond_to(req)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Responder> Responder for Option<T> {
|
impl<T> Responder for Option<T>
|
||||||
fn respond_to(self, req: &HttpRequest) -> HttpResponse<BoxBody> {
|
where
|
||||||
|
T: Responder,
|
||||||
|
<T::Body as MessageBody>::Error: Into<Box<dyn StdError + 'static>>,
|
||||||
|
{
|
||||||
|
type Body = EitherBody<T::Body>;
|
||||||
|
|
||||||
|
fn respond_to(self, req: &HttpRequest) -> HttpResponse<Self::Body> {
|
||||||
match self {
|
match self {
|
||||||
Some(val) => val.respond_to(req),
|
Some(val) => val
|
||||||
None => HttpResponse::new(StatusCode::NOT_FOUND),
|
.respond_to(req)
|
||||||
|
.map_body(|_, body| EitherBody::left(body)),
|
||||||
|
|
||||||
|
None => HttpResponse::new(StatusCode::NOT_FOUND)
|
||||||
|
.map_body(|_, body| EitherBody::right(body)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,48 +118,78 @@ impl<T: Responder> Responder for Option<T> {
|
||||||
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<Box<dyn StdError + 'static>>,
|
||||||
E: Into<Error>,
|
E: Into<Error>,
|
||||||
{
|
{
|
||||||
fn respond_to(self, req: &HttpRequest) -> HttpResponse<BoxBody> {
|
type Body = EitherBody<T::Body>;
|
||||||
|
|
||||||
|
fn respond_to(self, req: &HttpRequest) -> HttpResponse<Self::Body> {
|
||||||
match self {
|
match self {
|
||||||
Ok(val) => val.respond_to(req),
|
Ok(val) => val
|
||||||
Err(e) => HttpResponse::from_error(e.into()),
|
.respond_to(req)
|
||||||
|
.map_body(|_, body| EitherBody::left(body)),
|
||||||
|
|
||||||
|
Err(e) => {
|
||||||
|
HttpResponse::from_error(e.into()).map_body(|_, body| EitherBody::right(body))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Responder> Responder for (T, StatusCode) {
|
impl<T: Responder> Responder for (T, StatusCode) {
|
||||||
fn respond_to(self, req: &HttpRequest) -> HttpResponse<BoxBody> {
|
type Body = T::Body;
|
||||||
|
|
||||||
|
fn respond_to(self, req: &HttpRequest) -> HttpResponse<Self::Body> {
|
||||||
let mut res = self.0.respond_to(req);
|
let mut res = self.0.respond_to(req);
|
||||||
*res.status_mut() = self.1;
|
*res.status_mut() = self.1;
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_responder {
|
macro_rules! impl_responder_by_forward_into_base_response {
|
||||||
($res: ty, $ct: path) => {
|
($res:ty, $body:ty) => {
|
||||||
impl Responder for $res {
|
impl Responder for $res {
|
||||||
fn respond_to(self, _: &HttpRequest) -> HttpResponse<BoxBody> {
|
type Body = $body;
|
||||||
HttpResponse::Ok().content_type($ct).body(self)
|
|
||||||
|
fn respond_to(self, _: &HttpRequest) -> HttpResponse<Self::Body> {
|
||||||
|
let res: actix_http::Response<_> = self.into();
|
||||||
|
res.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
($res:ty) => {
|
||||||
|
impl_responder_by_forward_into_base_response!($res, $res);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_responder!(&'static str, mime::TEXT_PLAIN_UTF_8);
|
impl_responder_by_forward_into_base_response!(&'static [u8]);
|
||||||
|
impl_responder_by_forward_into_base_response!(Bytes);
|
||||||
|
impl_responder_by_forward_into_base_response!(BytesMut);
|
||||||
|
|
||||||
impl_responder!(String, mime::TEXT_PLAIN_UTF_8);
|
impl_responder_by_forward_into_base_response!(&'static str);
|
||||||
|
impl_responder_by_forward_into_base_response!(String);
|
||||||
|
|
||||||
|
// macro_rules! impl_responder {
|
||||||
|
// ($res:ty, $body:ty, $ct:path) => {
|
||||||
|
// impl Responder for $res {
|
||||||
|
// type Body = $body;
|
||||||
|
|
||||||
|
// fn respond_to(self, _: &HttpRequest) -> HttpResponse<Self::Body> {
|
||||||
|
// HttpResponse::Ok().content_type($ct).body(self)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
// ($res:ty, $ct:path) => {
|
||||||
|
// impl_responder!($res, $res, $ct);
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
|
||||||
// impl_responder!(&'_ String, mime::TEXT_PLAIN_UTF_8);
|
// impl_responder!(&'_ String, mime::TEXT_PLAIN_UTF_8);
|
||||||
|
|
||||||
// impl_responder!(Cow<'_, str>, mime::TEXT_PLAIN_UTF_8);
|
// impl_responder!(Cow<'_, str>, mime::TEXT_PLAIN_UTF_8);
|
||||||
|
|
||||||
impl_responder!(&'static [u8], mime::APPLICATION_OCTET_STREAM);
|
|
||||||
|
|
||||||
impl_responder!(Bytes, mime::APPLICATION_OCTET_STREAM);
|
|
||||||
|
|
||||||
impl_responder!(BytesMut, mime::APPLICATION_OCTET_STREAM);
|
|
||||||
|
|
||||||
/// Allows overriding status code and headers for a responder.
|
/// Allows overriding status code and headers for a responder.
|
||||||
pub struct CustomResponder<T> {
|
pub struct CustomResponder<T> {
|
||||||
responder: T,
|
responder: T,
|
||||||
|
@ -202,11 +254,20 @@ impl<T: Responder> CustomResponder<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Responder> Responder for CustomResponder<T> {
|
impl<T> Responder for CustomResponder<T>
|
||||||
fn respond_to(self, req: &HttpRequest) -> HttpResponse {
|
where
|
||||||
|
T: Responder,
|
||||||
|
<T::Body as MessageBody>::Error: Into<Box<dyn StdError + 'static>>,
|
||||||
|
{
|
||||||
|
type Body = EitherBody<T::Body>;
|
||||||
|
|
||||||
|
fn respond_to(self, req: &HttpRequest) -> HttpResponse<Self::Body> {
|
||||||
let headers = match self.headers {
|
let headers = match self.headers {
|
||||||
Ok(headers) => headers,
|
Ok(headers) => headers,
|
||||||
Err(err) => return HttpResponse::from_error(Error::from(err)),
|
Err(err) => {
|
||||||
|
return HttpResponse::from_error(Error::from(err))
|
||||||
|
.map_body(|_, body| EitherBody::right(body))
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut res = self.responder.respond_to(req);
|
let mut res = self.responder.respond_to(req);
|
||||||
|
@ -220,7 +281,7 @@ impl<T: Responder> Responder for CustomResponder<T> {
|
||||||
res.headers_mut().insert(k, v);
|
res.headers_mut().insert(k, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
res
|
res.map_body(|_, body| EitherBody::left(body))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -306,7 +306,7 @@ impl HttpResponseBuilder {
|
||||||
.extensions_mut()
|
.extensions_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a body and generate `Response`.
|
/// Set a body and build the `HttpResponse`.
|
||||||
///
|
///
|
||||||
/// `HttpResponseBuilder` can not be used after this call.
|
/// `HttpResponseBuilder` can not be used after this call.
|
||||||
pub fn body<B>(&mut self, body: B) -> HttpResponse<BoxBody>
|
pub fn body<B>(&mut self, body: B) -> HttpResponse<BoxBody>
|
||||||
|
@ -320,7 +320,7 @@ impl HttpResponseBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a body and generate `Response`.
|
/// Set a body and build the `HttpResponse`.
|
||||||
///
|
///
|
||||||
/// `HttpResponseBuilder` can not be used after this call.
|
/// `HttpResponseBuilder` can not be used after this call.
|
||||||
pub fn message_body<B>(&mut self, body: B) -> Result<HttpResponse<B>, Error> {
|
pub fn message_body<B>(&mut self, body: B) -> Result<HttpResponse<B>, Error> {
|
||||||
|
@ -350,7 +350,7 @@ impl HttpResponseBuilder {
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a streaming body and generate `Response`.
|
/// Set a streaming body and build the `HttpResponse`.
|
||||||
///
|
///
|
||||||
/// `HttpResponseBuilder` can not be used after this call.
|
/// `HttpResponseBuilder` can not be used after this call.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -362,7 +362,7 @@ impl HttpResponseBuilder {
|
||||||
self.body(BoxBody::new(BodyStream::new(stream)))
|
self.body(BoxBody::new(BodyStream::new(stream)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a json body and generate `Response`
|
/// Set a JSON body and build the `HttpResponse`.
|
||||||
///
|
///
|
||||||
/// `HttpResponseBuilder` can not be used after this call.
|
/// `HttpResponseBuilder` can not be used after this call.
|
||||||
pub fn json(&mut self, value: impl Serialize) -> HttpResponse {
|
pub fn json(&mut self, value: impl Serialize) -> HttpResponse {
|
||||||
|
@ -384,7 +384,7 @@ impl HttpResponseBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set an empty body and generate `Response`
|
/// Set an empty body and build the `HttpResponse`.
|
||||||
///
|
///
|
||||||
/// `HttpResponseBuilder` can not be used after this call.
|
/// `HttpResponseBuilder` can not be used after this call.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
17
src/route.rs
17
src/route.rs
|
@ -1,6 +1,6 @@
|
||||||
#![allow(clippy::rc_buffer)] // inner value is mutated before being shared (`Rc::get_mut`)
|
#![allow(clippy::rc_buffer)] // inner value is mutated before being shared (`Rc::get_mut`)
|
||||||
|
|
||||||
use std::{future::Future, rc::Rc};
|
use std::{error::Error as StdError, future::Future, mem, rc::Rc};
|
||||||
|
|
||||||
use actix_http::http::Method;
|
use actix_http::http::Method;
|
||||||
use actix_service::{
|
use actix_service::{
|
||||||
|
@ -10,6 +10,7 @@ use actix_service::{
|
||||||
use futures_core::future::LocalBoxFuture;
|
use futures_core::future::LocalBoxFuture;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
body::MessageBody,
|
||||||
guard::{self, Guard},
|
guard::{self, Guard},
|
||||||
handler::{handler_service, Handler},
|
handler::{handler_service, Handler},
|
||||||
service::{ServiceRequest, ServiceResponse},
|
service::{ServiceRequest, ServiceResponse},
|
||||||
|
@ -30,13 +31,16 @@ impl Route {
|
||||||
#[allow(clippy::new_without_default)]
|
#[allow(clippy::new_without_default)]
|
||||||
pub fn new() -> Route {
|
pub fn new() -> Route {
|
||||||
Route {
|
Route {
|
||||||
service: handler_service(HttpResponse::NotFound),
|
// TODO: remove double boxing
|
||||||
|
service: boxed::factory(
|
||||||
|
handler_service(HttpResponse::NotFound).map(|res| res.map_into_boxed_body()),
|
||||||
|
),
|
||||||
guards: Rc::new(Vec::new()),
|
guards: Rc::new(Vec::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn take_guards(&mut self) -> Vec<Box<dyn Guard>> {
|
pub(crate) fn take_guards(&mut self) -> Vec<Box<dyn Guard>> {
|
||||||
std::mem::take(Rc::get_mut(&mut self.guards).unwrap())
|
mem::take(Rc::get_mut(&mut self.guards).unwrap())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,8 +185,13 @@ impl Route {
|
||||||
T: FromRequest + 'static,
|
T: FromRequest + 'static,
|
||||||
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 as MessageBody>::Error:
|
||||||
|
Into<Box<dyn StdError + 'static>>,
|
||||||
{
|
{
|
||||||
self.service = handler_service(handler);
|
// TODO: remove double boxing
|
||||||
|
self.service =
|
||||||
|
boxed::factory(handler_service(handler).map(|res| res.map_into_boxed_body()));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -656,8 +656,8 @@ fn create_tcp_listener(addr: net::SocketAddr, backlog: u32) -> io::Result<net::T
|
||||||
Ok(net::TcpListener::from(socket))
|
Ok(net::TcpListener::from(socket))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "openssl")]
|
|
||||||
/// Configure `SslAcceptorBuilder` with custom server flags.
|
/// Configure `SslAcceptorBuilder` with custom server flags.
|
||||||
|
#[cfg(feature = "openssl")]
|
||||||
fn openssl_acceptor(mut builder: SslAcceptorBuilder) -> io::Result<SslAcceptor> {
|
fn openssl_acceptor(mut builder: SslAcceptorBuilder) -> io::Result<SslAcceptor> {
|
||||||
builder.set_alpn_select_callback(|_, protocols| {
|
builder.set_alpn_select_callback(|_, protocols| {
|
||||||
const H2: &[u8] = b"\x02h2";
|
const H2: &[u8] = b"\x02h2";
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
//! For either helper, see [`Either`].
|
//! For either helper, see [`Either`].
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
|
error::Error as StdError,
|
||||||
future::Future,
|
future::Future,
|
||||||
mem,
|
mem,
|
||||||
pin::Pin,
|
pin::Pin,
|
||||||
|
@ -12,7 +13,7 @@ use futures_core::ready;
|
||||||
use pin_project_lite::pin_project;
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
dev,
|
body, dev,
|
||||||
web::{Form, Json},
|
web::{Form, Json},
|
||||||
Error, FromRequest, HttpRequest, HttpResponse, Responder,
|
Error, FromRequest, HttpRequest, HttpResponse, Responder,
|
||||||
};
|
};
|
||||||
|
@ -144,12 +145,21 @@ impl<L, R> Either<L, R> {
|
||||||
impl<L, R> Responder for Either<L, R>
|
impl<L, R> Responder for Either<L, R>
|
||||||
where
|
where
|
||||||
L: Responder,
|
L: Responder,
|
||||||
|
<L::Body as dev::MessageBody>::Error: Into<Box<dyn StdError + 'static>>,
|
||||||
R: Responder,
|
R: Responder,
|
||||||
|
<R::Body as dev::MessageBody>::Error: Into<Box<dyn StdError + 'static>>,
|
||||||
{
|
{
|
||||||
fn respond_to(self, req: &HttpRequest) -> HttpResponse {
|
type Body = body::EitherBody<L::Body, R::Body>;
|
||||||
|
|
||||||
|
fn respond_to(self, req: &HttpRequest) -> HttpResponse<Self::Body> {
|
||||||
match self {
|
match self {
|
||||||
Either::Left(a) => a.respond_to(req),
|
Either::Left(a) => a
|
||||||
Either::Right(b) => b.respond_to(req),
|
.respond_to(req)
|
||||||
|
.map_body(|_, body| body::EitherBody::left(body)),
|
||||||
|
|
||||||
|
Either::Right(b) => b
|
||||||
|
.respond_to(req)
|
||||||
|
.map_body(|_, body| body::EitherBody::right(body)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,8 +20,9 @@ use serde::{de::DeserializeOwned, Serialize};
|
||||||
#[cfg(feature = "__compress")]
|
#[cfg(feature = "__compress")]
|
||||||
use crate::dev::Decompress;
|
use crate::dev::Decompress;
|
||||||
use crate::{
|
use crate::{
|
||||||
error::UrlencodedError, extract::FromRequest, http::header::CONTENT_LENGTH, web, Error,
|
body::EitherBody, error::UrlencodedError, extract::FromRequest,
|
||||||
HttpMessage, HttpRequest, HttpResponse, Responder,
|
http::header::CONTENT_LENGTH, web, Error, HttpMessage, HttpRequest, HttpResponse,
|
||||||
|
Responder,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// URL encoded payload extractor and responder.
|
/// URL encoded payload extractor and responder.
|
||||||
|
@ -180,12 +181,22 @@ impl<T: fmt::Display> fmt::Display for Form<T> {
|
||||||
|
|
||||||
/// See [here](#responder) for example of usage as a handler return type.
|
/// See [here](#responder) for example of usage as a handler return type.
|
||||||
impl<T: Serialize> Responder for Form<T> {
|
impl<T: Serialize> Responder for Form<T> {
|
||||||
fn respond_to(self, _: &HttpRequest) -> HttpResponse {
|
type Body = EitherBody<String>;
|
||||||
|
|
||||||
|
fn respond_to(self, _: &HttpRequest) -> HttpResponse<Self::Body> {
|
||||||
match serde_urlencoded::to_string(&self.0) {
|
match serde_urlencoded::to_string(&self.0) {
|
||||||
Ok(body) => HttpResponse::Ok()
|
Ok(body) => match HttpResponse::Ok()
|
||||||
.content_type(mime::APPLICATION_WWW_FORM_URLENCODED)
|
.content_type(mime::APPLICATION_WWW_FORM_URLENCODED)
|
||||||
.body(body),
|
.message_body(body)
|
||||||
Err(err) => HttpResponse::from_error(UrlencodedError::Serialize(err)),
|
{
|
||||||
|
Ok(res) => res.map_body(|_, body| EitherBody::left(body)),
|
||||||
|
Err(err) => {
|
||||||
|
HttpResponse::from_error(err).map_body(|_, body| EitherBody::right(body))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
Err(err) => HttpResponse::from_error(UrlencodedError::Serialize(err))
|
||||||
|
.map_body(|_, body| EitherBody::right(body)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ use actix_http::Payload;
|
||||||
#[cfg(feature = "__compress")]
|
#[cfg(feature = "__compress")]
|
||||||
use crate::dev::Decompress;
|
use crate::dev::Decompress;
|
||||||
use crate::{
|
use crate::{
|
||||||
|
body::EitherBody,
|
||||||
error::{Error, JsonPayloadError},
|
error::{Error, JsonPayloadError},
|
||||||
extract::FromRequest,
|
extract::FromRequest,
|
||||||
http::header::CONTENT_LENGTH,
|
http::header::CONTENT_LENGTH,
|
||||||
|
@ -116,12 +117,22 @@ impl<T: Serialize> Serialize for Json<T> {
|
||||||
///
|
///
|
||||||
/// If serialization failed
|
/// If serialization failed
|
||||||
impl<T: Serialize> Responder for Json<T> {
|
impl<T: Serialize> Responder for Json<T> {
|
||||||
fn respond_to(self, _: &HttpRequest) -> HttpResponse {
|
type Body = EitherBody<String>;
|
||||||
|
|
||||||
|
fn respond_to(self, _: &HttpRequest) -> HttpResponse<Self::Body> {
|
||||||
match serde_json::to_string(&self.0) {
|
match serde_json::to_string(&self.0) {
|
||||||
Ok(body) => HttpResponse::Ok()
|
Ok(body) => match HttpResponse::Ok()
|
||||||
.content_type(mime::APPLICATION_JSON)
|
.content_type(mime::APPLICATION_JSON)
|
||||||
.body(body),
|
.message_body(body)
|
||||||
Err(err) => HttpResponse::from_error(JsonPayloadError::Serialize(err)),
|
{
|
||||||
|
Ok(res) => res.map_body(|_, body| EitherBody::left(body)),
|
||||||
|
Err(err) => {
|
||||||
|
HttpResponse::from_error(err).map_body(|_, body| EitherBody::right(body))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
Err(err) => HttpResponse::from_error(JsonPayloadError::Serialize(err))
|
||||||
|
.map_body(|_, body| EitherBody::right(body)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
//! Essentials helper functions and types for application registration.
|
//! Essentials helper functions and types for application registration.
|
||||||
|
|
||||||
use std::future::Future;
|
use std::{error::Error as StdError, future::Future};
|
||||||
|
|
||||||
use actix_http::http::Method;
|
use actix_http::http::Method;
|
||||||
use actix_router::IntoPatterns;
|
use actix_router::IntoPatterns;
|
||||||
pub use bytes::{Buf, BufMut, Bytes, BytesMut};
|
pub use bytes::{Buf, BufMut, Bytes, BytesMut};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
error::BlockingError, extract::FromRequest, handler::Handler, resource::Resource,
|
body::MessageBody, error::BlockingError, extract::FromRequest, handler::Handler,
|
||||||
responder::Responder, route::Route, scope::Scope, service::WebService,
|
resource::Resource, responder::Responder, route::Route, scope::Scope, service::WebService,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use crate::config::ServiceConfig;
|
pub use crate::config::ServiceConfig;
|
||||||
|
@ -145,6 +145,8 @@ where
|
||||||
I: FromRequest + 'static,
|
I: FromRequest + 'static,
|
||||||
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 as MessageBody>::Error: Into<Box<dyn StdError + 'static>>,
|
||||||
{
|
{
|
||||||
Route::new().to(handler)
|
Route::new().to(handler)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue