Skip to content

Fast vhost#77

Draft
sheplu wants to merge 4 commits into
masterfrom
fast-vhost
Draft

Fast vhost#77
sheplu wants to merge 4 commits into
masterfrom
fast-vhost

Conversation

@sheplu

@sheplu sheplu commented Jun 13, 2026

Copy link
Copy Markdown
Member

No description provided.

sheplu added 4 commits June 13, 2026 09:32
Rewrite index.js as src/index.ts compiled with tsc to ESM in dist/, with
bundled type declarations. Matching logic is byte-for-byte faithful to v3.

Performance, while staying behaviour-identical:
  - Static (non-wildcard) hostnames take an ASCII-gated fast path: a length
    check + lowercase equality decide most requests without the regex, and
    req.vhost is written directly with length 0. A toLowerCase shortcut was
    rejected because RegExp i-folding differs from String#toLowerCase for code
    points like U+212A (Kelvin) and 'İ' length-changing folds; the fast path is
    gated on an ASCII pattern and defers to the regex otherwise.
  - Wildcard string hostnames gain an always-safe minimum-length reject before
    the regex (a match needs at least hostname.length chars). The regex still
    does the matching and capture extraction.
  - RegExp hostnames are unchanged.

Warm: static match ~1.37x, static no-match ~1.9x, wildcard short no-match
~2.2x vs v3; wildcard match / multi-star / RegExp stay ~1.0x.

Tooling: node:test + c8 + typescript-eslint flat config; the legacy
multi-version CI matrix is replaced with a Node 24 build-and-test job.

BREAKING CHANGE: package is now ESM-only (import, not require) and requires
Node.js 24+.
Replace the mocha suite with the built-in node:test runner (ESM) and grow it
from 19 to 56 cases to lock the behavioural contract. New cases cover:
multiple vhosts in series, null-prototype req.vhost, explicit length-0
static/RegExp shapes, case-insensitivity, regexp-metachar escaping, IPv6
with/without port, trailing-dot literals, and the optimization guards —
the Unicode case-fold (U+212A must not match /k/i), the 'İ' length-changing
fold, wildcard prefix/suffix capture + case-insensitivity, wrong-prefix and
wrong-suffix 404s, non-ASCII host via the regex path, and Kelvin in a wildcard
suffix. The module is imported via a stable package self-reference so the same
suite runs unchanged against the compiled build. 100% function coverage via c8.
Switch README examples from require() to import, note the ESM-only / Node 24+
requirement and bundled types, and document the exported VHost type. Add the
4.0.0 HISTORY entry.
Pin the original v3 implementation at bench/v3-baseline.cjs so old-vs-new stays
reproducible. Add:
  - bench/index.mjs        quick single-process snapshot (tinybench)
  - bench/session.mjs      one fresh-process session, fixed-iteration hrtime
  - bench/run-matrix.mjs   N sessions × several lengths, mean/min/max/sd
  - bench/collect.mjs      persists raw + summary per run to bench/results/
  - bench/{,run-}*experiments.mjs   variant studies, each fuzz-checked for
    identical captures against the regex (incl. the rejected wildcard string
    matcher and the object-allocation lesson)

Store a 25-session × {10k,100k,1M} run and document method + results in
BENCHMARKS.md (medians reported alongside means since OS-scheduler spikes
inflate the mean at 1M).
Comment thread bench/index.mjs
}

// Middlewares under test.
const staticMw = vhost('mail.example.com', handle)
Comment thread test/test.mjs
})

it('should capture a wildcard with both a prefix and a suffix', function (_, done) {
var app = createServer('user-*.example.com', function (req, res) {
Comment thread test/test.mjs
})

it('should 404 a single-wildcard host with the wrong prefix', function (_, done) {
var app = createServer('user-*.example.com', function (req, res) {
Comment thread test/test.mjs
})

it('should preserve wildcard case-insensitivity on prefix and suffix', function (_, done) {
var app = createServer('user-*.example.com', function (req, res) {
Comment thread test/test.mjs
})

it('should treat dot as a dot', function (_, done) {
var app = createServer('a.b.com', function (req, res) {
Comment thread test/test.mjs
})

it('should match case-insensitively', function (_, done) {
var app = createServer('mail.example.com', function (req, res) {
Comment thread test/test.mjs
})

it('should match a mixed-case static host (fast-path regex fallback)', function (_, done) {
var app = createServer('mail.example.com', function (req, res) {
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants