1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
use jetscii::{bytes, BytesConst}; use lazy_static::lazy_static; use std::borrow::Cow; pub fn xml_escape<'a>(raw: &'a str) -> Cow<'a, str> { lazy_static! { static ref ESCAPE_BYTES: BytesConst = bytes!(b'<', b'>', b'&', b'\'', b'"'); } let bytes = raw.as_bytes(); if let Some(off) = ESCAPE_BYTES.find(bytes) { let mut result = String::with_capacity(raw.len()); result.push_str(&raw[0..off]); let mut pos = off + 1; match bytes[pos - 1] { b'<' => result.push_str("<"), b'>' => result.push_str(">"), b'&' => result.push_str("&"), b'\'' => result.push_str("'"), b'"' => result.push_str("""), _ => unreachable!(), } while let Some(off) = ESCAPE_BYTES.find(&bytes[pos..]) { result.push_str(&raw[pos..pos + off]); pos += off + 1; match bytes[pos - 1] { b'<' => result.push_str("<"), b'>' => result.push_str(">"), b'&' => result.push_str("&"), b'\'' => result.push_str("'"), b'"' => result.push_str("""), _ => unreachable!(), } } result.push_str(&raw[pos..]); Cow::Owned(result) } else { Cow::Borrowed(raw) } } #[test] fn test_escape() { assert_eq!(xml_escape("< < <"), "< < <"); assert_eq!( xml_escape("<script>alert('Hello XSS')</script>"), "<script>alert('Hello XSS')</script>" ); }