Skip to main content

rustbasic_core/
serde_urlencoded.rs

1
2/// Decodes a URL-encoded string into any type that implements serde::de::DeserializeOwned.
3pub fn from_str<T: serde::de::DeserializeOwned>(s: &str) -> Result<T, String> {
4    let mut map = serde_json::Map::new();
5    for pair in s.split('&') {
6        if pair.is_empty() {
7            continue;
8        }
9        let mut parts = pair.splitn(2, '=');
10        let key = parts.next().unwrap_or("");
11        let val = parts.next().unwrap_or("");
12
13        let decoded_key = url_decode(key)?;
14        let decoded_val = url_decode(val)?;
15
16        map.insert(decoded_key, serde_json::Value::String(decoded_val));
17    }
18    serde_json::from_value(serde_json::Value::Object(map))
19        .map_err(|e| e.to_string())
20}
21
22/// Decodes a URL-encoded byte array into any type that implements serde::de::DeserializeOwned.
23pub fn from_bytes<T: serde::de::DeserializeOwned>(bytes: &[u8]) -> Result<T, String> {
24    let s = std::str::from_utf8(bytes).map_err(|e| e.to_string())?;
25    from_str(s)
26}
27
28fn url_decode(s: &str) -> Result<String, String> {
29    let mut decoded = String::new();
30    let mut chars = s.chars();
31    while let Some(c) = chars.next() {
32        if c == '+' {
33            decoded.push(' ');
34        } else if c == '%' {
35            let h0 = chars.next().ok_or("Format URL-encoded tidak valid")?;
36            let h1 = chars.next().ok_or("Format URL-encoded tidak valid")?;
37            let hex_str = format!("{}{}", h0, h1);
38            let byte = u8::from_str_radix(&hex_str, 16)
39                .map_err(|e| e.to_string())?;
40            decoded.push(byte as char);
41        } else {
42            decoded.push(c);
43        }
44    }
45    Ok(decoded)
46}