Don't use different escaping rules for attributes
This commit is contained in:
parent
0b531572cf
commit
b1aa300884
3 changed files with 20 additions and 78 deletions
|
@ -7,27 +7,9 @@ use std::fmt::Writer as FmtWriter;
|
||||||
|
|
||||||
pub type FmtResult<T> = Result<T, fmt::Error>;
|
pub type FmtResult<T> = Result<T, fmt::Error>;
|
||||||
|
|
||||||
/// Utilities for escaping HTML5 markup.
|
/// Escape an HTML value.
|
||||||
///
|
pub fn escape(s: &str) -> String {
|
||||||
/// These follow the *HTML fragment serialization algorithm*, as
|
render(|w| rt::escape(w, |w| w.write_str(s)))
|
||||||
/// 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)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Internal functions used by the `maud_macros` package. You should
|
/// Internal functions used by the `maud_macros` package. You should
|
||||||
|
@ -38,36 +20,19 @@ pub mod rt {
|
||||||
use std::fmt::Writer as FmtWriter;
|
use std::fmt::Writer as FmtWriter;
|
||||||
use super::FmtResult;
|
use super::FmtResult;
|
||||||
|
|
||||||
struct AttrEscaper<'a, 'b: 'a> {
|
struct Escaper<'a, 'b: 'a> {
|
||||||
inner: &'a mut (FmtWriter + 'b),
|
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<()> {
|
fn write_str(&mut self, s: &str) -> FmtResult<()> {
|
||||||
for c in s.chars() {
|
for c in s.chars() {
|
||||||
try!(match c {
|
try!(match c {
|
||||||
'&' => self.inner.write_str("&"),
|
'&' => 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(">"),
|
||||||
|
'"' => self.inner.write_str("""),
|
||||||
|
'\'' => self.inner.write_str("'"),
|
||||||
_ => write!(self.inner, "{}", c),
|
_ => write!(self.inner, "{}", c),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -76,17 +41,10 @@ pub mod rt {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[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: FnOnce(&mut FmtWriter) -> FmtResult<()>
|
||||||
{
|
{
|
||||||
f(&mut AttrEscaper { inner: w })
|
f(&mut Escaper { 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 })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,9 +9,8 @@ use super::render::Renderer;
|
||||||
|
|
||||||
#[derive(Copy, PartialEq, Show)]
|
#[derive(Copy, PartialEq, Show)]
|
||||||
pub enum Escape {
|
pub enum Escape {
|
||||||
None,
|
PassThru,
|
||||||
Attr,
|
Escape,
|
||||||
Body,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! guard {
|
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);
|
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.
|
/// Construct a Rust AST parser from the given token tree.
|
||||||
fn new_rust_parser(&self, tts: Vec<TokenTree>) -> RustParser<'s> {
|
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())
|
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();
|
let lit = self.new_rust_parser(vec![tt.clone()]).parse_lit();
|
||||||
match lit_to_string(self.render.cx, lit, minus) {
|
match lit_to_string(self.render.cx, lit, minus) {
|
||||||
Some(s) => {
|
Some(s) => self.render.string(s.as_slice(), Escape::Escape),
|
||||||
let escape = self.choose_escape();
|
|
||||||
self.render.string(s.as_slice(), escape);
|
|
||||||
},
|
|
||||||
None => return false,
|
None => return false,
|
||||||
}
|
}
|
||||||
true
|
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 {
|
let (escape, sp) = match self.input {
|
||||||
[ref tt @ dollar!(), dollar!(), ..] => {
|
[ref tt @ dollar!(), dollar!(), ..] => {
|
||||||
self.shift(2);
|
self.shift(2);
|
||||||
(Escape::None, tt.get_span())
|
(Escape::PassThru, tt.get_span())
|
||||||
},
|
},
|
||||||
[ref tt @ dollar!(), ..] => {
|
[ref tt @ dollar!(), ..] => {
|
||||||
self.shift(1);
|
self.shift(1);
|
||||||
(self.choose_escape(), tt.get_span())
|
(Escape::Escape, tt.get_span())
|
||||||
},
|
},
|
||||||
_ => return false,
|
_ => return false,
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,8 +4,8 @@ use syntax::ext::base::ExtCtxt;
|
||||||
use syntax::parse::token;
|
use syntax::parse::token;
|
||||||
use syntax::ptr::P;
|
use syntax::ptr::P;
|
||||||
|
|
||||||
|
use maud;
|
||||||
use super::parse::Escape;
|
use super::parse::Escape;
|
||||||
use maud::escape;
|
|
||||||
|
|
||||||
pub struct Renderer<'cx, 's: 'cx, 'o> {
|
pub struct Renderer<'cx, 's: 'cx, 'o> {
|
||||||
pub cx: &'cx mut ExtCtxt<'s>,
|
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.
|
/// Append a literal string, with the specified escaping method.
|
||||||
pub fn string(&mut self, s: &str, escape: Escape) {
|
pub fn string(&mut self, s: &str, escape: Escape) {
|
||||||
let s = match escape {
|
let s = match escape {
|
||||||
Escape::None => s.into_cow(),
|
Escape::PassThru => s.into_cow(),
|
||||||
Escape::Attr => escape::attribute(s).into_cow(),
|
Escape::Escape => maud::escape(s).into_cow(),
|
||||||
Escape::Body => escape::non_attribute(s).into_cow(),
|
|
||||||
};
|
};
|
||||||
self.write(s.as_slice());
|
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) {
|
pub fn splice(&mut self, expr: P<Expr>, escape: Escape) {
|
||||||
let w = self.w;
|
let w = self.w;
|
||||||
self.stmts.push(match escape {
|
self.stmts.push(match escape {
|
||||||
Escape::None => quote_stmt!(self.cx, try!(write!($w, "{}", $expr))),
|
Escape::PassThru => quote_stmt!(self.cx, try!(write!($w, "{}", $expr))),
|
||||||
Escape::Attr =>
|
Escape::Escape =>
|
||||||
quote_stmt!(self.cx,
|
quote_stmt!(self.cx,
|
||||||
try!(::maud::rt::escape_attribute($w, |w| write!(w, "{}", $expr)))),
|
try!(::maud::rt::escape($w, |w| write!(w, "{}", $expr)))),
|
||||||
Escape::Body =>
|
|
||||||
quote_stmt!(self.cx,
|
|
||||||
try!(::maud::rt::escape_non_attribute($w, |w| write!(w, "{}", $expr)))),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue