diff --git a/spring-web/src/main/java/org/springframework/web/server/adapter/ForwardedHeaderTransformer.java b/spring-web/src/main/java/org/springframework/web/server/adapter/ForwardedHeaderTransformer.java index af8ef160c2c7..1614671fb9f7 100644 --- a/spring-web/src/main/java/org/springframework/web/server/adapter/ForwardedHeaderTransformer.java +++ b/spring-web/src/main/java/org/springframework/web/server/adapter/ForwardedHeaderTransformer.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -53,6 +53,7 @@ * in which case it removes but does not use the headers. * * @author Rossen Stoyanchev + * @author Sebastien Deleuze * @since 5.1 * @see https://tools.ietf.org/html/rfc7239 * @see Forwarded Headers @@ -165,7 +166,7 @@ private static String getForwardedPrefix(ServerHttpRequest request) { String[] rawPrefixes = StringUtils.tokenizeToStringArray(header, ","); for (String rawPrefix : rawPrefixes) { int endIndex = rawPrefix.length(); - while (endIndex > 1 && rawPrefix.charAt(endIndex - 1) == '/') { + while (endIndex > 0 && rawPrefix.charAt(endIndex - 1) == '/') { endIndex--; } prefix.append((endIndex != rawPrefix.length() ? rawPrefix.substring(0, endIndex) : rawPrefix)); diff --git a/spring-web/src/test/java/org/springframework/web/filter/ForwardedHeaderFilterTests.java b/spring-web/src/test/java/org/springframework/web/filter/ForwardedHeaderFilterTests.java index 32ad293236e7..576d89153309 100644 --- a/spring-web/src/test/java/org/springframework/web/filter/ForwardedHeaderFilterTests.java +++ b/spring-web/src/test/java/org/springframework/web/filter/ForwardedHeaderFilterTests.java @@ -48,6 +48,7 @@ * @author EddĂș MelĂ©ndez * @author Rob Winch * @author Brian Clozel + * @author Sebastien Deleuze */ class ForwardedHeaderFilterTests { @@ -442,6 +443,15 @@ void shouldConcatenatePrefixesWithTrailingSlashes() throws Exception { assertThat(actual.getRequestURL().toString()).isEqualTo("http://localhost/first/second/mvc-showcase"); } + @Test + void shouldRemoveSingleTrailingSlash() throws Exception { + request.addHeader(X_FORWARDED_PREFIX, "/prefix,/"); + request.setRequestURI("/mvc-showcase"); + + HttpServletRequest actual = filterAndGetWrappedRequest(); + assertThat(actual.getRequestURL().toString()).isEqualTo("http://localhost/prefix/mvc-showcase"); + } + @Test void requestURLNewStringBuffer() throws Exception { request.addHeader(X_FORWARDED_PREFIX, "/prefix/"); diff --git a/spring-web/src/test/java/org/springframework/web/server/adapter/ForwardedHeaderTransformerTests.java b/spring-web/src/test/java/org/springframework/web/server/adapter/ForwardedHeaderTransformerTests.java index 564eab48b2c6..c1244707a741 100644 --- a/spring-web/src/test/java/org/springframework/web/server/adapter/ForwardedHeaderTransformerTests.java +++ b/spring-web/src/test/java/org/springframework/web/server/adapter/ForwardedHeaderTransformerTests.java @@ -32,6 +32,7 @@ * Tests for {@link ForwardedHeaderTransformer}. * * @author Rossen Stoyanchev + * @author Sebastien Deleuze */ class ForwardedHeaderTransformerTests { @@ -170,6 +171,17 @@ void shouldConcatenatePrefixesWithTrailingSlashes() { assertForwardedHeadersRemoved(request); } + @Test // gh-33465 + void shouldRemoveSingleTrailingSlash() { + HttpHeaders headers = new HttpHeaders(); + headers.add("X-Forwarded-Prefix", "/prefix,/"); + ServerHttpRequest request = this.requestMutator.apply(getRequest(headers)); + + assertThat(request.getURI()).isEqualTo(URI.create("https://example.com/prefix/path")); + assertThat(request.getPath().value()).isEqualTo("/prefix/path"); + assertForwardedHeadersRemoved(request); + } + @Test void forwardedForNotPresent() { HttpHeaders headers = new HttpHeaders();