From fdbe45ec60d628a014a1414b1ea8588ba4f9573c Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Mon, 4 Sep 2017 20:37:05 +0200 Subject: Move escaping algorithm into a separate module --- askama_shared/src/escaping.rs | 50 ++++++++++++++++++++++++++++++++++++++++ askama_shared/src/filters/mod.rs | 46 +++--------------------------------- askama_shared/src/lib.rs | 1 + 3 files changed, 54 insertions(+), 43 deletions(-) create mode 100644 askama_shared/src/escaping.rs diff --git a/askama_shared/src/escaping.rs b/askama_shared/src/escaping.rs new file mode 100644 index 0000000..54f58e4 --- /dev/null +++ b/askama_shared/src/escaping.rs @@ -0,0 +1,50 @@ +fn escapable(b: &u8) -> bool { + *b == b'<' || *b == b'>' || *b == b'&' +} + +pub fn escape(s: String) -> String { + let mut found = Vec::new(); + for (i, b) in s.as_bytes().iter().enumerate() { + if escapable(b) { + found.push(i); + } + } + if found.is_empty() { + return s; + } + + let bytes = s.as_bytes(); + let max_len = bytes.len() + found.len() * 3; + let mut res = Vec::::with_capacity(max_len); + let mut start = 0; + for idx in &found { + if start < *idx { + res.extend(&bytes[start..*idx]); + } + start = *idx + 1; + match bytes[*idx] { + b'<' => { res.extend(b"<"); }, + b'>' => { res.extend(b">"); }, + b'&' => { res.extend(b"&"); }, + _ => panic!("incorrect indexing"), + } + } + if start < bytes.len() - 1 { + res.extend(&bytes[start..]); + } + + String::from_utf8(res).unwrap() +} + + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn test_escape() { + assert_eq!(escape("".to_string()), ""); + assert_eq!(escape("<&>".to_string()), "<&>"); + assert_eq!(escape("bla&".to_string()), "bla&"); + assert_eq!(escape(" bool { - *b == b'<' || *b == b'>' || *b == b'&' -} - /// Escapes `&`, `<` and `>` in strings pub fn escape(s: &fmt::Display) -> Result { let s = format!("{}", s); - let mut found = Vec::new(); - for (i, b) in s.as_bytes().iter().enumerate() { - if escapable(b) { - found.push(i); - } - } - if found.is_empty() { - return Ok(s); - } - - let bytes = s.as_bytes(); - let max_len = bytes.len() + found.len() * 3; - let mut res = Vec::::with_capacity(max_len); - let mut start = 0; - for idx in &found { - if start < *idx { - res.extend(&bytes[start..*idx]); - } - start = *idx + 1; - match bytes[*idx] { - b'<' => { res.extend(b"<"); }, - b'>' => { res.extend(b">"); }, - b'&' => { res.extend(b"&"); }, - _ => panic!("incorrect indexing"), - } - } - if start < bytes.len() - 1 { - res.extend(&bytes[start..]); - } - - Ok(String::from_utf8(res).unwrap()) + Ok(escaping::escape(s)) } /// Alias for the `escape()` filter @@ -135,17 +102,10 @@ pub fn join(input: I, separator: S) -> Result Ok(rv) } + #[cfg(test)] mod tests { use super::*; - #[test] - fn test_escape() { - assert_eq!(escape(&"").unwrap(), ""); - assert_eq!(escape(&"<&>").unwrap(), "<&>"); - assert_eq!(escape(&"bla&").unwrap(), "bla&"); - assert_eq!(escape(&"