envoyproxy / envoyproxy/gateway

ClientTrafficPolicy: support HTTP/1 header key format `proper_case_words` (not only preserve)

Open
#9,571 2 comments 1 reaction 0 assignees View on GitHub
stale triage
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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.