buup/transformers/
url_decode.rs1use crate::{Transform, TransformError, TransformerCategory};
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub struct UrlDecode;
6
7impl Transform for UrlDecode {
8 fn name(&self) -> &'static str {
9 "URL Decode"
10 }
11
12 fn id(&self) -> &'static str {
13 "urldecode"
14 }
15
16 fn description(&self) -> &'static str {
17 "Decode URL-encoded text"
18 }
19
20 fn category(&self) -> TransformerCategory {
21 TransformerCategory::Decoder
22 }
23
24 fn transform(&self, input: &str) -> Result<String, TransformError> {
25 url_decode(input).map_err(|_e| TransformError::UrlDecodeError)
26 }
27
28 fn default_test_input(&self) -> &'static str {
29 "Hello%2C+World%21"
30 }
31}
32
33fn url_decode(input: &str) -> Result<String, &'static str> {
35 let mut decoded_bytes = Vec::with_capacity(input.len());
37 let mut bytes = input.bytes();
38
39 while let Some(byte) = bytes.next() {
40 match byte {
41 b'+' => decoded_bytes.push(b' '),
43 b'%' => {
45 let hi = bytes
47 .next()
48 .ok_or("Invalid URL encoding: unexpected end of input")?;
49 let lo = bytes
50 .next()
51 .ok_or("Invalid URL encoding: unexpected end of input")?;
52
53 let hex_to_digit = |b| match b {
55 b'0'..=b'9' => Ok(b - b'0'),
56 b'A'..=b'F' => Ok(b - b'A' + 10),
57 b'a'..=b'f' => Ok(b - b'a' + 10),
58 _ => Err("Invalid URL encoding: invalid hex digit"),
59 };
60
61 let high_nibble = hex_to_digit(hi)?;
62 let low_nibble = hex_to_digit(lo)?;
63
64 let decoded_byte = (high_nibble << 4) | low_nibble;
65 decoded_bytes.push(decoded_byte);
66 }
67 _ => decoded_bytes.push(byte),
69 }
70 }
71
72 String::from_utf8(decoded_bytes).map_err(|_| "Invalid UTF-8 sequence in decoded URL")
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79
80 #[test]
81 fn test_url_decode() {
82 let transformer = UrlDecode;
83 assert_eq!(
84 transformer
85 .transform(transformer.default_test_input())
86 .unwrap(),
87 "Hello, World!"
88 );
89 assert_eq!(transformer.transform("a+b").unwrap(), "a b");
90 assert_eq!(transformer.transform("100%25").unwrap(), "100%");
91 }
92}