relay_server/extractors/remote.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
//! Extractors for types from other crates via [`Remote`].
use axum::extract::{FromRequest, Request};
use axum::http::StatusCode;
use axum::response::{IntoResponse, Response};
use multer::Multipart;
use crate::service::ServiceState;
use crate::utils::{self, ApiErrorResponse};
/// A transparent wrapper around a remote type that implements [`FromRequest`] or [`IntoResponse`].
///
/// # Example
///
/// ```ignore
/// use std::convert::Infallible;
///
/// use axum::extract::{FromRequest, Request};
/// use axum::response::IntoResponse;
///
/// use crate::extractors::Remote;
///
/// // Derive `FromRequest` for `bool` for illustration purposes:
/// #[axum::async_trait]
/// impl<S> axum::extract::FromRequest<S> for Remote<bool> {
/// type Rejection = Remote<Infallible>;
///
/// async fn from_request(request: Request) -> Result<Self, Self::Rejection> {
/// Ok(Remote(true))
/// }
/// }
///
/// impl IntoResponse for Remote<Infallible> {
/// fn into_response(self) -> axum::response::Response {
/// match self.0 {}
/// }
/// }
/// ```
#[derive(Debug)]
pub struct Remote<T>(pub T);
impl<T> From<T> for Remote<T> {
fn from(inner: T) -> Self {
Self(inner)
}
}
#[axum::async_trait]
impl FromRequest<ServiceState> for Remote<Multipart<'static>> {
type Rejection = Remote<multer::Error>;
async fn from_request(request: Request, state: &ServiceState) -> Result<Self, Self::Rejection> {
utils::multipart_from_request(request, state.config())
.map(Remote)
.map_err(Remote)
}
}
impl IntoResponse for Remote<multer::Error> {
fn into_response(self) -> Response {
let Self(ref error) = self;
let status_code = match error {
multer::Error::FieldSizeExceeded { .. } => StatusCode::PAYLOAD_TOO_LARGE,
multer::Error::StreamSizeExceeded { .. } => StatusCode::PAYLOAD_TOO_LARGE,
_ => StatusCode::BAD_REQUEST,
};
(status_code, ApiErrorResponse::from_error(error)).into_response()
}
}