micro_web/extract/
from_request.rs

1use crate::responder::Responder;
2use crate::{OptionReqBody, RequestContext, ResponseBody};
3use http::{Response, StatusCode};
4use micro_http::protocol::ParseError;
5use std::convert::Infallible;
6
7#[trait_variant::make(Send)]
8pub trait FromRequest {
9    type Output<'r>: Send;
10    type Error: Responder + Send;
11
12    #[allow(unused)]
13    async fn from_request<'r>(req: &'r RequestContext<'_, '_>, body: OptionReqBody) -> Result<Self::Output<'r>, Self::Error>;
14}
15
16impl<T: FromRequest> FromRequest for Option<T> {
17    type Output<'r> = Option<T::Output<'r>>;
18    type Error = T::Error;
19
20    async fn from_request<'r>(req: &'r RequestContext<'_, '_>, body: OptionReqBody) -> Result<Self::Output<'r>, Self::Error> {
21        match T::from_request(req, body).await {
22            Ok(result) => Ok(Some(result)),
23            Err(_err) => Ok(None),
24        }
25    }
26}
27
28impl<T: FromRequest> FromRequest for Result<T, T::Error> {
29    type Output<'r> = Result<T::Output<'r>, T::Error>;
30    type Error = T::Error;
31
32    async fn from_request<'r>(req: &'r RequestContext<'_, '_>, body: OptionReqBody) -> Result<Self::Output<'r>, Self::Error> {
33        Ok(T::from_request(req, body).await)
34    }
35}
36
37impl FromRequest for &RequestContext<'_, '_> {
38    type Output<'r> = &'r RequestContext<'r, 'r> ;
39    type Error = Infallible;
40
41    async fn from_request<'r>(req: &'r RequestContext<'_, '_>, _: OptionReqBody) -> Result<&'r RequestContext<'r, 'r>, Infallible> {
42        Ok(req)
43    }
44}
45
46impl FromRequest for () {
47    type Output<'r> = ();
48    type Error = Infallible;
49
50    async fn from_request<'r>(_req: &'r RequestContext<'_, '_>, _body: OptionReqBody) -> Result<Self::Output<'r>, Self::Error> {
51        Ok(())
52    }
53}
54
55/// Responder implementation for ParseError to convert parsing errors to responses
56impl Responder for ParseError {
57    fn response_to(self, req: &RequestContext) -> Response<ResponseBody> {
58        match self {
59            ParseError::TooLargeHeader { .. } => (StatusCode::REQUEST_HEADER_FIELDS_TOO_LARGE, "payload too large").response_to(req),
60            ParseError::TooManyHeaders { .. } => (StatusCode::BAD_REQUEST, "too many headers").response_to(req),
61            ParseError::InvalidHeader { .. } => (StatusCode::BAD_REQUEST, "invalid header").response_to(req),
62            ParseError::InvalidVersion(_) => (StatusCode::BAD_REQUEST, "invalid version").response_to(req),
63            ParseError::InvalidMethod => (StatusCode::BAD_REQUEST, "invalid method").response_to(req),
64            ParseError::InvalidUri => (StatusCode::BAD_REQUEST, "invalid uri").response_to(req),
65            ParseError::InvalidContentLength { .. } => (StatusCode::BAD_REQUEST, "invalid content length").response_to(req),
66            ParseError::InvalidBody { .. } => (StatusCode::BAD_REQUEST, "invalid body").response_to(req),
67            ParseError::Io { .. } => (StatusCode::BAD_REQUEST, "connection error").response_to(req),
68        }
69    }
70}