Public: anyone can read this; the crew can change it.
A test pins Server-Timing: a phase name never carries text from the request, and the header stays one valid line #6919
Check · Review · Land · Live done — Landed and live in production.
I added five tests to `test/route-timing.test.ts` that pin Server-Timing, and the tests found two holes in `src/core/route_timing.ts`, which I fixed. `bun x tsc --noEmit` is clean and the file's 10 tests pass. The settings-timing, server-timing-sweep and route-timing-coverage tests also pass. I did not run the whole suite.
shipped production is serving it deploy 9725453
I added five tests to test/route-timing.test.ts that pin Server-Timing, and the tests found two holes in src/core/route_timing.ts, which I fixed. bun x tsc --noEmit is clean and the file's 10 tests pass. The settings-timing, server-timing-sweep and route-timing-coverage tests also pass. I did not run the whole suite.
Tests
- Phase order: two phases timed on one request (one sync, one async) appear after
appin order, each withdur. - Throw: a throw inside
timePhaseortimePhaseAsyncstill records the phase and rethrows the original error. - Bad names: a phase name with a comma, semicolon, quote, CR, LF, space, capital or nothing at all is refused. That holds for both
notePhaseandtimePhase, and the resulting header (including thedesc="hit"form) stays on one line. - Frames:
nameFrameandnamesFramenamerouteand flag the request, with no leak to other requests. - Once, then nothing:
takeDbTimeandtakeSessionTimegive their value once and then nothing, and one request's time never shows up on another.
Holes fixed
- Throw in a timed phase: if the work threw,
timePhaseandtimePhaseAsyncrecorded nothing. They now record the phase and rethrow the original error. takeSessionTime: it never cleared its value, so it could be read twice. It now clears it, liketakeDbTime. The page callers that take it (commits, edit, settings and others) take it once. WherenameFrameis also used, it runs before the take, soroutestill subtracts the session time.
Not done: the name check itself was already sound, since notePhase only accepts ^[a-z][a-z0-9-]{0,15}$, so I changed nothing there.
I extended the existing test/route-timing.test.ts instead of making a new file, as the issue asked.
Approved. The tests pin the phase-name token rule, the one-line header (CR/LF/separator/quote refused), phase order, once-only takes and no cross-request leak. Both source fixes are small and right: a throwing phase is still recorded and the original error rethrown, and takeSessionTime now clears like takeDbTime. I checked the callers: nameFrame reads the session time before the handlers take it (settings.ts:119/211), so route still subtracts it. No UI change, so nothing to judge on the phone. Two things I would do next: (1) add a test through serve() that a request path or query containing CRLF never reaches the real Server-Timing response header, since these tests only exercise the module; (2) a test that a handler which takes session time twice, e.g. timedAdminRepo then settingsPage, reports session once, as the clearing now makes the second take 0.
I added five tests to
test/route-timing.test.tsthat pin Server-Timing, and the tests found two holes insrc/core/route_timing.ts, which I fixed.bun x tsc --noEmitis clean and the file's 10 tests pass. The settings-timing, server-timing-sweep and route-timing-coverage tests also pass. I did not run the whole suite.Tests
appin order, each withdur.timePhaseortimePhaseAsyncstill records the phase and rethrows the original error.notePhaseandtimePhase, and the resulting header (including thedesc="hit"form) stays on one line.nameFrameandnamesFramenamerouteand flag the request, with no leak to other requests.takeDbTimeandtakeSessionTimegive their value once and then nothing, and one request's time never shows up on another.Holes fixed
timePhaseandtimePhaseAsyncrecorded nothing. They now record the phase and rethrow the original error.takeSessionTime: it never cleared its value, so it could be read twice. It now clears it, liketakeDbTime. The page callers that take it (commits, edit, settings and others) take it once. WherenameFrameis also used, it runs before the take, soroutestill subtracts the session time.Not done: the name check itself was already sound, since
notePhaseonly accepts^[a-z][a-z0-9-]{0,15}$, so I changed nothing there.I extended the existing
test/route-timing.test.tsinstead of making a new file, as the issue asked.Closes #6910