springspring-webflux

What is the correct value for x forward prefix header?


I have got a request with header from my proxy: X-Forwarded-Prefix: http://some-site?param=value

ForwardedHeaderTransformer concatenate header value with initial url which is incorrect and request breaks.

So, my question is - is it correct to send url params in x-forwarded-prefix header?


Solution

  • If you look at the Spring WebFlux source code for ForwardedHeaderTransformer, you'll see how the X-Forwarded-Prefix header is handled:

    URI originalUri = request.getURI();
    HttpHeaders headers = request.getHeaders();
    URI uri = adaptFromForwardedHeaders(originalUri, headers);
    builder.uri(uri);
    String prefix = getForwardedPrefix(request);
    if (prefix != null) {
        builder.path(prefix + uri.getRawPath());
        builder.contextPath(prefix);
    }
    

    This shows that the value of X-Forwarded-Prefix is interpreted as a plain path prefix. It is directly prepended to the URI path and applied as the request's context path.

    There is no URL parsing, and query strings are not expected here.

    Let's say a client requests:

    GET /api/users
    

    The reverse proxy strips the path prefix /api before forwarding the request to the backend, so the backend sees:

    GET /users
    

    To preserve the original client-visible prefix, the proxy adds:

    X-Forwarded-Prefix: /api
    

    Spring then reconstructs the full path via:

    builder.path(prefix + uri.getRawPath());
    

    Which becomes:

    "/api" + "/users" -> "/api/users"
    

    So if a header like this is used:

    X-Forwarded-Prefix: http://some-site?foo=bar
    

    Then Spring tries to build:

    "http://some-site?foo=bar" + "/users" -> "http://some-site?foo=bar/users"
    

    This results in a malformed URI and breaks request processing - as you've observed.

    So, the X-Forwarded-Prefix header is intended to carry a clean path prefix (e.g. /api/v1). Including a full URL or query string in this header isn't supported by Spring's processing logic and can lead to invalid URI construction.

    Side note: If you want to disable this behavior entirely, you can do it via configuration - no need to redefine the bean manually:

    spring.web.forwarded.enabled: false
    

    This disables automatic registration of ForwardedHeaderTransformer, so X-Forwarded-* headers will be ignored.

    Alternatively, you can register the bean manually with .setRemoveOnly(true) if you only want the headers to be stripped but not applied:

    @Bean
    public ForwardedHeaderTransformer forwardedHeaderTransformer() {
        ForwardedHeaderTransformer transformer = 
              new ForwardedHeaderTransformer();
        transformer.setRemoveOnly(true);
        return transformer;
    }