mirror of
https://github.com/askama-rs/askama.git
synced 2025-10-03 07:45:14 +00:00
Move escaping algorithm into a separate module
This commit is contained in:
parent
23279c3bce
commit
fdbe45ec60
50
askama_shared/src/escaping.rs
Normal file
50
askama_shared/src/escaping.rs
Normal file
@ -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::<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"&"); },
|
||||||
|
_ => 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("<foo".to_string()), "<foo");
|
||||||
|
}
|
||||||
|
}
|
@ -13,6 +13,7 @@ pub use self::json::json;
|
|||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
use escaping;
|
||||||
use super::Result;
|
use super::Result;
|
||||||
|
|
||||||
|
|
||||||
@ -33,44 +34,10 @@ pub const BUILT_IN_FILTERS: [&str; 9] = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
fn escapable(b: &u8) -> bool {
|
|
||||||
*b == b'<' || *b == b'>' || *b == b'&'
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Escapes `&`, `<` and `>` in strings
|
/// Escapes `&`, `<` and `>` in strings
|
||||||
pub fn escape(s: &fmt::Display) -> Result<String> {
|
pub fn escape(s: &fmt::Display) -> Result<String> {
|
||||||
let s = format!("{}", s);
|
let s = format!("{}", s);
|
||||||
let mut found = Vec::new();
|
Ok(escaping::escape(s))
|
||||||
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::<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"&"); },
|
|
||||||
_ => panic!("incorrect indexing"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if start < bytes.len() - 1 {
|
|
||||||
res.extend(&bytes[start..]);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(String::from_utf8(res).unwrap())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Alias for the `escape()` filter
|
/// Alias for the `escape()` filter
|
||||||
@ -135,17 +102,10 @@ pub fn join<T, I, S>(input: I, separator: S) -> Result<String>
|
|||||||
Ok(rv)
|
Ok(rv)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
#[test]
|
|
||||||
fn test_escape() {
|
|
||||||
assert_eq!(escape(&"").unwrap(), "");
|
|
||||||
assert_eq!(escape(&"<&>").unwrap(), "<&>");
|
|
||||||
assert_eq!(escape(&"bla&").unwrap(), "bla&");
|
|
||||||
assert_eq!(escape(&"<foo").unwrap(), "<foo");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_lower() {
|
fn test_lower() {
|
||||||
assert_eq!(lower(&"Foo").unwrap(), "foo");
|
assert_eq!(lower(&"Foo").unwrap(), "foo");
|
||||||
|
@ -16,6 +16,7 @@ pub mod path;
|
|||||||
pub use parser::parse;
|
pub use parser::parse;
|
||||||
pub use generator::generate;
|
pub use generator::generate;
|
||||||
|
|
||||||
|
mod escaping;
|
||||||
mod generator;
|
mod generator;
|
||||||
mod parser;
|
mod parser;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user