From f68fdd4454309657fe63006f27e51f67bec2414b Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Fri, 19 Jan 2018 19:13:06 +0100 Subject: [PATCH] Proper null path checks in HierarchicalUriComponents Issue: SPR-16364 --- .../web/util/HierarchicalUriComponents.java | 16 +- .../web/util/UriComponentsBuilderTests.java | 165 ++++++++++-------- 2 files changed, 106 insertions(+), 75 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/web/util/HierarchicalUriComponents.java b/spring-web/src/main/java/org/springframework/web/util/HierarchicalUriComponents.java index ce07354272..a652d9384a 100644 --- a/spring-web/src/main/java/org/springframework/web/util/HierarchicalUriComponents.java +++ b/spring-web/src/main/java/org/springframework/web/util/HierarchicalUriComponents.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 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. @@ -86,10 +86,11 @@ final class HierarchicalUriComponents extends UriComponents { this.userInfo = userInfo; this.host = host; this.port = port; - this.path = path != null ? path : NULL_PATH_COMPONENT; + this.path = (path != null ? path : NULL_PATH_COMPONENT); this.queryParams = CollectionUtils.unmodifiableMultiValueMap( queryParams != null ? queryParams : new LinkedMultiValueMap(0)); this.encoded = encoded; + if (verify) { verify(); } @@ -668,7 +669,10 @@ final class HierarchicalUriComponents extends UriComponents { @Override public List getPathSegments() { - String[] segments = StringUtils.tokenizeToStringArray(this.path, PATH_DELIMITER_STRING); + String[] segments = StringUtils.tokenizeToStringArray(getPath(), PATH_DELIMITER_STRING); + if (segments == null) { + return Collections.emptyList(); + } return Collections.unmodifiableList(Arrays.asList(segments)); } @@ -680,7 +684,7 @@ final class HierarchicalUriComponents extends UriComponents { @Override public void verify() { - verifyUriComponent(this.path, Type.PATH); + verifyUriComponent(getPath(), Type.PATH); } @Override @@ -697,12 +701,12 @@ final class HierarchicalUriComponents extends UriComponents { @Override public boolean equals(Object obj) { return (this == obj || (obj instanceof FullPathComponent && - getPath().equals(((FullPathComponent) obj).getPath()))); + ObjectUtils.nullSafeEquals(getPath(), ((FullPathComponent) obj).getPath()))); } @Override public int hashCode() { - return getPath().hashCode(); + return ObjectUtils.nullSafeHashCode(getPath()); } } diff --git a/spring-web/src/test/java/org/springframework/web/util/UriComponentsBuilderTests.java b/spring-web/src/test/java/org/springframework/web/util/UriComponentsBuilderTests.java index 0ad771c439..c8bfa07ccd 100644 --- a/spring-web/src/test/java/org/springframework/web/util/UriComponentsBuilderTests.java +++ b/spring-web/src/test/java/org/springframework/web/util/UriComponentsBuilderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2018 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. @@ -49,7 +49,9 @@ public class UriComponentsBuilderTests { @Test public void plain() throws URISyntaxException { UriComponentsBuilder builder = UriComponentsBuilder.newInstance(); - UriComponents result = builder.scheme("http").host("example.com").path("foo").queryParam("bar").fragment("baz").build(); + UriComponents result = builder.scheme("http").host("example.com") + .path("foo").queryParam("bar").fragment("baz") + .build(); assertEquals("http", result.getScheme()); assertEquals("example.com", result.getHost()); assertEquals("foo", result.getPath()); @@ -62,7 +64,8 @@ public class UriComponentsBuilderTests { @Test public void multipleFromSameBuilder() throws URISyntaxException { - UriComponentsBuilder builder = UriComponentsBuilder.newInstance().scheme("http").host("example.com").pathSegment("foo"); + UriComponentsBuilder builder = UriComponentsBuilder.newInstance() + .scheme("http").host("example.com").pathSegment("foo"); UriComponents result1 = builder.build(); builder = builder.pathSegment("foo2").queryParam("bar").fragment("baz"); UriComponents result2 = builder.build(); @@ -125,11 +128,12 @@ public class UriComponentsBuilderTests { assertEquals("Invalid result URI", uri, result.toUri()); } - @Test // SPR-9317 + @Test // SPR-9317 public void fromUriEncodedQuery() throws URISyntaxException { URI uri = new URI("http://www.example.org/?param=aGVsbG9Xb3JsZA%3D%3D"); String fromUri = UriComponentsBuilder.fromUri(uri).build().getQueryParams().get("param").get(0); - String fromUriString = UriComponentsBuilder.fromUriString(uri.toString()).build().getQueryParams().get("param").get(0); + String fromUriString = UriComponentsBuilder.fromUriString(uri.toString()) + .build().getQueryParams().get("param").get(0); assertEquals(fromUri, fromUriString); } @@ -146,16 +150,16 @@ public class UriComponentsBuilderTests { assertNull(result.getQuery()); assertNull(result.getFragment()); - result = UriComponentsBuilder.fromUriString( - "http://arjen:foobar@java.sun.com:80/javase/6/docs/api/java/util/BitSet.html?foo=bar#and(java.util.BitSet)") - .build(); + String url = "http://arjen:foobar@java.sun.com:80" + + "/javase/6/docs/api/java/util/BitSet.html?foo=bar#and(java.util.BitSet)"; + result = UriComponentsBuilder.fromUriString(url).build(); assertEquals("http", result.getScheme()); assertEquals("arjen:foobar", result.getUserInfo()); assertEquals("java.sun.com", result.getHost()); assertEquals(80, result.getPort()); assertEquals("/javase/6/docs/api/java/util/BitSet.html", result.getPath()); assertEquals("foo=bar", result.getQuery()); - MultiValueMap expectedQueryParams = new LinkedMultiValueMap(1); + MultiValueMap expectedQueryParams = new LinkedMultiValueMap<>(1); expectedQueryParams.add("foo", "bar"); assertEquals(expectedQueryParams, result.getQueryParams()); assertEquals("and(java.util.BitSet)", result.getFragment()); @@ -180,7 +184,7 @@ public class UriComponentsBuilderTests { assertEquals("28", result.getFragment()); } - @Test // SPR-9832 + @Test // SPR-9832 public void fromUriStringQueryParamWithReservedCharInValue() throws URISyntaxException { String uri = "http://www.google.com/ig/calculator?q=1USD=?EUR"; UriComponents result = UriComponentsBuilder.fromUriString(uri).build(); @@ -189,21 +193,19 @@ public class UriComponentsBuilderTests { assertEquals("1USD=?EUR", result.getQueryParams().getFirst("q")); } - @Test // SPR-10779 + @Test // SPR-10779 public void fromHttpUrlStringCaseInsesitiveScheme() { assertEquals("http", UriComponentsBuilder.fromHttpUrl("HTTP://www.google.com").build().getScheme()); assertEquals("https", UriComponentsBuilder.fromHttpUrl("HTTPS://www.google.com").build().getScheme()); } - - - @Test(expected = IllegalArgumentException.class) // SPR-10539 - public void fromHttpUrlStringInvalidIPv6Host() throws URISyntaxException { + @Test(expected = IllegalArgumentException.class) // SPR-10539 + public void fromHttpUrlStringInvalidIPv6Host() { UriComponentsBuilder.fromHttpUrl("http://[1abc:2abc:3abc::5ABC:6abc:8080/resource").build().encode(); } - @Test // SPR-10539 - public void fromUriStringIPv6Host() throws URISyntaxException { + @Test // SPR-10539 + public void fromUriStringIPv6Host() { UriComponents result = UriComponentsBuilder .fromUriString("http://[1abc:2abc:3abc::5ABC:6abc]:8080/resource").build().encode(); assertEquals("[1abc:2abc:3abc::5ABC:6abc]", result.getHost()); @@ -217,7 +219,7 @@ public class UriComponentsBuilderTests { assertEquals("[::192.168.1.1]", resultIPv4compatible.getHost()); } - @Test // SPR-11970 + @Test // SPR-11970 public void fromUriStringNoPathWithReservedCharInQuery() { UriComponents result = UriComponentsBuilder.fromUriString("http://example.com?foo=bar@baz").build(); assertTrue(StringUtils.isEmpty(result.getUserInfo())); @@ -227,7 +229,7 @@ public class UriComponentsBuilderTests { } @Test - public void fromHttpRequest() throws URISyntaxException { + public void fromHttpRequest() { MockHttpServletRequest request = new MockHttpServletRequest(); request.setScheme("http"); request.setServerName("localhost"); @@ -243,8 +245,8 @@ public class UriComponentsBuilderTests { assertEquals("a=1", result.getQuery()); } - @Test // SPR-12771 - public void fromHttpRequestResetsPortBeforeSettingIt() throws Exception { + @Test // SPR-12771 + public void fromHttpRequestResetsPortBeforeSettingIt() { MockHttpServletRequest request = new MockHttpServletRequest(); request.addHeader("X-Forwarded-Proto", "https"); request.addHeader("X-Forwarded-Host", "84.198.58.199"); @@ -263,7 +265,7 @@ public class UriComponentsBuilderTests { assertEquals("/rest/mobile/users/1", result.getPath()); } - @Test //SPR-14761 + @Test // SPR-14761 public void fromHttpRequestWithForwardedIPv4Host() { MockHttpServletRequest request = new MockHttpServletRequest(); request.setScheme("http"); @@ -278,7 +280,7 @@ public class UriComponentsBuilderTests { assertEquals("http://192.168.0.1/mvc-showcase", result.toString()); } - @Test //SPR-14761 + @Test // SPR-14761 public void fromHttpRequestWithForwardedIPv6() { MockHttpServletRequest request = new MockHttpServletRequest(); request.setScheme("http"); @@ -293,7 +295,7 @@ public class UriComponentsBuilderTests { assertEquals("http://[1abc:2abc:3abc::5ABC:6abc]/mvc-showcase", result.toString()); } - @Test //SPR-14761 + @Test // SPR-14761 public void fromHttpRequestWithForwardedIPv6Host() { MockHttpServletRequest request = new MockHttpServletRequest(); request.setScheme("http"); @@ -308,7 +310,7 @@ public class UriComponentsBuilderTests { assertEquals("http://[1abc:2abc:3abc::5ABC:6abc]/mvc-showcase", result.toString()); } - @Test //SPR-14761 + @Test // SPR-14761 public void fromHttpRequestWithForwardedIPv6HostAndPort() { MockHttpServletRequest request = new MockHttpServletRequest(); request.setScheme("http"); @@ -323,7 +325,6 @@ public class UriComponentsBuilderTests { assertEquals("http://[1abc:2abc:3abc::5ABC:6abc]:8080/mvc-showcase", result.toString()); } - @Test public void fromHttpRequestWithForwardedHost() { MockHttpServletRequest request = new MockHttpServletRequest(); @@ -339,7 +340,7 @@ public class UriComponentsBuilderTests { assertEquals("http://anotherHost/mvc-showcase", result.toString()); } - @Test // SPR-10701 + @Test // SPR-10701 public void fromHttpRequestWithForwardedHostIncludingPort() { MockHttpServletRequest request = new MockHttpServletRequest(); request.setScheme("http"); @@ -355,7 +356,7 @@ public class UriComponentsBuilderTests { assertEquals(443, result.getPort()); } - @Test // SPR-11140 + @Test // SPR-11140 public void fromHttpRequestWithForwardedHostMultiValuedHeader() { MockHttpServletRequest request = new MockHttpServletRequest(); request.setScheme("http"); @@ -370,7 +371,7 @@ public class UriComponentsBuilderTests { assertEquals(-1, result.getPort()); } - @Test // SPR-11855 + @Test // SPR-11855 public void fromHttpRequestWithForwardedHostAndPort() { MockHttpServletRequest request = new MockHttpServletRequest(); request.setScheme("http"); @@ -386,7 +387,7 @@ public class UriComponentsBuilderTests { assertEquals(9090, result.getPort()); } - @Test // SPR-11872 + @Test // SPR-11872 public void fromHttpRequestWithForwardedHostWithDefaultPort() { MockHttpServletRequest request = new MockHttpServletRequest(); request.setScheme("http"); @@ -401,7 +402,7 @@ public class UriComponentsBuilderTests { assertEquals(-1, result.getPort()); } - @Test // SPR-16262 + @Test // SPR-16262 public void fromHttpRequestWithForwardedProtoWithDefaultPort() { MockHttpServletRequest request = new MockHttpServletRequest(); request.setScheme("http"); @@ -435,7 +436,7 @@ public class UriComponentsBuilderTests { assertEquals(-1, result.getPort()); } - @Test // SPR-12771 + @Test // SPR-12771 public void fromHttpRequestWithForwardedProtoAndDefaultPort() { MockHttpServletRequest request = new MockHttpServletRequest(); request.setScheme("http"); @@ -452,7 +453,7 @@ public class UriComponentsBuilderTests { assertEquals("https://84.198.58.199/mvc-showcase", result.toString()); } - @Test // SPR-12813 + @Test // SPR-12813 public void fromHttpRequestWithForwardedPortMultiValueHeader() { MockHttpServletRequest request = new MockHttpServletRequest(); request.setScheme("http"); @@ -468,7 +469,7 @@ public class UriComponentsBuilderTests { assertEquals("http://a.example.org/mvc-showcase", result.toString()); } - @Test // SPR-12816 + @Test // SPR-12816 public void fromHttpRequestWithForwardedProtoMultiValueHeader() { MockHttpServletRequest request = new MockHttpServletRequest(); request.setScheme("http"); @@ -485,8 +486,8 @@ public class UriComponentsBuilderTests { assertEquals("https://a.example.org/mvc-showcase", result.toString()); } - @Test // SPR-12742 - public void fromHttpRequestWithTrailingSlash() throws Exception { + @Test // SPR-12742 + public void fromHttpRequestWithTrailingSlash() { UriComponents before = UriComponentsBuilder.fromPath("/foo/").build(); UriComponents after = UriComponentsBuilder.newInstance().uriComponents(before).build(); assertEquals("/foo/", after.getPath()); @@ -555,7 +556,7 @@ public class UriComponentsBuilderTests { assertEquals(Arrays.asList("foo", "bar"), result.getPathSegments()); } - @Test // SPR-12398 + @Test // SPR-12398 public void pathWithDuplicateSlashes() throws URISyntaxException { UriComponents uriComponents = UriComponentsBuilder.fromPath("/foo/////////bar").build(); assertEquals("/foo/bar", uriComponents.getPath()); @@ -597,7 +598,7 @@ public class UriComponentsBuilderTests { UriComponents result = builder.queryParam("baz", "qux", 42).build(); assertEquals("baz=qux&baz=42", result.getQuery()); - MultiValueMap expectedQueryParams = new LinkedMultiValueMap(2); + MultiValueMap expectedQueryParams = new LinkedMultiValueMap<>(2); expectedQueryParams.add("baz", "qux"); expectedQueryParams.add("baz", "42"); assertEquals(expectedQueryParams, result.getQueryParams()); @@ -609,7 +610,7 @@ public class UriComponentsBuilderTests { UriComponents result = builder.queryParam("baz").build(); assertEquals("baz", result.getQuery()); - MultiValueMap expectedQueryParams = new LinkedMultiValueMap(2); + MultiValueMap expectedQueryParams = new LinkedMultiValueMap<>(2); expectedQueryParams.add("baz", null); assertEquals(expectedQueryParams, result.getQueryParams()); } @@ -634,7 +635,7 @@ public class UriComponentsBuilderTests { UriComponents result = UriComponentsBuilder.fromPath("/{foo}").buildAndExpand("fooValue"); assertEquals("/fooValue", result.toUriString()); - Map values = new HashMap(); + Map values = new HashMap<>(); values.put("foo", "fooValue"); values.put("bar", "barValue"); result = UriComponentsBuilder.fromPath("/{foo}/{bar}").buildAndExpand(values); @@ -643,10 +644,11 @@ public class UriComponentsBuilderTests { @Test public void buildAndExpandOpaque() { - UriComponents result = UriComponentsBuilder.fromUriString("mailto:{user}@{domain}").buildAndExpand("foo", "example.com"); + UriComponents result = UriComponentsBuilder.fromUriString("mailto:{user}@{domain}") + .buildAndExpand("foo", "example.com"); assertEquals("mailto:foo@example.com", result.toUriString()); - Map values = new HashMap(); + Map values = new HashMap<>(); values.put("user", "foo"); values.put("domain", "example.com"); UriComponentsBuilder.fromUriString("mailto:{user}@{domain}").buildAndExpand(values); @@ -654,21 +656,21 @@ public class UriComponentsBuilderTests { } @Test - public void queryParamWithValueWithEquals() throws Exception { + public void queryParamWithValueWithEquals() { UriComponents uriComponents = UriComponentsBuilder.fromUriString("http://example.com/foo?bar=baz").build(); assertThat(uriComponents.toUriString(), equalTo("http://example.com/foo?bar=baz")); assertThat(uriComponents.getQueryParams().get("bar").get(0), equalTo("baz")); } @Test - public void queryParamWithoutValueWithEquals() throws Exception { + public void queryParamWithoutValueWithEquals() { UriComponents uriComponents = UriComponentsBuilder.fromUriString("http://example.com/foo?bar=").build(); assertThat(uriComponents.toUriString(), equalTo("http://example.com/foo?bar=")); assertThat(uriComponents.getQueryParams().get("bar").get(0), equalTo("")); } @Test - public void queryParamWithoutValueWithoutEquals() throws Exception { + public void queryParamWithoutValueWithoutEquals() { UriComponents uriComponents = UriComponentsBuilder.fromUriString("http://example.com/foo?bar").build(); assertThat(uriComponents.toUriString(), equalTo("http://example.com/foo?bar")); @@ -677,24 +679,39 @@ public class UriComponentsBuilderTests { } @Test - public void relativeUrls() throws Exception { - assertThat(UriComponentsBuilder.fromUriString("http://example.com/foo/../bar").build().toString(), equalTo("http://example.com/foo/../bar")); - assertThat(UriComponentsBuilder.fromUriString("http://example.com/foo/../bar").build().toUriString(), equalTo("http://example.com/foo/../bar")); - assertThat(UriComponentsBuilder.fromUriString("http://example.com/foo/../bar").build().toUri().getPath(), equalTo("/foo/../bar")); - assertThat(UriComponentsBuilder.fromUriString("../../").build().toString(), equalTo("../../")); - assertThat(UriComponentsBuilder.fromUriString("../../").build().toUriString(), equalTo("../../")); - assertThat(UriComponentsBuilder.fromUriString("../../").build().toUri().getPath(), equalTo("../../")); - assertThat(UriComponentsBuilder.fromUriString("http://example.com").path("foo/../bar").build().toString(), equalTo("http://example.com/foo/../bar")); - assertThat(UriComponentsBuilder.fromUriString("http://example.com").path("foo/../bar").build().toUriString(), equalTo("http://example.com/foo/../bar")); - assertThat(UriComponentsBuilder.fromUriString("http://example.com").path("foo/../bar").build().toUri().getPath(), equalTo("/foo/../bar")); + public void relativeUrls() { + String baseUrl = "http://example.com"; + assertThat(UriComponentsBuilder.fromUriString(baseUrl + "/foo/../bar").build().toString(), + equalTo(baseUrl + "/foo/../bar")); + assertThat(UriComponentsBuilder.fromUriString(baseUrl + "/foo/../bar").build().toUriString(), + equalTo(baseUrl + "/foo/../bar")); + assertThat(UriComponentsBuilder.fromUriString(baseUrl + "/foo/../bar").build().toUri().getPath(), + equalTo("/foo/../bar")); + assertThat(UriComponentsBuilder.fromUriString("../../").build().toString(), + equalTo("../../")); + assertThat(UriComponentsBuilder.fromUriString("../../").build().toUriString(), + equalTo("../../")); + assertThat(UriComponentsBuilder.fromUriString("../../").build().toUri().getPath(), + equalTo("../../")); + assertThat(UriComponentsBuilder.fromUriString(baseUrl).path("foo/../bar").build().toString(), + equalTo(baseUrl + "/foo/../bar")); + assertThat(UriComponentsBuilder.fromUriString(baseUrl).path("foo/../bar").build().toUriString(), + equalTo(baseUrl + "/foo/../bar")); + assertThat(UriComponentsBuilder.fromUriString(baseUrl).path("foo/../bar").build().toUri().getPath(), + equalTo("/foo/../bar")); } @Test - public void emptySegments() throws Exception { - assertThat(UriComponentsBuilder.fromUriString("http://example.com/abc/").path("/x/y/z").build().toString(), equalTo("http://example.com/abc/x/y/z")); - assertThat(UriComponentsBuilder.fromUriString("http://example.com/abc/").pathSegment("x", "y", "z").build().toString(), equalTo("http://example.com/abc/x/y/z")); - assertThat(UriComponentsBuilder.fromUriString("http://example.com/abc/").path("/x/").path("/y/z").build().toString(), equalTo("http://example.com/abc/x/y/z")); - assertThat(UriComponentsBuilder.fromUriString("http://example.com/abc/").pathSegment("x").path("y").build().toString(), equalTo("http://example.com/abc/x/y")); + public void emptySegments() { + String baseUrl = "http://example.com/abc/"; + assertThat(UriComponentsBuilder.fromUriString(baseUrl).path("/x/y/z").build().toString(), + equalTo("http://example.com/abc/x/y/z")); + assertThat(UriComponentsBuilder.fromUriString(baseUrl).pathSegment("x", "y", "z").build().toString(), + equalTo("http://example.com/abc/x/y/z")); + assertThat(UriComponentsBuilder.fromUriString(baseUrl).path("/x/").path("/y/z").build().toString(), + equalTo("http://example.com/abc/x/y/z")); + assertThat(UriComponentsBuilder.fromUriString(baseUrl).pathSegment("x").path("y").build().toString(), + equalTo("http://example.com/abc/x/y")); } @Test @@ -733,8 +750,8 @@ public class UriComponentsBuilderTests { assertEquals("f2", result2.getFragment()); } - @Test // SPR-11856 - public void fromHttpRequestForwardedHeader() throws Exception { + @Test // SPR-11856 + public void fromHttpRequestForwardedHeader() { MockHttpServletRequest request = new MockHttpServletRequest(); request.addHeader("Forwarded", "proto=https; host=84.198.58.199"); request.setScheme("http"); @@ -750,7 +767,7 @@ public class UriComponentsBuilderTests { } @Test - public void fromHttpRequestForwardedHeaderQuoted() throws Exception { + public void fromHttpRequestForwardedHeaderQuoted() { MockHttpServletRequest request = new MockHttpServletRequest(); request.addHeader("Forwarded", "proto=\"https\"; host=\"84.198.58.199\""); request.setScheme("http"); @@ -766,7 +783,7 @@ public class UriComponentsBuilderTests { } @Test - public void fromHttpRequestMultipleForwardedHeader() throws Exception { + public void fromHttpRequestMultipleForwardedHeader() { MockHttpServletRequest request = new MockHttpServletRequest(); request.addHeader("Forwarded", "host=84.198.58.199;proto=https"); request.addHeader("Forwarded", "proto=ftp; host=1.2.3.4"); @@ -783,7 +800,7 @@ public class UriComponentsBuilderTests { } @Test - public void fromHttpRequestMultipleForwardedHeaderComma() throws Exception { + public void fromHttpRequestMultipleForwardedHeaderComma() { MockHttpServletRequest request = new MockHttpServletRequest(); request.addHeader("Forwarded", "host=84.198.58.199 ;proto=https, proto=ftp; host=1.2.3.4"); request.setScheme("http"); @@ -799,7 +816,7 @@ public class UriComponentsBuilderTests { } @Test - public void fromHttpRequestForwardedHeaderWithHostPortAndWithoutServerPort() throws Exception { + public void fromHttpRequestForwardedHeaderWithHostPortAndWithoutServerPort() { MockHttpServletRequest request = new MockHttpServletRequest(); request.addHeader("Forwarded", "proto=https; host=84.198.58.199:9090"); request.setScheme("http"); @@ -817,7 +834,7 @@ public class UriComponentsBuilderTests { } @Test - public void fromHttpRequestForwardedHeaderWithHostPortAndServerPort() throws Exception { + public void fromHttpRequestForwardedHeaderWithHostPortAndServerPort() { MockHttpServletRequest request = new MockHttpServletRequest(); request.addHeader("Forwarded", "proto=https; host=84.198.58.199:9090"); request.setScheme("http"); @@ -836,7 +853,7 @@ public class UriComponentsBuilderTests { } @Test - public void fromHttpRequestForwardedHeaderWithoutHostPortAndWithServerPort() throws Exception { + public void fromHttpRequestForwardedHeaderWithoutHostPortAndWithServerPort() { MockHttpServletRequest request = new MockHttpServletRequest(); request.addHeader("Forwarded", "proto=https; host=84.198.58.199"); request.setScheme("http"); @@ -855,7 +872,7 @@ public class UriComponentsBuilderTests { } @Test // SPR-16262 - public void fromHttpRequestForwardedHeaderWithProtoAndServerPort() throws Exception { + public void fromHttpRequestForwardedHeaderWithProtoAndServerPort() { MockHttpServletRequest request = new MockHttpServletRequest(); request.addHeader("Forwarded", "proto=https"); request.setScheme("http"); @@ -872,4 +889,14 @@ public class UriComponentsBuilderTests { assertEquals(-1, result.getPort()); assertEquals("https://example.com/rest/mobile/users/1", result.toUriString()); } + + @Test // SPR-16364 + public void uriComponentsNotEqualAfterNormalization() { + UriComponents uri1 = UriComponentsBuilder.fromUriString("http://test.com").build().normalize(); + UriComponents uri2 = UriComponentsBuilder.fromUriString("http://test.com/").build(); + assertTrue(uri1.getPathSegments().isEmpty()); + assertTrue(uri2.getPathSegments().isEmpty()); + assertNotEquals(uri1, uri2); + } + }