1use core::fmt;
4
5use serde::de::Error;
6
7#[derive(Debug)]
9#[cfg_attr(feature = "defmt", derive(defmt::Format))]
10pub enum UrlEncodedCharacterDecodeError {
11 BadlyFormattedPercentEncoding,
13 Utf8Error,
15}
16
17impl fmt::Display for UrlEncodedCharacterDecodeError {
18 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19 match self {
20 Self::BadlyFormattedPercentEncoding => {
21 write!(f, "Percent symbol is not followed by two hex digits")
22 }
23 Self::Utf8Error => write!(
24 f,
25 "Percent-encoded sequence does not decode into UTF-8 byte sequence"
26 ),
27 }
28 }
29}
30
31#[cfg(any(test, feature = "std"))]
32impl std::error::Error for UrlEncodedCharacterDecodeError {}
33
34pub enum UrlDecodedCharacter {
36 Literal(char),
38 Encoded(char),
40}
41
42impl UrlDecodedCharacter {
43 pub const fn into_char(self) -> char {
45 match self {
46 UrlDecodedCharacter::Literal(c) | UrlDecodedCharacter::Encoded(c) => c,
47 }
48 }
49}
50
51pub struct UrlDecodedCharacters<'a>(core::str::Chars<'a>);
53
54impl<'a> UrlDecodedCharacters<'a> {
55 pub fn as_str(&self) -> UrlEncodedString<'a> {
57 UrlEncodedString(self.0.as_str())
58 }
59}
60
61impl Iterator for UrlDecodedCharacters<'_> {
62 type Item = Result<UrlDecodedCharacter, UrlEncodedCharacterDecodeError>;
63
64 fn next(&mut self) -> Option<Self::Item> {
65 Some(Ok(match self.0.next()? {
66 '+' => UrlDecodedCharacter::Encoded(' '),
67 '%' => {
68 fn to_hex(c: char) -> Option<u8> {
69 c.to_digit(16).map(|b| b as u8)
70 }
71
72 struct Ones(u8);
73
74 impl Iterator for Ones {
75 type Item = ();
76
77 fn next(&mut self) -> Option<Self::Item> {
78 let b = (0b10000000 & self.0) > 0;
79
80 self.0 <<= 1;
81
82 b.then_some(())
83 }
84 }
85
86 let mut first_byte = {
87 let Some(first) = self.0.next().and_then(to_hex) else {
88 return Some(Err(
89 UrlEncodedCharacterDecodeError::BadlyFormattedPercentEncoding,
90 ));
91 };
92 let Some(second) = self.0.next().and_then(to_hex) else {
93 return Some(Err(
94 UrlEncodedCharacterDecodeError::BadlyFormattedPercentEncoding,
95 ));
96 };
97
98 first * 0x10 + second
99 };
100
101 let mut bits = Ones(first_byte);
102
103 let code_point = if bits.next().is_some() {
104 let byte_count = 1 + bits.count();
105
106 if byte_count == 1 {
107 return Some(Err(UrlEncodedCharacterDecodeError::Utf8Error));
108 }
109
110 first_byte <<= byte_count;
112 first_byte >>= byte_count;
113
114 let mut code_point = u32::from(first_byte);
115
116 for _ in 1..byte_count {
117 let Some('%') = self.0.next() else {
118 return Some(Err(UrlEncodedCharacterDecodeError::Utf8Error));
119 };
120
121 let next_byte = {
122 let Some(first) = self.0.next().and_then(to_hex) else {
123 return Some(Err(
124 UrlEncodedCharacterDecodeError::BadlyFormattedPercentEncoding,
125 ));
126 };
127 let Some(second) = self.0.next().and_then(to_hex) else {
128 return Some(Err(
129 UrlEncodedCharacterDecodeError::BadlyFormattedPercentEncoding,
130 ));
131 };
132
133 first * 0x10 + second
134 };
135
136 if (0b11000000 & next_byte) != 0b10000000 {
137 return Some(Err(UrlEncodedCharacterDecodeError::Utf8Error));
138 }
139
140 code_point <<= 6;
141 code_point += u32::from(0b00111111 & next_byte);
142 }
143
144 code_point
145 } else {
146 first_byte.into()
147 };
148
149 let Some(c) = char::from_u32(code_point) else {
150 return Some(Err(UrlEncodedCharacterDecodeError::Utf8Error));
151 };
152 UrlDecodedCharacter::Encoded(c)
153 }
154 c => UrlDecodedCharacter::Literal(c),
155 }))
156 }
157}
158
159const URL_ENCODED_KEY: &str = "____URL_ENCODED____";
160
161fn deserializer<'a>(
162 key: &'a str,
163 value: UrlEncodedString<'a>,
164) -> serde::de::value::MapDeserializer<
165 'a,
166 core::option::IntoIter<(&'a str, DeserializeUrlEncoded<'a>)>,
167 DeserializationError,
168> {
169 serde::de::value::MapDeserializer::new(
170 Some((URL_ENCODED_KEY, DeserializeUrlEncoded { key, value })).into_iter(),
171 )
172}
173
174#[derive(serde::Deserialize)]
175struct UrlEncodedRepresentation<'a> {
176 #[serde(rename = "____URL_ENCODED____")]
177 value: &'a str,
178}
179
180#[derive(Debug)]
182#[cfg_attr(feature = "defmt", derive(defmt::Format))]
183pub enum DecodeError {
184 BadUrlEncodedCharacter(UrlEncodedCharacterDecodeError),
186 NoSpace,
188}
189
190impl fmt::Display for DecodeError {
191 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
192 match self {
193 Self::BadUrlEncodedCharacter(bad_url_encoded_character) => {
194 bad_url_encoded_character.fmt(f)
195 }
196 Self::NoSpace => write!(f, "No space to decode url-encoded string"),
197 }
198 }
199}
200
201#[cfg(any(test, feature = "std"))]
202impl std::error::Error for DecodeError {}
203
204struct NamedDecodeError<'a> {
205 key: &'a str,
206 error: DecodeError,
207}
208
209#[derive(Clone, Copy, Default, serde::Deserialize)]
211#[serde(from = "UrlEncodedRepresentation")]
212pub struct UrlEncodedString<'a>(pub &'a str);
213
214impl fmt::Debug for UrlEncodedString<'_> {
215 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
216 self.0.fmt(f)
217 }
218}
219
220impl<'r> PartialEq<&'r str> for UrlEncodedString<'r> {
221 fn eq(&self, other: &&'r str) -> bool {
222 matches!(self.strip_prefix(other), Some(UrlEncodedString("")))
223 }
224}
225
226impl<'de> From<UrlEncodedRepresentation<'de>> for UrlEncodedString<'de> {
227 fn from(UrlEncodedRepresentation { value }: UrlEncodedRepresentation<'de>) -> Self {
228 Self(value)
229 }
230}
231
232impl<'a> UrlEncodedString<'a> {
233 pub fn chars(self) -> UrlDecodedCharacters<'a> {
235 UrlDecodedCharacters(self.0.chars())
236 }
237
238 pub fn try_into_string<const N: usize>(self) -> Result<heapless::String<N>, DecodeError> {
240 let mut str = heapless::String::new();
241
242 for c in self.chars() {
243 str.push(c.map_err(DecodeError::BadUrlEncodedCharacter)?.into_char())
244 .map_err(|()| DecodeError::NoSpace)?;
245 }
246
247 Ok(str)
248 }
249
250 #[cfg(any(test, feature = "std"))]
251 pub fn try_into_std_string(
253 self,
254 ) -> Result<std::string::String, UrlEncodedCharacterDecodeError> {
255 self.chars()
256 .map(|c| c.map(UrlDecodedCharacter::into_char))
257 .collect()
258 }
259
260 pub fn strip_prefix(self, prefix: &str) -> Option<Self> {
263 let mut chars = self.chars();
264
265 for c in prefix.chars() {
266 if c == '/' {
267 let UrlDecodedCharacter::Literal('/') = chars.next()?.ok()? else {
268 return None;
269 };
270 } else if c != chars.next()?.ok()?.into_char() {
271 return None;
272 }
273 }
274
275 Some(chars.as_str())
276 }
277
278 pub const fn is_empty(self) -> bool {
280 self.0.is_empty()
281 }
282
283 fn with_decoded<'d, T, E: From<NamedDecodeError<'d>>, F: FnOnce(&str) -> Result<T, E>>(
284 self,
285 key: &'d str,
286 f: F,
287 ) -> Result<T, E> {
288 f(&self
289 .try_into_string::<1024>()
290 .map_err(|error| NamedDecodeError { key, error })?)
291 }
292}
293
294#[derive(Debug)]
295pub(crate) struct DeserializationError;
296
297impl fmt::Display for DeserializationError {
298 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
299 write!(f, "Deserialization Error")
300 }
301}
302
303impl serde::de::Error for DeserializationError {
304 fn custom<T: fmt::Display>(msg: T) -> Self {
305 log_warn!(
306 "DeserializationError: {}",
307 crate::logging::Display2Format(&msg)
308 );
309
310 Self
311 }
312}
313
314#[cfg(any(test, feature = "std"))]
315impl std::error::Error for DeserializationError {}
316
317impl From<NamedDecodeError<'_>> for DeserializationError {
318 fn from(NamedDecodeError { key, error }: NamedDecodeError) -> Self {
319 Self::custom(format_args!("No space to decode {key}: {error}"))
320 }
321}
322
323struct DeserializeUrlEncoded<'de> {
324 pub key: &'de str,
325 pub value: UrlEncodedString<'de>,
326}
327
328impl<'de> serde::de::IntoDeserializer<'de, DeserializationError> for DeserializeUrlEncoded<'de> {
329 type Deserializer = Self;
330
331 fn into_deserializer(self) -> Self::Deserializer {
332 self
333 }
334}
335
336macro_rules! deserialize_parse_value {
337 ($this:ident, $key_value:expr; $($deserialize:ident $visit:ident)*) => {
338 $(
339 fn $deserialize<V: serde::de::Visitor<'de>>(
340 $this,
341 visitor: V,
342 ) -> Result<V::Value, Self::Error> {
343 let (key, value) = $key_value;
344
345 value.with_decoded(key, |value| {
346 visitor.$visit(value.parse().map_err(|err| {
347 DeserializationError::custom(format_args!("Failed to parse {}: {}", key, err))
348 })?)
349 })
350 }
351 )*
352 };
353}
354
355impl<'de> serde::Deserializer<'de> for DeserializeUrlEncoded<'de> {
356 type Error = DeserializationError;
357
358 fn deserialize_any<V: serde::de::Visitor<'de>>(
359 self,
360 visitor: V,
361 ) -> Result<V::Value, Self::Error> {
362 self.value.with_decoded(self.key, |v| visitor.visit_str(v))
363 }
364
365 fn deserialize_struct<V: serde::de::Visitor<'de>>(
366 self,
367 name: &'static str,
368 fields: &'static [&'static str],
369 visitor: V,
370 ) -> Result<V::Value, Self::Error> {
371 if name == "UrlEncodedString" && fields == [URL_ENCODED_KEY] {
372 deserializer(self.key, self.value).deserialize_struct(name, fields, visitor)
373 } else {
374 Err(DeserializationError::custom("paths items must be atomic"))
375 }
376 }
377
378 fn deserialize_enum<V: serde::de::Visitor<'de>>(
379 self,
380 _name: &'static str,
381 _variants: &'static [&'static str],
382 visitor: V,
383 ) -> Result<V::Value, Self::Error> {
384 self.value.with_decoded(self.key, |value| {
385 visitor.visit_enum(serde::de::value::StrDeserializer::new(value))
386 })
387 }
388
389 fn deserialize_option<V: serde::de::Visitor<'de>>(
390 self,
391 visitor: V,
392 ) -> Result<V::Value, Self::Error> {
393 visitor.visit_some(self)
394 }
395
396 deserialize_parse_value!(
397 self, (self.key, self.value);
398 deserialize_bool visit_bool
399 deserialize_f32 visit_f32 deserialize_f64 visit_f64
400 deserialize_i8 visit_i8 deserialize_i16 visit_i16 deserialize_i32 visit_i32 deserialize_i64 visit_i64
401 deserialize_u8 visit_u8 deserialize_u16 visit_u16 deserialize_u32 visit_u32 deserialize_u64 visit_u64
402 );
403
404 serde::forward_to_deserialize_any! {
405 char str string
406 bytes byte_buf unit unit_struct newtype_struct seq tuple
407 tuple_struct map identifier ignored_any
408 }
409}
410
411#[derive(Debug)]
413#[cfg_attr(feature = "defmt", derive(defmt::Format))]
414pub struct FormDeserializationError;
415
416impl fmt::Display for FormDeserializationError {
417 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
418 write!(f, "Failed to deserialize Url Encoded Form")
419 }
420}
421
422impl serde::de::Error for FormDeserializationError {
423 fn custom<T: fmt::Display>(_msg: T) -> Self {
424 Self
425 }
426}
427
428#[cfg(any(test, feature = "std"))]
429impl std::error::Error for FormDeserializationError {}
430
431impl From<super::url_encoded::DeserializationError> for FormDeserializationError {
432 fn from(
433 super::url_encoded::DeserializationError: super::url_encoded::DeserializationError,
434 ) -> Self {
435 Self
436 }
437}
438
439struct DeserializeUrlEncodedForm<'r, T> {
440 pairs: T,
441 value: (&'r str, UrlEncodedString<'r>),
442}
443
444pub fn deserialize_form<T: serde::de::DeserializeOwned>(
446 UrlEncodedString(form): UrlEncodedString,
447) -> Result<T, FormDeserializationError> {
448 T::deserialize(DeserializeUrlEncodedForm {
449 pairs: form.split('&').filter(|s| !s.is_empty()),
450 value: ("", UrlEncodedString("")),
451 })
452}
453
454impl<'de, T: Iterator<Item = &'de str>> serde::de::Deserializer<'de>
455 for DeserializeUrlEncodedForm<'de, T>
456{
457 type Error = FormDeserializationError;
458
459 fn deserialize_any<V: serde::de::Visitor<'de>>(
460 self,
461 visitor: V,
462 ) -> Result<V::Value, Self::Error> {
463 visitor.visit_map(self)
464 }
465
466 serde::forward_to_deserialize_any! {
467 bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
468 bytes byte_buf option unit unit_struct newtype_struct seq tuple
469 tuple_struct map struct enum identifier ignored_any
470 }
471}
472
473impl<'de, T: Iterator<Item = &'de str>> serde::de::MapAccess<'de>
474 for DeserializeUrlEncodedForm<'de, T>
475{
476 type Error = FormDeserializationError;
477
478 fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
479 where
480 K: serde::de::DeserializeSeed<'de>,
481 {
482 self.pairs
483 .next()
484 .map(|value| {
485 let (key, value) = value.split_once('=').ok_or(FormDeserializationError)?;
486
487 self.value = (key, UrlEncodedString(value));
488
489 Ok(seed.deserialize(DeserializeUrlEncoded {
490 key,
491 value: UrlEncodedString(key),
492 })?)
493 })
494 .transpose()
495 }
496
497 fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
498 where
499 V: serde::de::DeserializeSeed<'de>,
500 {
501 let (name, value) = self.value;
502
503 Ok(seed.deserialize(DeserializeUrlEncoded { key: name, value })?)
504 }
505}