Deprecate historic forwarded header behavior

See gh-37072
This commit is contained in:
rstoyanchev
2026-07-23 12:15:24 +03:00
parent 31c37d4f2c
commit 9bdeadcfbd
3 changed files with 89 additions and 20 deletions
@@ -97,7 +97,7 @@ public class ForwardedHeaderFilter extends OncePerRequestFilter {
}
private final boolean useStandardHeader;
private final @Nullable Boolean useStandardHeader;
private boolean useForwardedPrefix;
@@ -106,6 +106,22 @@ public class ForwardedHeaderFilter extends OncePerRequestFilter {
private boolean relativeRedirects;
/**
* A default constructor with the historic behavior so far, which is to check
* both the standard "Forwarded" header and the "X-Forwarded-*" alternative
* headers in that order, also with "X-Forwarded-Prefix" enabled by default.
* <p>This behavior depends on proxies being configured correctly
* to clear both standard "Forwarded" and "X-Forwarded-*" header values coming
* from the outside. Going forward, applications must explicitly declare which
* forwarded headers are expected.
* @deprecated as of 7.1, in favor of {@link #ForwardedHeaderFilter(boolean)}
*/
@Deprecated(since = "7.1", forRemoval = true)
public ForwardedHeaderFilter() {
this.useStandardHeader = null;
this.useForwardedPrefix = true;
}
/**
* Create an instance of the filter and specify whether it should use the
* standard "Forwarded" header or the "X-Forwarded-*" alternative headers.
@@ -220,6 +236,24 @@ public class ForwardedHeaderFilter extends OncePerRequestFilter {
doFilterInternal(request, response, filterChain);
}
@SuppressWarnings("removal")
private static ForwardedHeaderUtils.ForwardedInfo getForwardedInfo(
@Nullable Boolean useStandardHeader, URI uri, HttpHeaders headers,
@Nullable InetSocketAddress remoteAddress, @Nullable InetSocketAddress localAddress) {
if (useStandardHeader == null) {
return new ForwardedHeaderUtils.ForwardedInfo(
ForwardedHeaderUtils.adaptFromForwardedHeaders(uri, headers),
ForwardedHeaderUtils.parseForwardedFor(uri, headers, remoteAddress),
ForwardedHeaderUtils.parseForwardedBy(uri, headers, localAddress));
}
else {
return (useStandardHeader ?
ForwardedHeaderUtils.parseStandardHeader(uri, headers, remoteAddress, localAddress) :
ForwardedHeaderUtils.parseXForwardedHeaders(uri, headers, remoteAddress, localAddress));
}
}
/**
* Hide "Forwarded" or "X-Forwarded-*" headers.
@@ -290,19 +324,15 @@ public class ForwardedHeaderFilter extends OncePerRequestFilter {
private final ForwardedPrefixExtractor forwardedPrefixExtractor;
ForwardedHeaderExtractingRequest(
HttpServletRequest servletRequest, boolean useStandardHeader, boolean useForwardedPrefix) {
HttpServletRequest servletRequest, @Nullable Boolean useStandardHeader, boolean useForwardedPrefix) {
super(servletRequest);
ServerHttpRequest request = new ServletServerHttpRequest(servletRequest);
URI uri = request.getURI();
HttpHeaders headers = request.getHeaders();
InetSocketAddress remoteAddress = request.getRemoteAddress();
InetSocketAddress localAddress = request.getLocalAddress();
ForwardedHeaderUtils.ForwardedInfo info = (useStandardHeader ?
ForwardedHeaderUtils.parseStandardHeader(uri, headers, remoteAddress, localAddress) :
ForwardedHeaderUtils.parseXForwardedHeaders(uri, headers, remoteAddress, localAddress));
ForwardedHeaderUtils.ForwardedInfo info = getForwardedInfo(
useStandardHeader, request.getURI(), request.getHeaders(),
request.getRemoteAddress(), request.getLocalAddress());
UriComponents uriComponents = info.uriComponentsBuilder().build();
int port = uriComponents.getPort();
@@ -516,10 +546,10 @@ public class ForwardedHeaderFilter extends OncePerRequestFilter {
private final HttpServletRequest request;
private final boolean useStandardHeader;
private final @Nullable Boolean useStandardHeader;
ForwardedHeaderExtractingResponse(
HttpServletResponse response, HttpServletRequest request, boolean useStandardHeader) {
HttpServletResponse response, HttpServletRequest request, @Nullable Boolean useStandardHeader) {
super(response);
this.request = request;
@@ -555,9 +585,8 @@ public class ForwardedHeaderFilter extends OncePerRequestFilter {
URI uri = httpRequest.getURI();
HttpHeaders headers = httpRequest.getHeaders();
ForwardedHeaderUtils.ForwardedInfo info = (this.useStandardHeader ?
ForwardedHeaderUtils.parseStandardHeader(uri, headers, null, null) :
ForwardedHeaderUtils.parseXForwardedHeaders(uri, headers, null, null));
ForwardedHeaderUtils.ForwardedInfo info =
getForwardedInfo(this.useStandardHeader, uri, headers, null, null);
String result = info.uriComponentsBuilder()
.replacePath(path)
@@ -83,13 +83,29 @@ public class ForwardedHeaderTransformer implements Function<ServerHttpRequest, S
}
private final boolean useStandardHeader;
private final @Nullable Boolean useStandardHeader;
private boolean useForwardedPrefix;
private boolean removeOnly;
/**
* A default constructor with the historic behavior so far, which is to check
* both the standard "Forwarded" header and the "X-Forwarded-*" alternative
* headers in that order, also with "X-Forwarded-Prefix" enabled by default.
* <p>This behavior depends on proxies being configured correctly
* to clear both standard "Forwarded" and "X-Forwarded-*" header values coming
* from the outside. Going forward, applications must explicitly declare which
* forwarded headers are expected.
* @deprecated as of 7.1, in favor of {@link #ForwardedHeaderTransformer(boolean)}
*/
@Deprecated(since = "7.1", forRemoval = true)
public ForwardedHeaderTransformer() {
this.useStandardHeader = null;
this.useForwardedPrefix = true;
}
/**
* Create an instance of the transformer and specify whether it should use the
* standard "Forwarded" header or the "X-Forwarded-*" alternative headers.
@@ -146,9 +162,8 @@ public class ForwardedHeaderTransformer implements Function<ServerHttpRequest, S
InetSocketAddress remoteAddress = request.getRemoteAddress();
InetSocketAddress localAddress = request.getLocalAddress();
ForwardedHeaderUtils.ForwardedInfo info = (this.useStandardHeader ?
ForwardedHeaderUtils.parseStandardHeader(originalUri, headers, remoteAddress, localAddress) :
ForwardedHeaderUtils.parseXForwardedHeaders(originalUri, headers, remoteAddress, localAddress));
ForwardedHeaderUtils.ForwardedInfo info = getForwardedInfo(
this.useStandardHeader, originalUri, headers, remoteAddress, localAddress);
URI uri = info.uri();
builder.uri(uri);
@@ -186,6 +201,24 @@ public class ForwardedHeaderTransformer implements Function<ServerHttpRequest, S
return false;
}
@SuppressWarnings("removal")
private static ForwardedHeaderUtils.ForwardedInfo getForwardedInfo(
@Nullable Boolean useStandardHeader, URI uri, HttpHeaders headers,
@Nullable InetSocketAddress remoteAddress, @Nullable InetSocketAddress localAddress) {
if (useStandardHeader == null) {
return new ForwardedHeaderUtils.ForwardedInfo(
ForwardedHeaderUtils.adaptFromForwardedHeaders(uri, headers),
ForwardedHeaderUtils.parseForwardedFor(uri, headers, remoteAddress),
ForwardedHeaderUtils.parseForwardedBy(uri, headers, localAddress));
}
else {
return (useStandardHeader ?
ForwardedHeaderUtils.parseStandardHeader(uri, headers, remoteAddress, localAddress) :
ForwardedHeaderUtils.parseXForwardedHeaders(uri, headers, remoteAddress, localAddress));
}
}
private void removeForwardedHeaders(ServerHttpRequest.Builder builder) {
builder.headers(map -> FORWARDED_HEADER_NAMES.forEach(map::remove));
}
@@ -314,7 +314,10 @@ public abstract class ForwardedHeaderUtils {
* @param headers the HTTP headers to consider
* @return a {@link UriComponentsBuilder} that reflects the request URI and
* additional updates from forwarded headers
* @deprecated as of 7.1 in favor of {@link #parseStandardHeader} and
* {@link #parseXForwardedHeaders}
*/
@Deprecated(since = "7.1", forRemoval = true)
public static UriComponentsBuilder adaptFromForwardedHeaders(URI uri, HttpHeaders headers) {
UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUri(uri);
try {
@@ -373,8 +376,10 @@ public abstract class ForwardedHeaderUtils {
* @param remoteAddress the current remote address
* @return an {@code InetSocketAddress} with the extracted host and port, or
* {@code null} if the headers are not present
* @see <a href="https://tools.ietf.org/html/rfc7239#section-5.2">RFC 7239, Section 5.2</a>
* @deprecated as of 7.1 in favor of {@link #parseStandardHeader} and
* {@link #parseXForwardedHeaders}
*/
@Deprecated(since = "7.1", forRemoval = true)
public static @Nullable InetSocketAddress parseForwardedFor(
URI uri, HttpHeaders headers, @Nullable InetSocketAddress remoteAddress) {
@@ -408,8 +413,10 @@ public abstract class ForwardedHeaderUtils {
* @return an {@code InetSocketAddress} with the extracted host and port, or
* {@code null} if the headers are not present
* @since 7.0
* @see <a href="https://tools.ietf.org/html/rfc7239#section-5.1">RFC 7239, Section 5.1</a>
* @deprecated as of 7.1 in favor of {@link #parseStandardHeader} and
* {@link #parseXForwardedHeaders}
*/
@Deprecated(since = "7.1", forRemoval = true)
public static @Nullable InetSocketAddress parseForwardedBy(
URI uri, HttpHeaders headers, @Nullable InetSocketAddress localAddress) {