predawn_core/
from_request.rs

1use std::{convert::Infallible, future::Future};
2
3use bytes::Bytes;
4use futures_util::FutureExt;
5use http::{HeaderMap, Method, Uri, Version};
6use http_body_util::{BodyExt, LengthLimitError};
7use snafu::{IntoError, ResultExt};
8
9use crate::{
10    body::RequestBody,
11    location::Location,
12    private::{ViaRequest, ViaRequestHead},
13    request::{BodyLimit, Head, LocalAddr, OriginalUri, RemoteAddr},
14    response_error::{
15        InvalidUtf8Snafu, ReadBytesError, ReadBytesSnafu, ReadStringError, RequestBodyLimitError,
16        RequestBodyLimitSnafu, ResponseError, UnknownBodySnafu,
17    },
18};
19
20pub trait FromRequestHead<'a>: Sized {
21    type Error: ResponseError;
22
23    fn from_request_head(
24        head: &'a mut Head,
25    ) -> impl Future<Output = Result<Self, Self::Error>> + Send;
26}
27
28pub trait FromRequest<'a, M = ViaRequest>: Sized {
29    type Error: ResponseError;
30
31    fn from_request(
32        head: &'a mut Head,
33        body: RequestBody,
34    ) -> impl Future<Output = Result<Self, Self::Error>> + Send;
35}
36
37impl<'a, T> FromRequest<'a, ViaRequestHead> for T
38where
39    T: FromRequestHead<'a>,
40{
41    type Error = T::Error;
42
43    async fn from_request(head: &'a mut Head, _: RequestBody) -> Result<Self, Self::Error> {
44        // TODO: remove boxed when https://github.com/rust-lang/rust/issues/100013 is resolved
45        T::from_request_head(head).boxed().await
46    }
47}
48
49impl<'a, T: FromRequestHead<'a>> FromRequestHead<'a> for Option<T> {
50    type Error = Infallible;
51
52    async fn from_request_head(head: &'a mut Head) -> Result<Self, Self::Error> {
53        // TODO: remove boxed when https://github.com/rust-lang/rust/issues/100013 is resolved
54        Ok(T::from_request_head(head).boxed().await.ok())
55    }
56}
57
58impl<'a, T: FromRequest<'a>> FromRequest<'a> for Option<T> {
59    type Error = Infallible;
60
61    async fn from_request(head: &'a mut Head, body: RequestBody) -> Result<Self, Self::Error> {
62        // TODO: remove boxed when https://github.com/rust-lang/rust/issues/100013 is resolved
63        Ok(T::from_request(head, body).boxed().await.ok())
64    }
65}
66
67impl<'a, T: FromRequestHead<'a>> FromRequestHead<'a> for Result<T, T::Error> {
68    type Error = Infallible;
69
70    async fn from_request_head(head: &'a mut Head) -> Result<Self, Self::Error> {
71        // TODO: remove boxed when https://github.com/rust-lang/rust/issues/100013 is resolved
72        Ok(T::from_request_head(head).boxed().await)
73    }
74}
75
76impl<'a, T: FromRequest<'a>> FromRequest<'a> for Result<T, T::Error> {
77    type Error = Infallible;
78
79    async fn from_request(head: &'a mut Head, body: RequestBody) -> Result<Self, Self::Error> {
80        // TODO: remove boxed when https://github.com/rust-lang/rust/issues/100013 is resolved
81        Ok(T::from_request(head, body).boxed().await)
82    }
83}
84
85impl<'a> FromRequest<'a> for RequestBody {
86    type Error = Infallible;
87
88    async fn from_request(_: &'a mut Head, body: RequestBody) -> Result<Self, Self::Error> {
89        Ok(body)
90    }
91}
92
93impl<'a> FromRequest<'a> for Bytes {
94    type Error = ReadBytesError;
95
96    async fn from_request(head: &'a mut Head, body: RequestBody) -> Result<Self, Self::Error> {
97        match body.collect().await {
98            Ok(collected) => Ok(collected.to_bytes()),
99            Err(err) => match err.downcast::<LengthLimitError>() {
100                Ok(_) => Err(RequestBodyLimitSnafu.into_error(RequestBodyLimitError {
101                    location: Location::caller(),
102                    actual: head.content_length(),
103                    expected: head.body_limit.0,
104                })),
105                Err(err) => Err(UnknownBodySnafu.into_error(err)),
106            },
107        }
108    }
109}
110
111impl<'a> FromRequest<'a> for Vec<u8> {
112    type Error = ReadBytesError;
113
114    async fn from_request(head: &'a mut Head, body: RequestBody) -> Result<Self, Self::Error> {
115        Ok(Bytes::from_request(head, body).await?.into())
116    }
117}
118
119impl<'a> FromRequest<'a> for String {
120    type Error = ReadStringError;
121
122    async fn from_request(head: &'a mut Head, body: RequestBody) -> Result<Self, Self::Error> {
123        let bytes = Vec::<u8>::from_request(head, body)
124            .await
125            .context(ReadBytesSnafu)?;
126
127        let string = String::from_utf8(bytes).context(InvalidUtf8Snafu)?;
128
129        Ok(string)
130    }
131}
132
133macro_rules! some_impl {
134    ($ty:ty; $($field:ident)?) => {
135        impl<'a> FromRequestHead<'a> for $ty {
136            type Error = Infallible;
137
138            async fn from_request_head(head: &'a mut Head) -> Result<Self, Self::Error> {
139                Ok(Clone::clone(&head $(.$field)?))
140            }
141        }
142    };
143}
144
145some_impl!(Head; );
146some_impl!(Uri; uri);
147some_impl!(Method; method);
148some_impl!(HeaderMap; headers);
149some_impl!(OriginalUri; original_uri);
150some_impl!(Version; version);
151some_impl!(LocalAddr; local_addr);
152some_impl!(RemoteAddr; remote_addr);
153some_impl!(BodyLimit; body_limit);