envoyproxy / envoyproxy/envoy

http: propose exact request-target rewrite early-header-mutation extension

Open
#46,700 2 comments 0 reactions 0 assignees View on GitHub
area/early-header-mutation area/http enhancement
Dominant language
C++
Stars
28.9k
Forks
5.6k
Avg merge
1d 20h
Merged PRs (30d)
428

Description

*Title*: *http: propose exact request-target rewrite early-header-mutation extension*

*Description*:

> Add a constrained early-header-mutation extension for host-aware, exact
> request-target rewrites before Envoy’s initial route lookup.
>
> The motivating deployment need is canonicalizing an exact bare API base path,
> for example `/api` to `/api/`, while preserving the raw query string. The
> extension should be a reusable primitive rather than an API-gateway-specific
> feature: the control plane decides which paths opt in and supplies the rules.
>
> A normal HTTP filter runs too late when the canonical target must affect:
>
> - the first route lookup;
> - tracing configuration;
> - route-dependent authorization and policy filters; and
> - all downstream HTTP filters.
>
> Clearing the route cache after a late rewrite does not provide equivalent
> behavior.
>
> The existing `envoy.http.early_header_mutation.header_mutation` extension
> supports configured mutations, but it does not provide conditional exact
> request-target matching with query-preserving path-component replacement.
>
> The proposed extension would:
>
> 1. Split `:path` at the first literal `?`.
> 2. Select the most-specific configured host rule set, then look up an exact
> path rule within it.
> 3. Replace only the path component and append the original query suffix
> byte-for-byte.
> 4. Run before the initial route lookup, tracing, and HTTP filter processing.
> 5. Leave the request target unchanged when no host rule set or path rule
> matches.
>
> For a rule `/api` → `/api/`:
>
> | Incoming `:path` | Result |
> | --- | --- |
> | `/api` | `/api/` |
> | `/api?active=true` | `/api/?active=true` |
> | `/api?one=1?two=2` | `/api/?one=1?two=2` |
> | `/api/` | unchanged |
> | `/api/child` | unchanged |
> | `/api2` | unchanged |
> | `/API` | unchanged |
> | `/api;parameter` | unchanged |
>
> The extension would use byte-oriented exact lookup only:
>
> - no prefix matching or regular expressions;
> - no percent decoding or path normalization;
> - no path case conversion;
> - no query parsing, decoding, reordering, or re-encoding;
> - no request-body access or buffering.
>
> If the path component contains a literal `%`, the extension should leave the
> request target unchanged. Escaped-path semantics remain the responsibility of
> Envoy’s configured URI normalization and header validation.
>
> Host-aware selection is necessary because listeners may be shared by port. A
> path-only map is insufficient. The selected host-source header must be used as
> provided after the HCM’s configured authority normalization; the extension
> must not independently lowercase hosts, strip ports, or otherwise normalize
> it.
>
> Host matching should follow Envoy virtual-host domain semantics:
>
> 1. Exact domain names, such as `api.example.com`.
> 2. Longest suffix wildcard, such as `*.example.com`.
> 3. Longest prefix wildcard, such as `example.*`.
> 4. The optional catch-all domain `*`.
>
> After selecting the most-specific host rule set, look up the exact path only
> in that rule set. If the path does not have a matching rule, leave the request
> target unchanged; do not fall through to a less-specific host rule set. This
> means an empty `rules` list is a host-level no-rewrite rule.
>
> The configuration should reject duplicate domains and more than one `*`
> domain. It should also reject invalid or ambiguous wildcard patterns.
>
> A tentative configuration direction:
>
> ```proto
> message ExactPathRewrite {
> // Header used to select host-specific rules, such as ":authority".
> string host_header = 1;
>
> repeated HostRules hosts = 2;
> }
>
> message HostRules {
> // Exact domains and Envoy-style wildcards, such as "*.example.com",
> // "example.*", and "*".
> repeated string domains = 1;
>
> repeated Rule rules = 2;
> }
>
> message Rule {
> string exact_path = 1;
> string replacement_path = 2;
> }
> ```
>
> For example, `admin.example.com` selects its own empty rule set instead of
> falling through to the `*.example.com` rule set:
>
> ```text
> Host: api.example.com, path: /api?active=true
> Selected domains: *.example.com
> Result: /api/?active=true
>
> Host: admin.example.com, path: /api
> Selected domains: admin.example.com
> Selected rules: []
> Result: unchanged
>
> Host: other.example.net, path: /api
> Selected domains: none
> Result: unchanged
> ```
>
> Configuration for this example:
>
> ```yaml
> early_header_mutation_extensions:
> - name: envoy.http.early_header_mutation.exact_path_rewrite
> typed_config:
> "@type": type.googleapis.com/envoy.extensions.http.early_header_mutation.exact_path_rewrite.v3.ExactPathRewrite
> host_header: ":authority"
> hosts:
> - domains:
> - "*.example.com"
> rules:
> - exact_path: /api
> replacement_path: /api/
> - domains:
> - admin.example.com
> rules: []
> ```
>
> The exact `admin.example.com` entry wins over `*.example.com`; its empty
> rules list leaves the path unchanged. An unlisted host, or a path with no
> matching rule in the selected host rule set, also remains unchanged.
>
> The extension should parse and validate the lookup tables at configuration-load
> time, use immutable exact hash-map lookups at runtime, and avoid allocations
> when no rewrite is selected where practical. It should preserve configured
> early-header-mutation ordering and allow subsequent extensions to run.
>
> The expected behavior for internally recreated or internally redirected
> streams also needs an explicit decision and integration coverage. For parity
> with a filter that can run again on a recreated filter chain, the extension may
> need to run before each initial route lookup for such a stream.
>
> Feedback is requested on:
>
> 1. Whether this is sufficiently general and useful to warrant a core
> extension, versus extending the existing early header mutation capability.
> 2. Whether host-aware selection belongs in the initial API, and the preferred
> behavior for missing host headers.
> 3. The intended behavior for internally recreated or redirected streams.
> 4. Maintainer sponsorship and interest from other users of this capability.

Contributor guide

Open the contributing guide

Research direction

Start by reviewing the existing envoy.http.early_header_mutation.header_mutation extension and the initial route-lookup path described in the issue. Clarify host selection, missing-host behavior, and recreated-stream handling with maintainers, then define integration coverage for the listed rewrite and no-rewrite cases. Done requires an agreed design and maintainer sponsorship before implementation.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
backend-api-design, networking
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
28/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.