Skip to main content

rama_http/layer/html_rewrite/
mod.rs

1//! Middleware that rewrites `text/html` response bodies on the fly, using
2//! rama's streaming HTML rewriter ([`crate::protocols::html::rewrite`]).
3//!
4//! [`HtmlRewriteLayer`] wraps a service and, for each response, checks the
5//! `Content-Type`: a `text/html` body (that is not content-encoded) is piped
6//! through an [`HtmlRewriter`](crate::protocols::html::rewrite::HtmlRewriter)
7//! as it streams, applying a handler to matched elements; anything else is
8//! forwarded unchanged. Because rewriting changes the body length, the layer
9//! drops the now-stale `Content-Length`.
10//!
11//! The body adapter, [`HtmlRewriteBody`], is also usable on its own — e.g.
12//! composed with [`MapResponseBodyLayer`](crate::layer::map_response_body) —
13//! when you already handle the header concerns yourself.
14//!
15//! ## Handlers
16//!
17//! The handler is any type implementing
18//! [`ElementContentHandler`](crate::protocols::html::rewrite::ElementContentHandler).
19//! The layer requires it to be `Clone` (it is cloned per response, so each
20//! response rewrites with fresh handler state) and `Send`. A plain data
21//! struct fits naturally — no `Rc<RefCell>` / `Arc<Mutex>` / `SyncWrapper`
22//! ceremony, since the rewriter is owned and only touched through `&mut self`
23//! while the body is polled.
24//!
25//! When the handler *accumulates* state, recover it once the body finishes
26//! via [`HtmlRewriteBody::on_end`].
27//!
28//! ## Encoding
29//!
30//! The rewriter sees raw bytes, so a compressed (`Content-Encoding`) body is
31//! skipped. Place this layer *after* a decompression layer if you need to
32//! rewrite compressed responses. Charset is assumed UTF-8 (the rewriter is
33//! byte-faithful and does not decode entities).
34
35mod body;
36mod service;
37
38pub use body::HtmlRewriteBody;
39pub use service::{HtmlRewrite, HtmlRewriteLayer};
40
41#[cfg(test)]
42mod tests;