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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
use async_trait::async_trait;
use axum_core::extract::FromRequest;
use bytes::{Bytes, BytesMut};
use http::{Method, Request};
use super::{
has_content_type,
rejection::{InvalidFormContentType, RawFormRejection},
};
use crate::{body::HttpBody, BoxError};
#[derive(Debug)]
pub struct RawForm(pub Bytes);
#[async_trait]
impl<S, B> FromRequest<S, B> for RawForm
where
B: HttpBody + Send + 'static,
B::Data: Send,
B::Error: Into<BoxError>,
S: Send + Sync,
{
type Rejection = RawFormRejection;
async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> {
if req.method() == Method::GET {
let mut bytes = BytesMut::new();
if let Some(query) = req.uri().query() {
bytes.extend(query.as_bytes());
}
Ok(Self(bytes.freeze()))
} else {
if !has_content_type(req.headers(), &mime::APPLICATION_WWW_FORM_URLENCODED) {
return Err(InvalidFormContentType.into());
}
Ok(Self(Bytes::from_request(req, state).await?))
}
}
}
#[cfg(test)]
mod tests {
use http::{header::CONTENT_TYPE, Request};
use super::{InvalidFormContentType, RawForm, RawFormRejection};
use crate::{
body::{Bytes, Empty, Full},
extract::FromRequest,
};
async fn check_query(uri: &str, value: &[u8]) {
let req = Request::builder()
.uri(uri)
.body(Empty::<Bytes>::new())
.unwrap();
assert_eq!(RawForm::from_request(req, &()).await.unwrap().0, value);
}
async fn check_body(body: &'static [u8]) {
let req = Request::post("http://example.com/test")
.header(CONTENT_TYPE, mime::APPLICATION_WWW_FORM_URLENCODED.as_ref())
.body(Full::new(Bytes::from(body)))
.unwrap();
assert_eq!(RawForm::from_request(req, &()).await.unwrap().0, body);
}
#[crate::test]
async fn test_from_query() {
check_query("http://example.com/test", b"").await;
check_query("http://example.com/test?page=0&size=10", b"page=0&size=10").await;
}
#[crate::test]
async fn test_from_body() {
check_body(b"").await;
check_body(b"username=user&password=secure%20password").await;
}
#[crate::test]
async fn test_incorrect_content_type() {
let req = Request::post("http://example.com/test")
.body(Full::<Bytes>::from(Bytes::from("page=0&size=10")))
.unwrap();
assert!(matches!(
RawForm::from_request(req, &()).await.unwrap_err(),
RawFormRejection::InvalidFormContentType(InvalidFormContentType)
))
}
}