diff options
Diffstat (limited to 'askama_shared/src')
-rw-r--r-- | askama_shared/src/escaping.rs | 85 |
1 files changed, 39 insertions, 46 deletions
diff --git a/askama_shared/src/escaping.rs b/askama_shared/src/escaping.rs index 93545fd..930dbbe 100644 --- a/askama_shared/src/escaping.rs +++ b/askama_shared/src/escaping.rs @@ -47,60 +47,53 @@ where } } -fn escapable(b: u8) -> bool { - match b { - b'<' | b'>' | b'&' | b'"' | b'\'' | b'/' => true, - _ => false, - } -} - +const FLAG: u8 = b'>' - b'"'; pub fn escape(s: String) -> String { - let mut found = Vec::new(); + let mut found = None; for (i, b) in s.as_bytes().iter().enumerate() { - if escapable(*b) { - found.push(i); + if b.wrapping_sub(b'"') <= FLAG { + match *b { + b'<' | b'>' | b'&' | b'"' | b'\'' | b'/' => { + found = Some(i); + break; + } + _ => (), + }; } } - if found.is_empty() { - return s; - } - let bytes = s.as_bytes(); - let max_len = bytes.len() + found.len() * 5; - let mut res = Vec::<u8>::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"&"); + if let Some(found) = found { + let bytes = s.as_bytes(); + let mut res = Vec::with_capacity(s.len() + 6); + res.extend(&bytes[0..found]); + for c in bytes[found..].iter() { + match *c { + b'<' => { + res.extend(b"<"); + } + b'>' => { + res.extend(b">"); + } + b'&' => { + res.extend(b"&"); + } + b'"' => { + res.extend(b"""); + } + b'\'' => { + res.extend(b"'"); + } + b'/' => { + res.extend(b"/"); + } + _ => res.push(*c), } - b'"' => { - res.extend(b"""); - } - b'\'' => { - res.extend(b"'"); - } - b'/' => { - res.extend(b"/"); - } - _ => panic!("incorrect indexing"), } - } - if start < bytes.len() { - res.extend(&bytes[start..]); - } - String::from_utf8(res).unwrap() + String::from_utf8(res).unwrap() + } else { + s + } } #[cfg(test)] |