For the complete documentation index, see llms.txt. Markdown versions of all docs pages are available by appending .md to any docs URL.
Preserve request paths
Disable Envoy’s default path normalization and slash merging so that backends that depend on the original request path, such as S3-compatible object stores, receive it unmodified.
About path normalization and slash merging
By default, Envoy applies two transformations to a request path before it forwards the request to the backend.
- Path normalization: Envoy resolves the path per RFC 3986, for example by collapsing
.and..segments and decoding percent-encoded characters. - Slash merging: Envoy collapses sequences of adjacent
/characters into a single/.
These defaults match Envoy’s historical behavior and help guard against common path-based bypass techniques. However, some backends depend on the original, unmodified path. For example, S3-compatible object stores can use object keys that contain repeated slashes, such as my-bucket//nested//key. If Envoy merges these slashes before routing, the request no longer matches the intended object key.
Use a ListenerPolicy to disable path normalization, slash merging, or both, for the listeners on a Gateway.
Before you begin
-
Follow the Get started guide to install kgateway.
-
Follow the Sample app guide to create a gateway proxy with an HTTP listener and deploy the httpbin sample app.
-
Get the external address of the gateway and save it in an environment variable.
export INGRESS_GW_ADDRESS=$(kubectl get svc -n kgateway-system http -o jsonpath="{.status.loadBalancer.ingress[0]['hostname','ip']}") echo $INGRESS_GW_ADDRESS
Disable path normalization and slash merging
-
Create a ListenerPolicy that sets
normalizePathandmergeSlashestofalse. IntargetRefs, attach the policy to the Gateway. The policy applies to all HTTP and HTTPS listeners on that Gateway.Review the following table to understand this configuration.kubectl apply -f- <<EOF apiVersion: gateway.kgateway.dev/v1alpha1 kind: ListenerPolicy metadata: name: preserve-path-handling namespace: kgateway-system spec: targetRefs: - group: gateway.networking.k8s.io kind: Gateway name: http default: httpSettings: normalizePath: false mergeSlashes: false EOFSetting Description spec.default.httpSettings.normalizePathSet to falseto keep Envoy from normalizing paths before routing, such as collapsing.and..segments or decoding percent-encoded characters. Defaults totrue.spec.default.httpSettings.mergeSlashesSet to falseto keep Envoy from merging adjacent/characters in request paths. Defaults totrue. -
Port-forward the gateway proxy on port 19000 to open the Envoy admin interface, and verify that the HTTP connection manager config for the gateway listener no longer normalizes paths or merges slashes.
kubectl port-forward deploy/http -n kgateway-system 19000 & PF_PID=$! sleep 2 curl -s localhost:19000/config_dump | jq ' .configs[] | select(.["@type"] == "type.googleapis.com/envoy.admin.v3.ListenersConfigDump") | .dynamic_listeners[] | .active_state.listener.filter_chains[].filters[] | select(.name == "envoy.filters.network.http_connection_manager") | .typed_config | {normalize_path, merge_slashes} ' kill $PF_PIDExample output:
{ "normalize_path": false, "merge_slashes": null }Note
merge_slashesshows asnullrather thanfalse. Envoy omits this field from the config dump entirely when it is set to its default value offalse, so the{normalize_path, merge_slashes}object construction in the command above fills innullfor the missing key. Anullvalue confirms that slash merging is disabled.normalize_pathalways appears explicitly, including when it isfalse, because Envoy represents it as a wrapper type rather than a plain boolean..dynamic_listenerscontains only the Gateway-managed listener, so you don’t need to filter by name or port. Use.active_state, not.draining_state, to see the current configuration instead of a previous version of the listener that Envoy is still closing out connections for after an update. -
Send a request with a repeated slash in the path.
curl -i http://$INGRESS_GW_ADDRESS:8080/anything/foo//bar -H "host: www.example.com:8080"Example output:
HTTP/1.1 301 Moved Permanently content-type: text/html; charset=utf-8 location: /anything/foo/bar <a href="/anything/foo/bar">Moved Permanently</a>.Note
The 301 response comes from httpbin’s underlying Werkzeug framework, which has its own, independent path normalization. Httpbin redirects any request with a repeated slash to the canonical single-slash path. This behavior only triggers if httpbin receives the raw, unmerged path with repeated slashes. If Envoy had merged the slashes before proxying the request, httpbin would receive the already-canonical path and return a normal 200 response with no redirect.
Cleanup
You can remove the resources that you created in this guide.kubectl delete listenerpolicy preserve-path-handling -n kgateway-system --ignore-not-found