From 986d219391d2e1312cccd08ea51f4a4fb5058020 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Thu, 29 Mar 2018 18:26:31 -0400 Subject: [PATCH] Replaces rather than prepend contextPath Issue: SPR-16650 --- .../support/ServletUriComponentsBuilder.java | 54 +++++++++++++++++-- .../ServletUriComponentsBuilderTests.java | 35 +++++++----- 2 files changed, 71 insertions(+), 18 deletions(-) diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/support/ServletUriComponentsBuilder.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/support/ServletUriComponentsBuilder.java index 8ea7004d7ce..8bf1125f67f 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/support/ServletUriComponentsBuilder.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/support/ServletUriComponentsBuilder.java @@ -81,10 +81,15 @@ public class ServletUriComponentsBuilder extends UriComponentsBuilder { * *

Note: This method extracts values from "Forwarded" * and "X-Forwarded-*" headers if found. See class-level docs. + * + *

As of 4.3.15, this method replaces the contextPath with the value + * of "X-Forwarded-Prefix" rather than prepending, thus aligning with + * {@code ForwardedHeaderFiller}. */ public static ServletUriComponentsBuilder fromContextPath(HttpServletRequest request) { ServletUriComponentsBuilder builder = initFromRequest(request); - builder.replacePath(prependForwardedPrefix(request, request.getContextPath())); + String forwardedPrefix = getForwardedPrefix(request); + builder.replacePath(forwardedPrefix != null ? forwardedPrefix : request.getContextPath()); return builder; } @@ -98,6 +103,10 @@ public class ServletUriComponentsBuilder extends UriComponentsBuilder { * *

Note: This method extracts values from "Forwarded" * and "X-Forwarded-*" headers if found. See class-level docs. + * + *

As of 4.3.15, this method replaces the contextPath with the value + * of "X-Forwarded-Prefix" rather than prepending, thus aligning with + * {@code ForwardedHeaderFiller}. */ public static ServletUriComponentsBuilder fromServletMapping(HttpServletRequest request) { ServletUriComponentsBuilder builder = fromContextPath(request); @@ -113,10 +122,14 @@ public class ServletUriComponentsBuilder extends UriComponentsBuilder { * *

Note: This method extracts values from "Forwarded" * and "X-Forwarded-*" headers if found. See class-level docs. + * + *

As of 4.3.15, this method replaces the contextPath with the value + * of "X-Forwarded-Prefix" rather than prepending, thus aligning with + * {@code ForwardedHeaderFiller}. */ public static ServletUriComponentsBuilder fromRequestUri(HttpServletRequest request) { ServletUriComponentsBuilder builder = initFromRequest(request); - builder.initPath(prependForwardedPrefix(request, request.getRequestURI())); + builder.initPath(getRequestUriWithForwardedPrefix(request)); return builder; } @@ -126,10 +139,14 @@ public class ServletUriComponentsBuilder extends UriComponentsBuilder { * *

Note: This method extracts values from "Forwarded" * and "X-Forwarded-*" headers if found. See class-level docs. + * + *

As of 4.3.15, this method replaces the contextPath with the value + * of "X-Forwarded-Prefix" rather than prepending, thus aligning with + * {@code ForwardedHeaderFiller}. */ public static ServletUriComponentsBuilder fromRequest(HttpServletRequest request) { ServletUriComponentsBuilder builder = initFromRequest(request); - builder.initPath(prependForwardedPrefix(request, request.getRequestURI())); + builder.initPath(getRequestUriWithForwardedPrefix(request)); builder.query(request.getQueryString()); return builder; } @@ -153,7 +170,7 @@ public class ServletUriComponentsBuilder extends UriComponentsBuilder { return builder; } - private static String prependForwardedPrefix(HttpServletRequest request, String path) { + private static String getForwardedPrefix(HttpServletRequest request) { String prefix = null; Enumeration names = request.getHeaderNames(); while (names.hasMoreElements()) { @@ -163,7 +180,22 @@ public class ServletUriComponentsBuilder extends UriComponentsBuilder { } } if (prefix != null) { - path = prefix + path; + while (prefix.endsWith("/")) { + prefix = prefix.substring(0, prefix.length() - 1); + } + } + return prefix; + } + + private static String getRequestUriWithForwardedPrefix(HttpServletRequest request) { + String path = request.getRequestURI(); + String forwardedPrefix = getForwardedPrefix(request); + if (forwardedPrefix != null) { + String contextPath = request.getContextPath(); + if (!StringUtils.isEmpty(contextPath) && !contextPath.equals("/") && path.startsWith(contextPath)) { + path = path.substring(contextPath.length()); + } + path = forwardedPrefix + path; } return path; } @@ -177,6 +209,10 @@ public class ServletUriComponentsBuilder extends UriComponentsBuilder { * *

Note: This method extracts values from "Forwarded" * and "X-Forwarded-*" headers if found. See class-level docs. + * + *

As of 4.3.15, this method replaces the contextPath with the value + * of "X-Forwarded-Prefix" rather than prepending, thus aligning with + * {@code ForwardedHeaderFiller}. */ public static ServletUriComponentsBuilder fromCurrentContextPath() { return fromContextPath(getCurrentRequest()); @@ -199,6 +235,10 @@ public class ServletUriComponentsBuilder extends UriComponentsBuilder { * *

Note: This method extracts values from "Forwarded" * and "X-Forwarded-*" headers if found. See class-level docs. + * + *

As of 4.3.15, this method replaces the contextPath with the value + * of "X-Forwarded-Prefix" rather than prepending, thus aligning with + * {@code ForwardedHeaderFiller}. */ public static ServletUriComponentsBuilder fromCurrentRequestUri() { return fromRequestUri(getCurrentRequest()); @@ -210,6 +250,10 @@ public class ServletUriComponentsBuilder extends UriComponentsBuilder { * *

Note: This method extracts values from "Forwarded" * and "X-Forwarded-*" headers if found. See class-level docs. + * + *

As of 4.3.15, this method replaces the contextPath with the value + * of "X-Forwarded-Prefix" rather than prepending, thus aligning with + * {@code ForwardedHeaderFiller}. */ public static ServletUriComponentsBuilder fromCurrentRequest() { return fromRequest(getCurrentRequest()); diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/support/ServletUriComponentsBuilderTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/support/ServletUriComponentsBuilderTests.java index 23f45e603b8..605c03ff9c5 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/support/ServletUriComponentsBuilderTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/support/ServletUriComponentsBuilderTests.java @@ -102,22 +102,33 @@ public class ServletUriComponentsBuilderTests { assertEquals("http://localhost/mvc-showcase/data/param", result); } - @Test + @Test // SPR-16650 public void fromRequestWithForwardedPrefix() { - this.request.setRequestURI("/bar"); - this.request.addHeader("X-Forwarded-Prefix", "/foo"); + this.request.addHeader("X-Forwarded-Prefix", "/prefix"); + this.request.setContextPath("/mvc-showcase"); + this.request.setRequestURI("/mvc-showcase/bar"); UriComponents result = ServletUriComponentsBuilder.fromRequest(this.request).build(); - assertEquals("http://localhost/foo/bar", result.toUriString()); + assertEquals("http://localhost/prefix/bar", result.toUriString()); } - @Test + @Test // SPR-16650 public void fromRequestWithForwardedPrefixTrailingSlash() { - this.request.setRequestURI("/bar"); this.request.addHeader("X-Forwarded-Prefix", "/foo/"); + this.request.setContextPath("/spring-mvc-showcase"); + this.request.setRequestURI("/spring-mvc-showcase/bar"); UriComponents result = ServletUriComponentsBuilder.fromRequest(this.request).build(); assertEquals("http://localhost/foo/bar", result.toUriString()); } + @Test // SPR-16650 + public void fromRequestWithForwardedPrefixRoot() { + this.request.addHeader("X-Forwarded-Prefix", "/"); + this.request.setContextPath("/mvc-showcase"); + this.request.setRequestURI("/mvc-showcase/bar"); + UriComponents result = ServletUriComponentsBuilder.fromRequest(this.request).build(); + assertEquals("http://localhost/bar", result.toUriString()); + } + @Test public void fromContextPath() { this.request.setRequestURI("/mvc-showcase/data/param"); @@ -126,13 +137,13 @@ public class ServletUriComponentsBuilderTests { assertEquals("http://localhost/mvc-showcase", result); } - @Test + @Test // SPR-16650 public void fromContextPathWithForwardedPrefix() { this.request.addHeader("X-Forwarded-Prefix", "/prefix"); this.request.setContextPath("/mvc-showcase"); this.request.setRequestURI("/mvc-showcase/simple"); String result = ServletUriComponentsBuilder.fromContextPath(this.request).build().toUriString(); - assertEquals("http://localhost/prefix/mvc-showcase", result); + assertEquals("http://localhost/prefix", result); } @Test @@ -144,14 +155,14 @@ public class ServletUriComponentsBuilderTests { assertEquals("http://localhost/mvc-showcase/app", result); } - @Test + @Test // SPR-16650 public void fromServletMappingWithForwardedPrefix() { this.request.addHeader("X-Forwarded-Prefix", "/prefix"); this.request.setContextPath("/mvc-showcase"); this.request.setServletPath("/app"); this.request.setRequestURI("/mvc-showcase/app/simple"); String result = ServletUriComponentsBuilder.fromServletMapping(this.request).build().toUriString(); - assertEquals("http://localhost/prefix/mvc-showcase/app", result); + assertEquals("http://localhost/prefix/app", result); } @Test @@ -168,9 +179,7 @@ public class ServletUriComponentsBuilderTests { } } - // SPR-10272 - - @Test + @Test // SPR-10272 public void pathExtension() { this.request.setRequestURI("/rest/books/6.json"); ServletUriComponentsBuilder builder = ServletUriComponentsBuilder.fromRequestUri(this.request);