diff --git a/Cargo.lock b/Cargo.lock index bb70124..7980ef2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1157,6 +1157,15 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" +[[package]] +name = "smallmap" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35c0f2ba34636f226215707072e602d87000095a60ad825f531827e9154d2823" +dependencies = [ + "rustc_version", +] + [[package]] name = "socket2" version = "0.3.12" @@ -1475,6 +1484,7 @@ dependencies = [ "hex-literal 0.3.1", "hyper", "khash", + "lazy_static", "libc", "log", "once_cell", @@ -1484,6 +1494,7 @@ dependencies = [ "rustc_version", "serde", "serde_cbor", + "smallmap", "tokio", "uuid", ] diff --git a/Cargo.toml b/Cargo.toml index 972c803..518f3e2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,6 +41,9 @@ pcre = "0.2.3" generational-arena = "0.2.8" khash = {version = "2.0.0", default-features=false} hex-literal = "0.3.1" +lazy_static = "1.4.0" +smallmap = "1.1" +maud = "0.22.0" [build-dependencies] rustc_version = "0.2" diff --git a/src/html/mod.rs b/src/html/mod.rs index 33b3ba2..294cbf3 100644 --- a/src/html/mod.rs +++ b/src/html/mod.rs @@ -5,8 +5,19 @@ use std::{ self, Display, }, + io, }; +pub struct HtmlTokenStream(W); + +impl HtmlTokenStream +{ + fn push(&mut self, token: T) -> io::Result<()> + { + write!(&mut self.0, "{}", display_html(&token)) //TODO: How to do async version of this? + } +} + /// Coerce a `DisplayHtml` value into an opaque implementor of `fmt::Display`. #[inline] pub fn display_html<'a, T: DisplayHtml+?Sized>(from: &'a T) -> impl fmt::Display +'a { @@ -15,7 +26,7 @@ use std::{ impl<'a,T> fmt::Display for Wrap<'a,T> where T: DisplayHtml+?Sized { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { DisplayHtml::fmt(self.0, f) } @@ -31,12 +42,53 @@ use std::{ { struct Wrap<'a, T: Display+?Sized>(&'a T); + struct FilterStream(T, F) + where F: FnMut(&mut T, char) -> fmt::Result; + + impl fmt::Write for FilterStream + where T: fmt::Write, + F: FnMut(&mut T, char) -> fmt::Result + { + fn write_str(&mut self, s: &str) -> fmt::Result + { + for c in s.chars() + { + self.1(&mut self.0, c)?; + } + Ok(()) + } + fn write_char(&mut self, c: char) -> fmt::Result + { + self.1(&mut self.0, c) + } + } + impl<'a,T> DisplayHtml for Wrap<'a,T> where T: Display +?Sized { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - //TODO: Escape HTML the string + use smallmap::Map; + lazy_static! { + static ref HTML_EQ_TABLE: Map = { + let mut map = Map::new(); + map.insert('&', "&"); + map.insert('<', "<"); + map.insert('>', ">"); + map.insert('"', """); + map + }; + } + let mut output = FilterStream(f, |output, c| { + output.write_str(match HTML_EQ_TABLE.get(&c) { + Some(s) => s, + None => { + return output.write_char(c); + }, + }) + }); + use fmt::Write; + write!(&mut output, "{}", self.0) } } diff --git a/src/main.rs b/src/main.rs index 4b3c6fb..a39c352 100644 --- a/src/main.rs +++ b/src/main.rs @@ -23,6 +23,7 @@ use futures::{ prelude::*, }; use hex_literal::hex; +use lazy_static::lazy_static; macro_rules! cfg_debug { (if {$($if:tt)*} else {$($else:tt)*}) => {