From 8dd4db11ec72ca1c3db83cf929a21b78a749b06b Mon Sep 17 00:00:00 2001 From: Noah Hellman Date: Mon, 30 Jan 2023 22:48:34 +0100 Subject: [PATCH] html: escape user provided attribute values --- src/html.rs | 73 ++++++++++++++++++++++++++++------------------------- 1 file changed, 38 insertions(+), 35 deletions(-) diff --git a/src/html.rs b/src/html.rs index 8554f1b..6a6fc59 100644 --- a/src/html.rs +++ b/src/html.rs @@ -167,7 +167,9 @@ impl<'s, I: Iterator>, W: std::fmt::Write> Writer<'s, I, W> { if dst.is_empty() { self.out.write_str(" { @@ -193,7 +195,9 @@ impl<'s, I: Iterator>, W: std::fmt::Write> Writer<'s, I, W> { } for (a, v) in attrs.iter().filter(|(a, _)| *a != "class") { - write!(self.out, r#" {}="{}""#, a, v)?; + write!(self.out, r#" {}=""#, a)?; + self.write_escape(v)?; + self.out.write_char('"')?; } if let Container::Heading { @@ -204,7 +208,9 @@ impl<'s, I: Iterator>, W: std::fmt::Write> Writer<'s, I, W> { | Container::Section { id } = &c { if !attrs.iter().any(|(a, _)| a == "id") { - write!(self.out, r#" id="{}""#, id)?; + self.out.write_str(r#" id=""#)?; + self.write_escape(id)?; + self.out.write_char('"')?; } } @@ -271,7 +277,9 @@ impl<'s, I: Iterator>, W: std::fmt::Write> Writer<'s, I, W> { } Container::CodeBlock { lang } => { if let Some(l) = lang { - write!(self.out, r#">"#, l)?; + self.out.write_str(r#">"#)?; } else { self.out.write_str(">")?; } @@ -381,37 +389,11 @@ impl<'s, I: Iterator>, W: std::fmt::Write> Writer<'s, I, W> { Container::Mark => self.out.write_str("")?, } } - Event::Str(s) => { - let mut s: &str = s.as_ref(); - match self.raw { - Raw::None => { - let mut ent = ""; - while let Some(i) = s.chars().position(|c| { - if let Some(s) = match c { - '<' => Some("<"), - '>' => Some(">"), - '&' => Some("&"), - _ => None, - } { - ent = s; - true - } else { - false - } - }) { - self.out.write_str(&s[..i])?; - self.out.write_str(ent)?; - s = &s[i + 1..]; - } - self.out.write_str(s)?; - } - Raw::Html => { - self.out.write_str(s)?; - } - Raw::Other => {} - } - } - + Event::Str(s) => match self.raw { + Raw::None => self.write_escape(&s)?, + Raw::Html => self.out.write_str(&s)?, + Raw::Other => {} + }, Event::Atom(a) => match a { Atom::FootnoteReference(_tag, number) => { write!( @@ -441,4 +423,25 @@ impl<'s, I: Iterator>, W: std::fmt::Write> Writer<'s, I, W> { self.out.write_char('\n')?; Ok(()) } + + fn write_escape(&mut self, mut s: &str) -> std::fmt::Result { + let mut ent = ""; + while let Some(i) = s.find(|c| { + match c { + '<' => Some("<"), + '>' => Some(">"), + '&' => Some("&"), + _ => None, + } + .map_or(false, |s| { + ent = s; + true + }) + }) { + self.out.write_str(&s[..i])?; + self.out.write_str(ent)?; + s = &s[i + 1..]; + } + self.out.write_str(s) + } }