axum_core/extract/
request_parts.rs1use super::{rejection::*, FromRequest, FromRequestParts, Request};
2use crate::{body::Body, RequestExt};
3use bytes::{BufMut, Bytes, BytesMut};
4use http::{request::Parts, Extensions, HeaderMap, Method, Uri, Version};
5use http_body_util::BodyExt;
6use std::convert::Infallible;
7
8impl<S> FromRequest<S> for Request
9where
10 S: Send + Sync,
11{
12 type Rejection = Infallible;
13
14 async fn from_request(req: Request, _: &S) -> Result<Self, Self::Rejection> {
15 Ok(req)
16 }
17}
18
19impl<S> FromRequestParts<S> for Method
20where
21 S: Send + Sync,
22{
23 type Rejection = Infallible;
24
25 async fn from_request_parts(parts: &mut Parts, _: &S) -> Result<Self, Self::Rejection> {
26 Ok(parts.method.clone())
27 }
28}
29
30impl<S> FromRequestParts<S> for Uri
31where
32 S: Send + Sync,
33{
34 type Rejection = Infallible;
35
36 async fn from_request_parts(parts: &mut Parts, _: &S) -> Result<Self, Self::Rejection> {
37 Ok(parts.uri.clone())
38 }
39}
40
41impl<S> FromRequestParts<S> for Version
42where
43 S: Send + Sync,
44{
45 type Rejection = Infallible;
46
47 async fn from_request_parts(parts: &mut Parts, _: &S) -> Result<Self, Self::Rejection> {
48 Ok(parts.version)
49 }
50}
51
52impl<S> FromRequestParts<S> for HeaderMap
58where
59 S: Send + Sync,
60{
61 type Rejection = Infallible;
62
63 async fn from_request_parts(parts: &mut Parts, _: &S) -> Result<Self, Self::Rejection> {
64 Ok(parts.headers.clone())
65 }
66}
67
68#[diagnostic::do_not_recommend] impl<S> FromRequest<S> for BytesMut
70where
71 S: Send + Sync,
72{
73 type Rejection = BytesRejection;
74
75 async fn from_request(req: Request, _: &S) -> Result<Self, Self::Rejection> {
76 let mut body = req.into_limited_body();
77 #[allow(clippy::use_self)]
78 let mut bytes = BytesMut::new();
79 body_to_bytes_mut(&mut body, &mut bytes).await?;
80 Ok(bytes)
81 }
82}
83
84async fn body_to_bytes_mut(body: &mut Body, bytes: &mut BytesMut) -> Result<(), BytesRejection> {
85 while let Some(frame) = body
86 .frame()
87 .await
88 .transpose()
89 .map_err(FailedToBufferBody::from_err)?
90 {
91 let Ok(data) = frame.into_data() else {
92 return Ok(());
93 };
94 bytes.put(data);
95 }
96
97 Ok(())
98}
99
100impl<S> FromRequest<S> for Bytes
101where
102 S: Send + Sync,
103{
104 type Rejection = BytesRejection;
105
106 async fn from_request(req: Request, _: &S) -> Result<Self, Self::Rejection> {
107 let bytes = req
108 .into_limited_body()
109 .collect()
110 .await
111 .map_err(FailedToBufferBody::from_err)?
112 .to_bytes();
113
114 Ok(bytes)
115 }
116}
117
118impl<S> FromRequest<S> for String
119where
120 S: Send + Sync,
121{
122 type Rejection = StringRejection;
123
124 async fn from_request(req: Request, state: &S) -> Result<Self, Self::Rejection> {
125 let bytes = Bytes::from_request(req, state)
126 .await
127 .map_err(|err| match err {
128 BytesRejection::FailedToBufferBody(inner) => {
129 StringRejection::FailedToBufferBody(inner)
130 }
131 })?;
132
133 #[allow(clippy::use_self)]
134 let string = String::from_utf8(bytes.into()).map_err(InvalidUtf8::from_err)?;
135
136 Ok(string)
137 }
138}
139
140#[diagnostic::do_not_recommend] impl<S> FromRequestParts<S> for Parts
142where
143 S: Send + Sync,
144{
145 type Rejection = Infallible;
146
147 async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
148 Ok(parts.clone())
149 }
150}
151
152#[diagnostic::do_not_recommend] impl<S> FromRequestParts<S> for Extensions
154where
155 S: Send + Sync,
156{
157 type Rejection = Infallible;
158
159 async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
160 Ok(parts.extensions.clone())
161 }
162}
163
164impl<S> FromRequest<S> for Body
165where
166 S: Send + Sync,
167{
168 type Rejection = Infallible;
169
170 async fn from_request(req: Request, _: &S) -> Result<Self, Self::Rejection> {
171 Ok(req.into_body())
172 }
173}
174
175#[cfg(test)]
176mod tests {
177 use axum::{extract::Extension, routing::get, test_helpers::*, Router};
178 use http::{Method, StatusCode};
179
180 #[crate::test]
181 async fn extract_request_parts() {
182 #[derive(Clone)]
183 struct Ext;
184
185 async fn handler(parts: http::request::Parts) {
186 assert_eq!(parts.method, Method::GET);
187 assert_eq!(parts.uri, "/");
188 assert_eq!(parts.version, http::Version::HTTP_11);
189 assert_eq!(parts.headers["x-foo"], "123");
190 parts.extensions.get::<Ext>().unwrap();
191 }
192
193 let client = TestClient::new(Router::new().route("/", get(handler)).layer(Extension(Ext)));
194
195 let res = client.get("/").header("x-foo", "123").await;
196 assert_eq!(res.status(), StatusCode::OK);
197 }
198}