Skip to content

perf: fuse uncommon header name conversion - #2795

Merged
dunglas merged 3 commits into
php:mainfrom
andreybolonin:perf/fuse-header-name-conversion
Nov 1, 2026
Merged

dunglas merged 3 commits into
php:mainfrom
andreybolonin:perf/fuse-header-name-conversion

Conversation

@andreybolonin

@andreybolonin andreybolonin commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

Each uncommon-header cache miss currently builds intermediate strings for uppercase conversion, dash replacement, and the PHP variable prefix and terminator.

Build validated ASCII names in one pass and one allocation with strings.Builder. Go rejects invalid header names before dispatching HTTP/1 and HTTP/2 requests, so no preliminary ASCII scan or Unicode conversion is needed. Keep the cache and its capacity unchanged.

Extend the raw HTTP connection test to verify that names containing spaces, Unicode, invalid UTF-8, or NUL receive HTTP 400 before reaching the handler. Compare conversion against the original expression for valid header names, including all token punctuation, and add a differential fuzz test and a direct conversion benchmark.

Performance reference from the earlier standalone prototype (Go 1.27.3, darwin/arm64, median of five 200ms samples). These measurements include a preliminary ASCII scan that the current revision removes; the current revision has not been benchmarked:

Header Before After Time reduction Go B/op allocs/op
X-Custom-Trace-Id 106.5 ns 42.68 ns 59.9% 96 → 24 4 → 1
X-CUSTOM-TRACE-ID 69.35 ns 43.93 ns 36.7% 72 → 24 3 → 1
x-custom-trace-id 101.7 ns 42.71 ns 58.0% 96 → 24 4 → 1

These results measure conversion on a cache miss, not cache hits, total request time, or process RSS. Benchmarks were not rerun for this PR.

Validation:

  • go test -race ./internal/phpheaders passed.
  • go test ./internal/phpheaders -run '^$' -fuzz '^FuzzHeaderName$' -fuzztime=5s passed 375,900 executions.
  • go vet ./internal/phpheaders, gofmt, and git diff --check passed.

Validation in Go's server implementation:

  • HTTP/1: net/http/server.go rejects names failing httpguts.ValidHeaderFieldName.
  • HTTP/2: the frame decoder rejects names failing validWireHeaderFieldName, which checks token characters and lowercase ASCII.

Comment thread internal/phpheaders/phpheaders.go Resolved
@dunglas
dunglas merged commit 3ef155a into php:main Nov 1, 2026
28 checks passed
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