From b1aa3008842fcf83069b8cf9ca273cfafd61d9a0 Mon Sep 17 00:00:00 2001 From: Chris Wong <lambda.fairy@gmail.com> Date: Sun, 11 Jan 2015 10:58:27 +1300 Subject: [PATCH] Don't use different escaping rules for attributes --- maud/src/lib.rs | 60 ++++++--------------------------------- maud_macros/src/parse.rs | 22 ++++---------- maud_macros/src/render.rs | 16 ++++------- 3 files changed, 20 insertions(+), 78 deletions(-) diff --git a/maud/src/lib.rs b/maud/src/lib.rs index 88d5514..7fdd9dc 100644 --- a/maud/src/lib.rs +++ b/maud/src/lib.rs @@ -7,27 +7,9 @@ use std::fmt::Writer as FmtWriter; pub type FmtResult<T> = Result<T, fmt::Error>; -/// Utilities for escaping HTML5 markup. -/// -/// These follow the *HTML fragment serialization algorithm*, as -/// specified by the [HTML 5.1 Working Draft][1]. -/// -/// [1]: http://www.w3.org/TR/html51/syntax.html#escapingString -pub mod escape { - use std::fmt::Writer as FmtWriter; - - use super::render; - use super::rt; - - /// Escape a double-quoted attribute value, as per HTML5 rules. - pub fn attribute(s: &str) -> String { - render(|w| rt::escape_attribute(w, |w| w.write_str(s))) - } - - /// Escape non-attribute text content, as per HTML5 rules. - pub fn non_attribute(s: &str) -> String { - render(|w| rt::escape_non_attribute(w, |w| w.write_str(s))) - } +/// Escape an HTML value. +pub fn escape(s: &str) -> String { + render(|w| rt::escape(w, |w| w.write_str(s))) } /// Internal functions used by the `maud_macros` package. You should @@ -38,36 +20,19 @@ pub mod rt { use std::fmt::Writer as FmtWriter; use super::FmtResult; - struct AttrEscaper<'a, 'b: 'a> { + struct Escaper<'a, 'b: 'a> { inner: &'a mut (FmtWriter + 'b), } - impl<'a, 'b> FmtWriter for AttrEscaper<'a, 'b> { + impl<'a, 'b> FmtWriter for Escaper<'a, 'b> { fn write_str(&mut self, s: &str) -> FmtResult<()> { for c in s.chars() { try!(match c { '&' => self.inner.write_str("&"), - '\u{A0}' => self.inner.write_str(" "), - '"' => self.inner.write_str("""), - _ => write!(self.inner, "{}", c), - }); - } - Ok(()) - } - } - - struct NonAttrEscaper<'a, 'b: 'a> { - inner: &'a mut (FmtWriter + 'b), - } - - impl<'a, 'b> FmtWriter for NonAttrEscaper<'a, 'b> { - fn write_str(&mut self, s: &str) -> FmtResult<()> { - for c in s.chars() { - try!(match c { - '&' => self.inner.write_str("&"), - '\u{A0}' => self.inner.write_str(" "), '<' => self.inner.write_str("<"), '>' => self.inner.write_str(">"), + '"' => self.inner.write_str("""), + '\'' => self.inner.write_str("'"), _ => write!(self.inner, "{}", c), }); } @@ -76,17 +41,10 @@ pub mod rt { } #[inline] - pub fn escape_attribute<F>(w: &mut FmtWriter, f: F) -> FmtResult<()> where + pub fn escape<F>(w: &mut FmtWriter, f: F) -> FmtResult<()> where F: FnOnce(&mut FmtWriter) -> FmtResult<()> { - f(&mut AttrEscaper { inner: w }) - } - - #[inline] - pub fn escape_non_attribute<F>(w: &mut FmtWriter, f: F) -> FmtResult<()> where - F: FnOnce(&mut FmtWriter) -> FmtResult<()> - { - f(&mut NonAttrEscaper { inner: w }) + f(&mut Escaper { inner: w }) } } diff --git a/maud_macros/src/parse.rs b/maud_macros/src/parse.rs index da183f4..40f21d7 100644 --- a/maud_macros/src/parse.rs +++ b/maud_macros/src/parse.rs @@ -9,9 +9,8 @@ use super::render::Renderer; #[derive(Copy, PartialEq, Show)] pub enum Escape { - None, - Attr, - Body, + PassThru, + Escape, } macro_rules! guard { @@ -85,14 +84,6 @@ impl<'cx: 'r, 's: 'cx, 'i, 'r, 'o: 'r> Parser<'cx, 's, 'i, 'r, 'o> { self.input = self.input.slice_from(n); } - fn choose_escape(&self) -> Escape { - if self.in_attr { - Escape::Attr - } else { - Escape::Body - } - } - /// Construct a Rust AST parser from the given token tree. fn new_rust_parser(&self, tts: Vec<TokenTree>) -> RustParser<'s> { parse::tts_to_parser(self.render.cx.parse_sess, tts, self.render.cx.cfg.clone()) @@ -135,10 +126,7 @@ impl<'cx: 'r, 's: 'cx, 'i, 'r, 'o: 'r> Parser<'cx, 's, 'i, 'r, 'o> { }; let lit = self.new_rust_parser(vec![tt.clone()]).parse_lit(); match lit_to_string(self.render.cx, lit, minus) { - Some(s) => { - let escape = self.choose_escape(); - self.render.string(s.as_slice(), escape); - }, + Some(s) => self.render.string(s.as_slice(), Escape::Escape), None => return false, } true @@ -148,11 +136,11 @@ impl<'cx: 'r, 's: 'cx, 'i, 'r, 'o: 'r> Parser<'cx, 's, 'i, 'r, 'o> { let (escape, sp) = match self.input { [ref tt @ dollar!(), dollar!(), ..] => { self.shift(2); - (Escape::None, tt.get_span()) + (Escape::PassThru, tt.get_span()) }, [ref tt @ dollar!(), ..] => { self.shift(1); - (self.choose_escape(), tt.get_span()) + (Escape::Escape, tt.get_span()) }, _ => return false, }; diff --git a/maud_macros/src/render.rs b/maud_macros/src/render.rs index 22225f4..4736bf4 100644 --- a/maud_macros/src/render.rs +++ b/maud_macros/src/render.rs @@ -4,8 +4,8 @@ use syntax::ext::base::ExtCtxt; use syntax::parse::token; use syntax::ptr::P; +use maud; use super::parse::Escape; -use maud::escape; pub struct Renderer<'cx, 's: 'cx, 'o> { pub cx: &'cx mut ExtCtxt<'s>, @@ -43,9 +43,8 @@ impl<'cx, 's: 'cx, 'o> Renderer<'cx, 's, 'o> { /// Append a literal string, with the specified escaping method. pub fn string(&mut self, s: &str, escape: Escape) { let s = match escape { - Escape::None => s.into_cow(), - Escape::Attr => escape::attribute(s).into_cow(), - Escape::Body => escape::non_attribute(s).into_cow(), + Escape::PassThru => s.into_cow(), + Escape::Escape => maud::escape(s).into_cow(), }; self.write(s.as_slice()); } @@ -54,13 +53,10 @@ impl<'cx, 's: 'cx, 'o> Renderer<'cx, 's, 'o> { pub fn splice(&mut self, expr: P<Expr>, escape: Escape) { let w = self.w; self.stmts.push(match escape { - Escape::None => quote_stmt!(self.cx, try!(write!($w, "{}", $expr))), - Escape::Attr => + Escape::PassThru => quote_stmt!(self.cx, try!(write!($w, "{}", $expr))), + Escape::Escape => quote_stmt!(self.cx, - try!(::maud::rt::escape_attribute($w, |w| write!(w, "{}", $expr)))), - Escape::Body => - quote_stmt!(self.cx, - try!(::maud::rt::escape_non_attribute($w, |w| write!(w, "{}", $expr)))), + try!(::maud::rt::escape($w, |w| write!(w, "{}", $expr)))), }); }