cyware_convert/encoding/
html.rs

1#[cfg(target_family = "wasm")]
2use serde::{Deserialize, Serialize};
3
4use crate::Operation;
5use crate::OperationError;
6
7#[derive(Clone)]
8#[cfg_attr(target_family = "wasm", derive(Serialize, Deserialize))]
9pub struct HtmlDecode {}
10
11// Inspired by this https://doc.rust-lang.org/stable/nightly-rustc/src/rustdoc/html/escape.rs.html#1-40
12// and this http://stackoverflow.com/questions/7381974
13impl Operation for HtmlDecode {
14    fn execute(&self, input: &[u8]) -> Result<Vec<u8>, OperationError> {
15        let mut decoded = vec![];
16        let mut i = 0;
17        while i < input.len() {
18            if let Some(window) = input.get(i..i + 4) {
19                match window {
20                    b"&gt;" => {
21                        decoded.push(b'>');
22                        i += 4;
23                        continue;
24                    }
25                    b"&lt;" => {
26                        decoded.push(b'<');
27                        i += 4;
28                        continue;
29                    }
30                    _ => (),
31                };
32            }
33            if let Some(window) = input.get(i..i + 5) {
34                match window {
35                    b"&amp;" => {
36                        decoded.push(b'&');
37                        i += 5;
38                        continue;
39                    }
40                    b"&#39;" => {
41                        decoded.push(b'\\');
42                        i += 5;
43                        continue;
44                    }
45
46                    _ => (),
47                }
48            }
49            if let Some(window) = input.get(i..i + 6) {
50                if window == b"&quot;" {
51                    decoded.push(b'"');
52                    i += 6;
53                    continue;
54                }
55            }
56            decoded.push(input[i]);
57            i += 1;
58        }
59        Ok(decoded)
60    }
61}
62
63impl HtmlDecode {
64    pub const fn new() -> Self {
65        HtmlDecode {}
66    }
67}
68
69#[derive(Clone)]
70#[cfg_attr(target_family = "wasm", derive(Serialize, Deserialize))]
71pub struct HtmlEncode {}
72
73impl Operation for HtmlEncode {
74    fn execute(&self, input: &[u8]) -> Result<Vec<u8>, OperationError> {
75        let mut encoded = vec![];
76        for ch in input {
77            match ch {
78                b'>' => encoded.extend_from_slice(b"&gt;"),
79                b'<' => encoded.extend_from_slice(b"&lt;"),
80                b'&' => encoded.extend_from_slice(b"&amp;"),
81                b'\\' => encoded.extend_from_slice(b"&#39;"),
82                b'"' => encoded.extend_from_slice(b"&quot;"),
83                byte => encoded.push(*byte),
84            };
85        }
86        Ok(encoded)
87    }
88}
89
90impl HtmlEncode {
91    pub const fn new() -> Self {
92        HtmlEncode {}
93    }
94}
95
96#[cfg(test)]
97mod tests {
98    use super::*;
99
100    #[test]
101    fn url_decode() {
102        let encoder = HtmlDecode::new();
103        let actual = encoder
104            .execute(b"&#39;&amp;&lt;script&gt;alert(1)&lt;/script&gt;a&quot;")
105            .unwrap();
106        let expected = b"\\&<script>alert(1)</script>a\"".to_vec();
107        assert_eq!(actual, expected);
108    }
109
110    #[test]
111    fn url_encode() {
112        let encoder = HtmlEncode::new();
113        let actual = encoder.execute(b"\\&<script>alert(1)</script>a\"").unwrap();
114        let expected = b"&#39;&amp;&lt;script&gt;alert(1)&lt;/script&gt;a&quot;".to_vec();
115        assert_eq!(actual, expected);
116    }
117}