1use axum::{
2 body::Bytes,
3 extract::FromRequest,
4 response::{IntoResponse, Response},
5};
6use std::{fmt::Debug, marker::PhantomData};
7
8pub struct SplitBody<T1, T2, State>(pub T1, pub T2, pub PhantomData<State>)
9where
10 T1: FromRequest<State> + Send + Sync + Send + Sync,
11 T2: FromRequest<State> + Send + Sync + Send + Sync,
12 State: Send + Sync;
13
14impl<T1, T2, S> FromRequest<S> for SplitBody<T1, T2, S>
15where
16 T1: FromRequest<S> + Send + Sync,
17 T2: FromRequest<S> + Send + Sync,
18 T1::Rejection: Debug + Send + Sync,
19 T2::Rejection: Debug + Send + Sync,
20 S: Send + Sync,
21{
22 type Rejection = Response;
23 async fn from_request(req: axum::extract::Request, state: &S) -> Result<Self, Self::Rejection> {
24 fn make_builder(req: &axum::extract::Request) -> axum::http::request::Builder {
27 let mut builder = axum::extract::Request::builder();
28 if let Some(headers) = builder.headers_mut() {
29 *headers = req.headers().clone();
30 }
31 builder.uri(req.uri().clone()).version(req.version())
32 }
33
34 let builders = (make_builder(&req), make_builder(&req));
35
36 let body = Bytes::from_request(req, state)
37 .await
38 .map_err(|err| err.into_response())?;
39
40 let builders = (
41 builders
42 .0
43 .body(axum::body::Body::new(http_body_util::Full::new(
44 body.clone(),
45 )))
46 .unwrap(),
48 builders
49 .1
50 .body(axum::body::Body::new(http_body_util::Full::new(body)))
51 .unwrap(),
53 );
54 Ok(SplitBody(
56 T1::from_request(builders.0, state)
57 .await
58 .map_err(|err| err.into_response())?,
59 T2::from_request(builders.1, state)
60 .await
61 .map_err(|err| err.into_response())?,
62 PhantomData,
63 ))
64 }
65}