Skip to content

Fixes overlapping X-Forwarded-Prefix for chained path filters [webflux]#4239

Open
garvit-joshi wants to merge 1 commit into
spring-cloud:mainfrom
garvit-joshi:fix/gh-4236-xforwarded-prefix-overlap
Open

Fixes overlapping X-Forwarded-Prefix for chained path filters [webflux]#4239
garvit-joshi wants to merge 1 commit into
spring-cloud:mainfrom
garvit-joshi:fix/gh-4236-xforwarded-prefix-overlap

Conversation

@garvit-joshi

Copy link
Copy Markdown
Contributor

Fixes gh-4236

When a WebFlux route applies more than one path-mutating filter (e.g. StripPrefix=1 twice), every filter adds a snapshot of the request URL to GATEWAY_ORIGINAL_REQUEST_URL_ATTR, and XForwardedHeadersFilter emitted one X-Forwarded-Prefix value per suffix-matching snapshot. For a request to /tenant/api/blue stripped to /blue, the downstream request carried:

X-Forwarded-Prefix: /tenant/api,/api

Downstream forwarded-header processing concatenates comma-separated prefix values, so the downstream application reconstructs a wrong context path (/tenant/api/api instead of /tenant/api).

With this change the prefix is derived once, from the URL as received from the client (the first entry of the attribute, which is insertion-ordered) against the final routed path. A single gateway therefore contributes a single prefix value. Values appended by upstream proxies are still preserved, covered by a new test asserting /upstream,/tenant/api.

This is the WebFlux counterpart of gh-4237, fixed separately in #4238 so each module can be reviewed and backported independently.

When multiple path-mutating filters (e.g. two StripPrefix filters)
process a request, each adds a snapshot to
GATEWAY_ORIGINAL_REQUEST_URL_ATTR and XForwardedHeadersFilter emitted
one prefix per snapshot, producing overlapping values such as
"/tenant/api,/api". Downstream forwarded-header processing concatenates
the values and reconstructs a wrong context path ("/tenant/api/api").

The prefix is now derived once, from the URL as received from the
client (the first entry of the attribute) against the final routed
path, so a single gateway contributes a single prefix while values
appended by upstream proxies are preserved.

Fixes spring-cloudgh-4236

Signed-off-by: Garvit Joshi <garvitjoshi9@gmail.com>
@garvit-joshi

Copy link
Copy Markdown
Contributor Author

Additional context on why the duplicate X-Forwarded-Prefix values cause an incorrect downstream context path:

A comma in an HTTP field represents a list separator; it does not itself mean path concatenation. X-Forwarded-Prefix is a non-standard header, so its interpretation is implementation-specific.

Spring WebFlux performs the concatenation in ForwardedHeaderTransformer#getForwardedPrefix. It splits the header on commas and appends every prefix:

String[] rawPrefixes = StringUtils.tokenizeToStringArray(header, ",");
for (String rawPrefix : rawPrefixes) {
	// trailing slash handling omitted
	prefix.append(rawPrefix);
}

Source: https://github.com/spring-projects/spring-framework/blob/v7.0.3/spring-web/src/main/java/org/springframework/web/server/adapter/ForwardedHeaderTransformer.java#L165-L180

Therefore:

X-Forwarded-Prefix: /tenant/api,/api

is interpreted as:

/tenant/api + /api = /tenant/api/api

The second /api is not a prefix contributed by another proxy; it is an intermediate URL snapshot produced by the second path-mutating filter in the same gateway. This change correctly makes the gateway contribute its complete prefix once (/tenant/api), while still preserving a legitimate upstream value such as /upstream,/tenant/api.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[WebFlux] XForwardedHeadersFilter emits overlapping X-Forwarded-Prefix values for chained path filters

2 participants