#[cfg(target_family = "wasm")]
use serde::{Deserialize, Serialize};
use crate::Operation;
use crate::OperationError;
#[derive(Clone)]
#[cfg_attr(target_family = "wasm", derive(Serialize, Deserialize))]
pub struct HtmlDecode {}
impl Operation for HtmlDecode {
fn execute(&self, input: &[u8]) -> Result<Vec<u8>, OperationError> {
let mut decoded = vec![];
let mut i = 0;
while i < input.len() {
if let Some(window) = input.get(i..i + 4) {
match window {
b">" => {
decoded.push(b'>');
i += 4;
continue;
}
b"<" => {
decoded.push(b'<');
i += 4;
continue;
}
_ => (),
};
}
if let Some(window) = input.get(i..i + 5) {
match window {
b"&" => {
decoded.push(b'&');
i += 5;
continue;
}
b"'" => {
decoded.push(b'\\');
i += 5;
continue;
}
_ => (),
}
}
if let Some(window) = input.get(i..i + 6) {
if window == b""" {
decoded.push(b'"');
i += 6;
continue;
}
}
decoded.push(input[i]);
i += 1;
}
Ok(decoded)
}
}
impl HtmlDecode {
pub fn new() -> Self {
HtmlDecode {}
}
}
#[derive(Clone)]
#[cfg_attr(target_family = "wasm", derive(Serialize, Deserialize))]
pub struct HtmlEncode {}
impl Operation for HtmlEncode {
fn execute(&self, input: &[u8]) -> Result<Vec<u8>, OperationError> {
let mut encoded = vec![];
for ch in input {
match ch {
b'>' => encoded.extend_from_slice(b">"),
b'<' => encoded.extend_from_slice(b"<"),
b'&' => encoded.extend_from_slice(b"&"),
b'\\' => encoded.extend_from_slice(b"'"),
b'"' => encoded.extend_from_slice(b"""),
byte => encoded.push(*byte),
};
}
Ok(encoded)
}
}
impl HtmlEncode {
pub fn new() -> Self {
HtmlEncode {}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn url_decode() {
let encoder = HtmlDecode::new();
let actual = encoder
.execute(b"'&<script>alert(1)</script>a"")
.unwrap();
let expected = b"\\&<script>alert(1)</script>a\"".to_vec();
assert_eq!(actual, expected);
}
#[test]
fn url_encode() {
let encoder = HtmlEncode::new();
let actual = encoder.execute(b"\\&<script>alert(1)</script>a\"").unwrap();
let expected = b"'&<script>alert(1)</script>a"".to_vec();
assert_eq!(actual, expected);
}
}