diff --git a/reactor-netty-http/src/main/java/reactor/netty/http/server/DefaultHttpForwardedHeaderHandler.java b/reactor-netty-http/src/main/java/reactor/netty/http/server/DefaultHttpForwardedHeaderHandler.java index b9fdb4afe..259e7a980 100644 --- a/reactor-netty-http/src/main/java/reactor/netty/http/server/DefaultHttpForwardedHeaderHandler.java +++ b/reactor-netty-http/src/main/java/reactor/netty/http/server/DefaultHttpForwardedHeaderHandler.java @@ -138,7 +138,11 @@ private static String parseForwardedPrefix(String prefixHeader) { } prefix.append((endIndex != rawPrefix.length() ? rawPrefix.substring(0, endIndex) : rawPrefix)); } - return prefix.toString(); + String parsedPrefix = prefix.toString(); + if (!parsedPrefix.isEmpty() && DEFAULT_FORWARDED_HEADER_VALIDATION && !parsedPrefix.startsWith("/")) { + throw new IllegalArgumentException("X-Forwarded-Prefix did not start with a slash (\"/\"): " + prefixHeader); + } + return parsedPrefix; } private static String[] tokenizeToStringArray(String str) { diff --git a/reactor-netty-http/src/test/java/reactor/netty/http/server/ConnectionInfoTests.java b/reactor-netty-http/src/test/java/reactor/netty/http/server/ConnectionInfoTests.java index 8de955518..0bc45f72c 100644 --- a/reactor-netty-http/src/test/java/reactor/netty/http/server/ConnectionInfoTests.java +++ b/reactor-netty-http/src/test/java/reactor/netty/http/server/ConnectionInfoTests.java @@ -315,14 +315,30 @@ void xForwardedHostPortIncludedAndXForwardedPort(boolean useCustomForwardedHandl void xForwardedPrefix(boolean useCustomForwardedHandler) { testClientRequest( clientRequestHeaders -> { - clientRequestHeaders.add("X-Forwarded-Prefix", "test-prefix"); + clientRequestHeaders.add("X-Forwarded-Prefix", "/test-prefix"); }, serverRequest -> { - Assertions.assertThat(serverRequest.forwardedPrefix()).isEqualTo("test-prefix"); + Assertions.assertThat(serverRequest.forwardedPrefix()).isEqualTo("/test-prefix"); }, useCustomForwardedHandler); } + @Test + void xForwardedPrefixWithoutForwardSlash() { + testClientRequest( + clientRequestHeaders -> { + clientRequestHeaders.add("X-Forwarded-Prefix", "forward-slash-missing"); + }, + serverRequest -> { + + }, + null, + httpClient -> httpClient, + httpServer -> httpServer.port(8080), + false, + true); + } + @ParameterizedTest @CsvSource(value = { "/first,/second | /first/second", @@ -376,7 +392,7 @@ void xForwardedMultipleHeaders(boolean useCustomForwardedHandler) { clientRequestHeaders.add("X-Forwarded-Port", "8081"); clientRequestHeaders.add("X-Forwarded-Proto", "http"); clientRequestHeaders.add("X-Forwarded-Proto", "https"); - clientRequestHeaders.add("X-Forwarded-Prefix", "test-prefix"); + clientRequestHeaders.add("X-Forwarded-Prefix", "/test-prefix"); }, serverRequest -> { Assertions.assertThat(serverRequest.hostAddress().getHostString()).isEqualTo("192.168.0.1"); @@ -384,7 +400,7 @@ void xForwardedMultipleHeaders(boolean useCustomForwardedHandler) { Assertions.assertThat(serverRequest.hostName()).isEqualTo("192.168.0.1"); Assertions.assertThat(serverRequest.hostPort()).isEqualTo(8080); Assertions.assertThat(serverRequest.scheme()).isEqualTo("http"); - Assertions.assertThat(serverRequest.forwardedPrefix()).isEqualTo("test-prefix"); + Assertions.assertThat(serverRequest.forwardedPrefix()).isEqualTo("/test-prefix"); }, useCustomForwardedHandler); }