envoyproxy / envoyproxy/gateway
ClientTrafficPolicy: support HTTP/1 header key format `proper_case_words` (not only preserve)
- Dominant language
- Go
- Stars
- 3k
- Forks
- 864
- Avg merge
- 2d 2h
- Merged PRs (30d)
- 140
Description
## Description
`ClientTrafficPolicy.spec.http1` today exposes `preserveHeaderCase`, which maps to Envoy’s **preserve_case** formatter with an empty `PreserveCaseFormatterConfig` ([PR #2506](https://github.com/envoyproxy/gateway/pull/2506), issue #2501).
That is not enough for a common case:
- Filters or the control plane **add** response headers (Lua `respond()`, router, local replies, etc.).
- Envoy stores those header **names** as lowercase.
- With default preserve-case settings, **Envoy-added** headers stay lowercase on the wire (`formatter_type_on_envoy_headers` default is lower case — see [PreserveCaseFormatterConfig](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/http/header_formatters/preserve_case/v3/preserve_case.proto)).
- Some HTTP/1 clients match header names with **case-sensitive** comparison (e.g. they look up `"Location"` and miss `"location"`).
Envoy already supports forcing Title-Case on encode via:
```yaml
# Http1ProtocolOptions
header_key_format:
proper_case_words: {}
```
Docs: [HTTP/1.1 Header Casing](https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_conn_man/header_casing), [Http1ProtocolOptions.HeaderKeyFormat](https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/protocol.proto#config-core-v3-http1protocoloptions-headerkeyformat).
Envoy Gateway does not surface this (or `preserve_case` + `formatter_type_on_envoy_headers: PROPER_CASE`) on any CRD. Operators must use raw xDS patches (e.g. EnvoyPatchPolicy) on the HCM `http_protocol_options`.
Related closed discussion of lowercase response headers: #7450.
## Proposal
Extend `ClientTrafficPolicy` HTTP/1 settings so users can choose how HTTP/1 header **names** are formatted when serializing to the client, without raw patches.
Sketch (names flexible):
```yaml
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: ClientTrafficPolicy
metadata:
name: http1-header-format
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: eg
http1:
# existing
preserveHeaderCase: false
# new — one of:
headerKeyFormat: ProperCaseWords
# or more explicit:
# headerKeyFormat:
# type: ProperCaseWords
# # type: PreserveCase
# # type: Default # lowercase
```
Translation:
| API | Envoy |
|-----|--------|
| default / omit | current behavior (lowercase) |
| `PreserveCase` / `preserveHeaderCase: true` | existing preserve_case formatter (keep as today) |
| `ProperCaseWords` | `header_key_format.proper_case_words: {}` |
Optional later: expose preserve_case `formatter_type_on_envoy_headers` (`DEFAULT` vs `PROPER_CASE`) if you prefer extending preserve rather than a separate ProperCaseWords mode.
## Why not only `preserveHeaderCase`?
Preserve keeps original casing for headers that still carry case through the stack. Headers **created inside Envoy** (including many filter-generated responses) are lowercased at creation time; empty preserve config does **not** Title-Case them. `proper_case_words` rewrites keys at serialization and covers that path.
## Acceptance criteria
- [ ] Documented `ClientTrafficPolicy` field (or equivalent) that enables Envoy `proper_case_words` on the listener HCM HTTP/1 codec.
- [ ] e2e: with the field set, a response header added by Envoy/filter as `location` is observed by an HTTP/1.1 client as `Location` (and similarly for other multi-word names if tested).
- [ ] Default remains current lowercase behavior (no surprise for existing users).
- [ ] Docs note interaction with `preserveHeaderCase` (mutually exclusive or documented precedence).
## Workaround today
EnvoyPatchPolicy (or other raw xDS patch) on the HTTP connection manager, e.g. set `http_protocol_options.header_key_format.proper_case_words: {}` for the affected Gateway listener.
## Version
Observed on Envoy Gateway **v1.7.x** (field still absent on latest docs for `HTTP1Settings`: only `preserveHeaderCase`, trailers, HTTP/1.0, etc.).
Contributor guide
No contributing guide indexed for this repository
Research direction
Start at the ClientTrafficPolicy HTTP/1 settings and the existing preserveHeaderCase translation into the listener HCM, then trace the related API and documentation entry points. Add coverage for an Envoy- or filter-added response header and verify the default, ProperCaseWords behavior, and its interaction with preserveHeaderCase against the acceptance criteria.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go, kubernetes
- Domain
- api, networking
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 58/100