Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions actix-files/src/path_buf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use std::{
str::FromStr,
};

use actix_utils::future::{ready, Ready};
use actix_web::{dev::Payload, FromRequest, HttpRequest};

use crate::error::UriSegmentError;
Expand Down Expand Up @@ -88,10 +87,10 @@ impl AsRef<Path> for PathBufWrap {

impl FromRequest for PathBufWrap {
type Error = UriSegmentError;
type Future = Ready<Result<Self, Self::Error>>;

fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
ready(req.match_info().unprocessed().parse())
#[inline]
async fn from_request(req: &HttpRequest, _: &mut Payload) -> Result<Self, Self::Error> {
req.match_info().unprocessed().parse()
}
}

Expand Down
1 change: 1 addition & 0 deletions actix-web/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ serde_json = "1.0"
serde_urlencoded = "0.7"
smallvec = "1.6.1"
socket2 = "0.5"
tokio = { version = "1.24.2", features = ["macros"] }
time = { version = "0.3", default-features = false, features = ["formatting"] }
url = "2.1"

Expand Down
8 changes: 3 additions & 5 deletions actix-web/src/data.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::{any::type_name, ops::Deref, sync::Arc};

use actix_http::Extensions;
use actix_utils::future::{err, ok, Ready};
use futures_core::future::LocalBoxFuture;
use serde::{de, Serialize};

Expand Down Expand Up @@ -159,12 +158,11 @@ where

impl<T: ?Sized + 'static> FromRequest for Data<T> {
type Error = Error;
type Future = Ready<Result<Self, Error>>;

#[inline]
fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
async fn from_request(req: &HttpRequest, _: &mut Payload) -> Result<Self, Self::Error> {
if let Some(st) = req.app_data::<Data<T>>() {
ok(st.clone())
Ok(st.clone())
} else {
log::debug!(
"Failed to extract `Data<{}>` for `{}` handler. For the Data extractor to work \
Expand All @@ -174,7 +172,7 @@ impl<T: ?Sized + 'static> FromRequest for Data<T> {
req.match_name().unwrap_or_else(|| req.path())
);

err(error::ErrorInternalServerError(
Err(error::ErrorInternalServerError(
"Requested application data is not configured correctly. \
View/enable debug logs for more details.",
))
Expand Down
169 changes: 34 additions & 135 deletions actix-web/src/extract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@
use std::{
convert::Infallible,
future::Future,
marker::PhantomData,
pin::Pin,
task::{Context, Poll},
};

use actix_http::{Method, Uri};
use actix_utils::future::{ok, Ready};
use futures_core::ready;
use pin_project_lite::pin_project;

Expand Down Expand Up @@ -66,33 +64,17 @@ pub trait FromRequest: Sized {
/// The associated error which can be returned.
type Error: Into<Error>;

/// Future that resolves to a `Self`.
///
/// To use an async function or block, the futures must be boxed. The following snippet will be
/// common when creating async/await extractors (that do not consume the body).
///
/// ```ignore
/// type Future = Pin<Box<dyn Future<Output = Result<Self, Self::Error>>>>;
/// // or
/// type Future = futures_util::future::LocalBoxFuture<'static, Result<Self, Self::Error>>;
///
/// fn from_request(req: HttpRequest, ...) -> Self::Future {
/// let req = req.clone();
/// Box::pin(async move {
/// ...
/// })
/// }
/// ```
type Future: Future<Output = Result<Self, Self::Error>>;

/// Create a `Self` from request parts asynchronously.
fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future;
/// Creates a `Self` from request parts asynchronously.
fn from_request(
req: &HttpRequest,
payload: &mut Payload,
) -> impl Future<Output = Result<Self, Self::Error>>;

/// Create a `Self` from request head asynchronously.
///
/// This method is short for `T::from_request(req, &mut Payload::None)`.
fn extract(req: &HttpRequest) -> Self::Future {
Self::from_request(req, &mut Payload::None)
fn extract(req: &HttpRequest) -> impl Future<Output = Result<Self, Self::Error>> {
async { Self::from_request(req, &mut Payload::None).await }
}
}

Expand Down Expand Up @@ -146,12 +128,19 @@ where
T: FromRequest,
{
type Error = Infallible;
type Future = FromRequestOptFuture<T::Future>;

#[inline]
fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future {
FromRequestOptFuture {
fut: T::from_request(req, payload),
async fn from_request(req: &HttpRequest, payload: &mut Payload) -> Result<Self, Self::Error> {
match T::from_request(req, payload).await {
Ok(t) => Ok(Some(t)),
Err(err) => {
log::debug!(
"Error from `Option<{}>` extractor: {}",
std::any::type_name::<T>(),
err.into()
);
Ok(None)
}
}
}
}
Expand Down Expand Up @@ -203,9 +192,11 @@ where
///
/// impl FromRequest for Thing {
/// type Error = Error;
/// type Future = Ready<Result<Thing, Error>>;
///
/// fn from_request(req: &HttpRequest, payload: &mut dev::Payload) -> Self::Future {
/// async fn from_request(
/// req: &HttpRequest,
/// payload: &mut dev::Payload,
/// ) -> Result<Self, Self::Error> {
/// if rand::random() {
/// ok(Thing { name: "thingy".into() })
/// } else {
Expand All @@ -232,36 +223,10 @@ where
T::Error: Into<E>,
{
type Error = Infallible;
type Future = FromRequestResFuture<T::Future, E>;

#[inline]
fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future {
FromRequestResFuture {
fut: T::from_request(req, payload),
_phantom: PhantomData,
}
}
}

pin_project! {
pub struct FromRequestResFuture<Fut, E> {
#[pin]
fut: Fut,
_phantom: PhantomData<E>,
}
}

impl<Fut, T, Ei, E> Future for FromRequestResFuture<Fut, E>
where
Fut: Future<Output = Result<T, Ei>>,
Ei: Into<E>,
{
type Output = Result<Result<T, E>, Infallible>;

fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.project();
let res = ready!(this.fut.poll(cx));
Poll::Ready(Ok(res.map_err(Into::into)))
async fn from_request(req: &HttpRequest, payload: &mut Payload) -> Result<Self, Self::Error> {
Ok(T::from_request(req, payload).await.map_err(Into::into))
}
}

Expand All @@ -279,10 +244,9 @@ where
/// ```
impl FromRequest for Uri {
type Error = Infallible;
type Future = Ready<Result<Self, Self::Error>>;

fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
ok(req.uri().clone())
async fn from_request(req: &HttpRequest, _: &mut Payload) -> Result<Self, Self::Error> {
Ok(req.uri().clone())
}
}

Expand All @@ -300,10 +264,9 @@ impl FromRequest for Uri {
/// ```
impl FromRequest for Method {
type Error = Infallible;
type Future = Ready<Result<Self, Self::Error>>;

fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
ok(req.method().clone())
async fn from_request(req: &HttpRequest, _: &mut Payload) -> Result<Self, Self::Error> {
Ok(req.method().clone())
}
}

Expand All @@ -319,88 +282,24 @@ mod tuple_from_req {
impl<$($T: FromRequest + 'static),+> FromRequest for ($($T,)+)
{
type Error = Error;
type Future = $fut<$($T),+>;

fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future {
$fut {
$(
$T: ExtractFuture::Future {
fut: $T::from_request(req, payload)
},
)+
}
}
}

pin_project! {
pub struct $fut<$($T: FromRequest),+> {
async fn from_request(req: &HttpRequest, payload: &mut Payload) -> Result<Self, Self::Error> {
$(
#[pin]
$T: ExtractFuture<$T::Future, $T>,
let $T = $T::from_request(req, payload).await.map_err(Into::into)?;
)+
}
}

impl<$($T: FromRequest),+> Future for $fut<$($T),+>
{
type Output = Result<($($T,)+), Error>;

fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let mut this = self.project();

let mut ready = true;
$(
match this.$T.as_mut().project() {
ExtractProj::Future { fut } => match fut.poll(cx) {
Poll::Ready(Ok(output)) => {
let _ = this.$T.as_mut().project_replace(ExtractFuture::Done { output });
},
Poll::Ready(Err(err)) => return Poll::Ready(Err(err.into())),
Poll::Pending => ready = false,
},
ExtractProj::Done { .. } => {},
ExtractProj::Empty => unreachable!("FromRequest polled after finished"),
}
)+

if ready {
Poll::Ready(Ok(
($(
match this.$T.project_replace(ExtractFuture::Empty) {
ExtractReplaceProj::Done { output } => output,
_ => unreachable!("FromRequest polled after finished"),
},
)+)
))
} else {
Poll::Pending
}
Ok(($($T,)+))
}
}
};
}

pin_project! {
#[project = ExtractProj]
#[project_replace = ExtractReplaceProj]
enum ExtractFuture<Fut, Res> {
Future {
#[pin]
fut: Fut
},
Done {
output: Res,
},
Empty
}
}

impl FromRequest for () {
type Error = Infallible;
type Future = Ready<Result<Self, Self::Error>>;

fn from_request(_: &HttpRequest, _: &mut Payload) -> Self::Future {
ok(())
#[inline]
async fn from_request(_: &HttpRequest, _: &mut Payload) -> Result<Self, Self::Error> {
Ok(())
}
}

Expand Down
15 changes: 7 additions & 8 deletions actix-web/src/info.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use std::{convert::Infallible, net::SocketAddr};

use actix_utils::future::{err, ok, Ready};
use derive_more::{Display, Error};

use crate::{
Expand Down Expand Up @@ -198,10 +197,10 @@ impl ConnectionInfo {

impl FromRequest for ConnectionInfo {
type Error = Infallible;
type Future = Ready<Result<Self, Self::Error>>;

fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
ok(req.connection_info().clone())
#[inline]
async fn from_request(req: &HttpRequest, _: &mut Payload) -> Result<Self, Self::Error> {
Ok(req.connection_info().clone())
}
}

Expand Down Expand Up @@ -240,14 +239,14 @@ impl ResponseError for MissingPeerAddr {}

impl FromRequest for PeerAddr {
type Error = MissingPeerAddr;
type Future = Ready<Result<Self, Self::Error>>;

fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
#[inline]
async fn from_request(req: &HttpRequest, _: &mut Payload) -> Result<Self, Self::Error> {
match req.peer_addr() {
Some(addr) => ok(PeerAddr(addr)),
Some(addr) => Ok(PeerAddr(addr)),
None => {
log::error!("Missing peer address.");
err(MissingPeerAddr)
Err(MissingPeerAddr)
}
}
}
Expand Down
11 changes: 5 additions & 6 deletions actix-web/src/request.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use std::{
cell::{Ref, RefCell, RefMut},
convert::Infallible,
fmt, net,
rc::Rc,
str,
};

use actix_http::{Message, RequestHead};
use actix_router::{Path, Url};
use actix_utils::future::{ok, Ready};
#[cfg(feature = "cookies")]
use cookie::{Cookie, ParseError as CookieParseError};
use smallvec::SmallVec;
Expand All @@ -20,7 +20,7 @@ use crate::{
http::{header::HeaderMap, Method, Uri, Version},
info::ConnectionInfo,
rmap::ResourceMap,
Error, FromRequest, HttpMessage,
FromRequest, HttpMessage,
};

#[cfg(feature = "cookies")]
Expand Down Expand Up @@ -417,12 +417,11 @@ impl Drop for HttpRequest {
/// );
/// ```
impl FromRequest for HttpRequest {
type Error = Error;
type Future = Ready<Result<Self, Error>>;
type Error = Infallible;

#[inline]
fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
ok(req.clone())
async fn from_request(req: &HttpRequest, _: &mut Payload) -> Result<Self, Self::Error> {
Ok(req.clone())
}
}

Expand Down
Loading