pub struct SanitizedHtml { /* private fields */ }Expand description
Article-body HTML that has been through the sanitizer in this process — and so can be emitted into a page without escaping.
Why it exists (#151). entries.content_html reached entry.html as a
raw Option<String> rendered with |safe — the one expression in the
reader that bypassed Askama’s escaper. Its safety was ingest’s ammonia
pass in feed.rs, on a different code path, holding only while every
future writer to the column remembered to go through it. That is the same
procedural guard SafeLink replaced for the entry’s hrefs.
The guarantee cannot ride through storage. The column is SQLite TEXT,
so a type set at ingest means nothing by the time a row is read back. It is
re-established at render instead: the only constructor runs the ingest
sanitizer, feed::sanitize_html, over whatever the row holds. A newtype
that wrapped the stored string without cleaning it was rejected in the
issue as a guarantee in name only.
- One policy. It calls ingest’s function rather than holding its own
ammoniabuilder, so ingest and render cannot drift; a test pins them byte for byte. - No change for readers. Sanitizer output is a fixed point of the
sanitizer, so a body ingest stored comes back byte-identical (all 545
real bodies measured). Two known exceptions, both the same page to a
browser: a literal U+00A0 in a standard.site plain-text summary comes
back as
, and a table whose<tfoot>the policy stripped gains the<tbody>a browser would build around those rows anyway. - Bounded blast radius. Not here: in
BodyRenderer, which is how the reader’s handler gets one of these from a stored row.
There is no From<String>, no Deref, and no public field. A raw string
does not become one — not by struct literal (E0451, private field):
use feather_reader::sanitized_html::SanitizedHtml;
let _ = SanitizedHtml { html: String::from("<script>alert(1)</script>") };and not by conversion (E0277, no From):
use feather_reader::sanitized_html::SanitizedHtml;
let _: SanitizedHtml = String::from("<script>alert(1)</script>").into();Only through the cleaning constructor:
use feather_reader::sanitized_html::SanitizedHtml;
let html = SanitizedHtml::clean("<p>hi</p><script>alert(1)</script>");
assert_eq!(html.as_str(), "<p>hi</p>");Implementations§
Source§impl SanitizedHtml
impl SanitizedHtml
Sourcepub fn clean(raw: &str) -> Self
pub fn clean(raw: &str) -> Self
Sanitize raw with the ingest policy. The only way to make one.
Blocks for as long as the sanitizer runs, on the whole of raw: on an
async task use SanitizedHtml::clean_off_runtime, and for a stored
body use BodyRenderer, which also applies the bounds.
Sourcepub async fn clean_off_runtime(raw: String) -> Result<Self>
pub async fn clean_off_runtime(raw: String) -> Result<Self>
SanitizedHtml::clean on tokio’s blocking pool, so a slow clean
stalls no other request sharing the async worker. This does not make
the clean cheaper or bound it; BodyRenderer does that.
Trait Implementations§
Source§impl Display for SanitizedHtml
impl Display for SanitizedHtml
impl HtmlSafe for SanitizedHtml
Auto Trait Implementations§
impl Freeze for SanitizedHtml
impl RefUnwindSafe for SanitizedHtml
impl Send for SanitizedHtml
impl Sync for SanitizedHtml
impl Unpin for SanitizedHtml
impl UnsafeUnpin for SanitizedHtml
impl UnwindSafe for SanitizedHtml
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<A, B, T> HttpServerConnExec<A, B> for Twhere
B: Body,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more