needsrewrite

command
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 28, 2026 License: BSD-3-Clause Imports: 5 Imported by: 0

Documentation

Overview

Command needsrewrite decides whether a document is worth rewriting before rewriting it, which is the question a proxy asks thousands of times a second and mostly answers "no".

The cheap answer is a byte search: if the body cannot contain anything the handlers match, skip the rewrite. Two things make that harder than it sounds - one about cost and one about correctness - and both are measurable.

Cost first, and getting it cheap took three attempts, each of which I expected to be the answer. HTML tag names are case-insensitive, so the search has to be, and the usual way to write that lower-cases the body. On a 93 KB page with nothing in it to match, fastest of twenty:

                                             time   allocates
one bytes.Contains, case-sensitive (wrong)    26µs           0
ToLower then Contains, once per probe        157µs      98,304
fold the comparison, byte at a time          318µs           0
fold, skipping with bytes.IndexByte          150µs           0
fold, one pass, table on the byte after "<"   52µs           0
the rewrite this is avoiding                 175µs           -

The three surprises, in order. A hand-written fold loop is worse than lower-casing the whole document, because ToLower and Contains have vectorised implementations behind them and a byte-at-a-time loop does not. Skipping with IndexByte helps less than it looks like it should, because in HTML the "<" is exactly as dense as the tags are - that page has 6,000 of them, one every fifteen bytes - so there is little to skip and the work at each candidate is what counts. And searching once per probe is a full pass per probe on a miss, so three probes cost three scans while the rewrite is paid once.

What works is one pass with a 256-entry table on the byte after the bracket, which rejects almost every candidate with a lookup: 52µs against a 175µs rewrite, and nothing allocated. A gate that costs a third of what it saves is worth having; the first three attempts were not.

Correctness second, and it is one rule: the probe has to match a superset of what the handlers match, or the gate skips a document it should have rewritten - silently, since the whole point is that nothing runs. Being too broad only costs a wasted rewrite.

The rule bites in a way worth naming. A selector for images has to be `img,image`, because `<image>` is a spelling of `<img>` that the parser renames and this library reports as spelled (B155). A probe of "<img" is therefore not a superset of that selector, and a page whose only image is spelled `<image src=x>` would be skipped. The probe is "<im".

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL