Skip to content

Support multi-value request headers#423

Open
fopina wants to merge 1 commit into
Danny-Dasilva:mainfrom
fopina:upstream-request-header-values-casing
Open

Support multi-value request headers#423
fopina wants to merge 1 commit into
Danny-Dasilva:mainfrom
fopina:upstream-request-header-values-casing

Conversation

@fopina

@fopina fopina commented Jun 7, 2026

Copy link
Copy Markdown

Summary

  • accept string or string-array request header values when decoding JSON options
  • preserve exact request header casing by assigning header slices directly instead of using Header.Set
  • apply the same header handling to HTTP, HTTP/3, SSE, WebSocket, and CycleTLS.Do paths
  • add local raw HTTP/1 wire integration tests that assert header casing and repeated values without relying on httpbin or net/http header parsing

Tests

  • go test -tags=integration ./tests/integration -run 'TestHTTP1RequestHeaders' -count=1 -v

Related issues

#251 #278

@fopina
fopina force-pushed the upstream-request-header-values-casing branch from fe0166e to ab8b6ad Compare June 7, 2026 05:54
Danny-Dasilva added a commit that referenced this pull request Jun 12, 2026
…vation (follow-up to #423) (#424)

* feat: support multi-value request headers and preserve header name casing

Port of PR #423 to the v3 architecture. JSON headers may now be a string or
an array of strings; arrays are sent as repeated header lines and the exact
key casing the caller provides is preserved on the wire (direct map writes
instead of http.Header.Set canonicalization).

- Options gains HeaderValues (map[string][]string, populated by a custom
  UnmarshalJSON that accepts both legacy string values and arrays), shared
  by both Go decode paths: the legacy JSON WebSocket message and the v2
  binary protocol init packet.
- All six header application sites (buildHTTPRequest, processRequest,
  dispatchHTTP3Request, dispatchSSERequest, dispatchWebSocketRequest, Do)
  use the new setRequestHeaders/hasRequestHeader helpers.
- setHeaderExact keeps the old 'options.UserAgent overrides any user-agent
  header' semantics without reintroducing canonicalization, avoiding the
  duplicate user-agent line that a plain map write would cause.
- TS: flow-control RequestOptions.headers widened to string | string[]
  (classic API HttpHeaders already allowed arrays); JSDoc documents the
  repeated-header/casing behavior.
- Tests: Go unit tests for decode/apply helpers, hermetic raw-wire HTTP/1
  capture tests, and an e2e Jest suite over a local HTTPS server verifying
  repeated headers and casing through the full TS-WS-Go path.

* chore(security): bump golang.org/x/net to v0.55.0 and fix npm audit findings

Clears the Go Vulnerability Check and NPM Security Audit CI gates (both
pre-existing on version/3.0.0, unrelated to the header feature).

- golang.org/x/net v0.43.0 -> v0.55.0 across all three modules (cycletls,
  src, root), resolving GO-2026-5026 and GO-2026-4918 (idna/http2 reachable
  via DialContext and roundTripper). govulncheck ./... now reports 0
  vulnerabilities. go directive bumped 1.24 -> 1.25.0 (drops the stale
  toolchain go1.24.4 pin) so the analyzed stdlib matches CI's Go 1.25.x and
  clears the remaining standard-library advisories.
- npm audit fix (lockfile only, no package.json/range changes): ws
  8.18.3 -> 8.21.0 (GHSA-58qx-3vcg-4xpx) and shell-quote 1.8.1 -> 1.8.4
  (GHSA-w7jw-789q-3m8p, via concurrently). npm audit now finds 0
  vulnerabilities.

No source changes. cycletls unit tests, the raw-wire header tests, and the
Jest TS->WS->Go header e2e suite all still pass.
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.

1 participant