Skip to main content

rws_server/handler/
urlencoded.rs

1//! [`Query<T>`] and [`Form<T>`]: `application/x-www-form-urlencoded` pairs
2//! deserialized into a struct (`serde`), with a small deserializer of its
3//! own (no `serde_urlencoded`).
4
5use serde::de::{self, DeserializeOwned, IntoDeserializer, Visitor};
6use serde::de::value::Error;
7
8use super::{rejection, FromRequestParts, RequestParts};
9use crate::response::{Response, STATUS_CODE_REASON_PHRASE};
10use crate::url::URL;
11
12/// The query string deserialized into `T`: `Query(page): Query<Page>`.
13///
14/// Fields are scalars, `String`s, `Option`s (absent or empty → `None`),
15/// unit enums, or `Vec`s of them (`?tag=a&tag=b`). A query that doesn't
16/// fit `T` answers `400 Bad Request`. The untyped map is
17/// [`extract::Query`](crate::extract::Query).
18#[derive(Debug, Clone, PartialEq, Eq)]
19pub struct Query<T>(pub T);
20
21impl<T> std::ops::Deref for Query<T> {
22    type Target = T;
23    fn deref(&self) -> &T {
24        &self.0
25    }
26}
27
28impl<S, T: DeserializeOwned> FromRequestParts<S> for Query<T> {
29    fn from_request_parts(parts: &RequestParts<'_, S>) -> Result<Self, Response> {
30        let uri = &parts.request.request_uri;
31        let query = uri.split_once('?').map(|(_, q)| q).unwrap_or("");
32        let query = query.split('#').next().unwrap_or("");
33        from_urlencoded(query)
34            .map(Query)
35            .map_err(|e| rejection(parts.request, STATUS_CODE_REASON_PHRASE.n400_bad_request, &format!("query string: {e}")))
36    }
37}
38
39/// An `application/x-www-form-urlencoded` body deserialized into `T`:
40/// `Form(signup): Form<Signup>`. Same field types as [`Query`].
41///
42/// Rejections: `415` when the `Content-Type` isn't
43/// `application/x-www-form-urlencoded`, `400` for a body that isn't UTF-8,
44/// `422` when the fields don't fit `T`.
45#[derive(Debug, Clone, PartialEq, Eq)]
46pub struct Form<T>(pub T);
47
48impl<T> std::ops::Deref for Form<T> {
49    type Target = T;
50    fn deref(&self) -> &T {
51        &self.0
52    }
53}
54
55const FORM_TYPE: &str = "application/x-www-form-urlencoded";
56
57impl<S, T: DeserializeOwned> FromRequestParts<S> for Form<T> {
58    fn from_request_parts(parts: &RequestParts<'_, S>) -> Result<Self, Response> {
59        let request = parts.request;
60        let content_type: &str = request.header("Content-Type").map(|h| h.value.as_ref()).unwrap_or("");
61        let essence = content_type.split(';').next().unwrap_or("").trim();
62        if !essence.eq_ignore_ascii_case(FORM_TYPE) {
63            let detail = format!("expected Content-Type {FORM_TYPE}");
64            return Err(rejection(request, STATUS_CODE_REASON_PHRASE.n415_unsupported_media_type, &detail));
65        }
66        let body = std::str::from_utf8(&request.body)
67            .map_err(|_| rejection(request, STATUS_CODE_REASON_PHRASE.n400_bad_request, "request body is not valid UTF-8"))?;
68        from_urlencoded(body)
69            .map(Form)
70            .map_err(|e| rejection(request, STATUS_CODE_REASON_PHRASE.n422_unprocessable_entity, &format!("form: {e}")))
71    }
72}
73
74/// `a=1&b=x+y&b=z` into `T`.
75pub(crate) fn from_urlencoded<T: DeserializeOwned>(input: &str) -> Result<T, Error> {
76    // Keys in first-seen order; the index keeps a body of many distinct
77    // keys linear.
78    let mut pairs: Vec<(String, Vec<String>)> = Vec::new();
79    let mut index: std::collections::HashMap<String, usize> = std::collections::HashMap::new();
80    for pair in input.split('&').filter(|p| !p.is_empty()) {
81        let (k, v) = pair.split_once('=').unwrap_or((pair, ""));
82        let (k, v) = (URL::form_decode(k), URL::form_decode(v));
83        match index.get(&k) {
84            Some(&i) => pairs[i].1.push(v),
85            None => {
86                index.insert(k.clone(), pairs.len());
87                pairs.push((k, vec![v]));
88            }
89        }
90    }
91    T::deserialize(Pairs(pairs))
92}
93
94/// Every shape the deserializer handles, for the fuzzer and the
95/// stack-depth test.
96#[doc(hidden)]
97pub fn fuzz(input: &str) {
98    use std::collections::HashMap;
99    let _ = from_urlencoded::<HashMap<String, String>>(input);
100    let _ = from_urlencoded::<HashMap<String, Vec<String>>>(input);
101    let _ = from_urlencoded::<HashMap<String, Option<u64>>>(input);
102    let _ = from_urlencoded::<HashMap<String, (bool, char)>>(input);
103    let _ = from_urlencoded::<Vec<(String, f64)>>(input);
104}
105
106struct Pairs(Vec<(String, Vec<String>)>);
107
108impl<'de> de::Deserializer<'de> for Pairs {
109    type Error = Error;
110
111    fn deserialize_any<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Error> {
112        visitor.visit_map(PairsAccess { pairs: self.0.into_iter(), value: None })
113    }
114
115    serde::forward_to_deserialize_any! {
116        bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
117        bytes byte_buf option unit unit_struct newtype_struct seq tuple
118        tuple_struct map struct enum identifier ignored_any
119    }
120}
121
122struct PairsAccess {
123    pairs: std::vec::IntoIter<(String, Vec<String>)>,
124    value: Option<Vec<String>>,
125}
126
127impl<'de> de::MapAccess<'de> for PairsAccess {
128    type Error = Error;
129
130    fn next_key_seed<K: de::DeserializeSeed<'de>>(&mut self, seed: K) -> Result<Option<K::Value>, Error> {
131        match self.pairs.next() {
132            Some((key, values)) => {
133                self.value = Some(values);
134                seed.deserialize(key.into_deserializer()).map(Some)
135            }
136            None => Ok(None),
137        }
138    }
139
140    fn next_value_seed<V: de::DeserializeSeed<'de>>(&mut self, seed: V) -> Result<V::Value, Error> {
141        let values = self.value.take().unwrap_or_default();
142        seed.deserialize(Values(values))
143    }
144}
145
146/// A field's values (one, or several for a repeated key). Scalars take the
147/// last; sequences take them all.
148struct Values(Vec<String>);
149
150impl Values {
151    fn last(self) -> String {
152        self.0.into_iter().next_back().unwrap_or_default()
153    }
154
155    fn parse<T: std::str::FromStr>(self, what: &str) -> Result<T, Error>
156    where
157        T::Err: std::fmt::Display,
158    {
159        let value = self.last();
160        value.parse::<T>().map_err(|e| de::Error::custom(format!("{value:?} is not a valid {what}: {e}")))
161    }
162}
163
164macro_rules! parse_scalar {
165    ($($method:ident => $visit:ident $t:ty),*) => {$(
166        fn $method<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Error> {
167            visitor.$visit(self.parse::<$t>(stringify!($t))?)
168        }
169    )*};
170}
171
172impl<'de> de::Deserializer<'de> for Values {
173    type Error = Error;
174
175    fn deserialize_any<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Error> {
176        if self.0.len() > 1 {
177            return self.deserialize_seq(visitor);
178        }
179        visitor.visit_string(self.last())
180    }
181
182    parse_scalar! {
183        deserialize_bool => visit_bool bool,
184        deserialize_i8 => visit_i8 i8, deserialize_i16 => visit_i16 i16,
185        deserialize_i32 => visit_i32 i32, deserialize_i64 => visit_i64 i64,
186        deserialize_i128 => visit_i128 i128,
187        deserialize_u8 => visit_u8 u8, deserialize_u16 => visit_u16 u16,
188        deserialize_u32 => visit_u32 u32, deserialize_u64 => visit_u64 u64,
189        deserialize_u128 => visit_u128 u128,
190        deserialize_f32 => visit_f32 f32, deserialize_f64 => visit_f64 f64,
191        deserialize_char => visit_char char
192    }
193
194    fn deserialize_str<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Error> {
195        visitor.visit_string(self.last())
196    }
197
198    fn deserialize_string<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Error> {
199        visitor.visit_string(self.last())
200    }
201
202    fn deserialize_option<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Error> {
203        if self.0.iter().all(|v| v.is_empty()) {
204            visitor.visit_none()
205        } else {
206            visitor.visit_some(self)
207        }
208    }
209
210    fn deserialize_newtype_struct<V: Visitor<'de>>(self, _name: &'static str, visitor: V) -> Result<V::Value, Error> {
211        visitor.visit_newtype_struct(self)
212    }
213
214    fn deserialize_seq<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Error> {
215        visitor.visit_seq(de::value::SeqDeserializer::new(self.0.into_iter().map(|v| Values(vec![v]))))
216    }
217
218    fn deserialize_enum<V: Visitor<'de>>(
219        self,
220        _name: &'static str,
221        _variants: &'static [&'static str],
222        visitor: V,
223    ) -> Result<V::Value, Error> {
224        visitor.visit_enum(self.last().into_deserializer())
225    }
226
227    fn deserialize_unit<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Error> {
228        visitor.visit_unit()
229    }
230
231    serde::forward_to_deserialize_any! {
232        bytes byte_buf unit_struct tuple tuple_struct map struct identifier ignored_any
233    }
234}
235
236impl<'de> IntoDeserializer<'de, Error> for Values {
237    type Deserializer = Values;
238    fn into_deserializer(self) -> Values {
239        self
240    }
241}