diff --git a/spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java b/spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java index 409588bd8ebb..028d0e8695f3 100644 --- a/spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java +++ b/spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java @@ -518,9 +518,9 @@ private UriComponentsBuilder whatWgUrlRecord(WhatWgUrlParser.UrlRecord record) { } path(record.path().toString()); query(record.query()); - if (StringUtils.hasText(record.fragment())) { - fragment(record.fragment()); - } + } + if (StringUtils.hasText(record.fragment())) { + fragment(record.fragment()); } return this; } 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 d40ef9a918a4..f97457b5c63e 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 @@ -27,9 +27,12 @@ import java.util.function.BiConsumer; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; +import org.springframework.web.util.UriComponentsBuilder.ParserType; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; @@ -47,8 +50,9 @@ */ class UriComponentsBuilderTests { - @Test // see gh-26453 - void examplesInReferenceManual() { + @ParameterizedTest // see gh-26453 + @EnumSource(value = ParserType.class) + void examplesInReferenceManual(ParserType parserType) { final String expected = "/hotel%20list/New%20York?q=foo%2Bbar"; URI uri = UriComponentsBuilder.fromPath("/hotel list/{city}") @@ -63,7 +67,7 @@ void examplesInReferenceManual() { .build("New York", "foo+bar"); assertThat(uri).asString().isEqualTo(expected); - uri = UriComponentsBuilder.fromUriString("/hotel list/{city}?q={q}") + uri = UriComponentsBuilder.fromUriString("/hotel list/{city}?q={q}", parserType) .build("New York", "foo+bar"); assertThat(uri).asString().isEqualTo(expected); } @@ -150,19 +154,21 @@ void fromOpaqueUri() { assertThat(result.toUri()).as("Invalid result URI").isEqualTo(uri); } - @Test // SPR-9317 - void fromUriEncodedQuery() { + @ParameterizedTest // see gh-9317 + @EnumSource(value = ParserType.class) + void fromUriEncodedQuery(ParserType parserType) { URI uri = URI.create("https://www.example.org/?param=aGVsbG9Xb3JsZA%3D%3D"); String fromUri = UriComponentsBuilder.fromUri(uri).build().getQueryParams().get("param").get(0); - String fromUriString = UriComponentsBuilder.fromUriString(uri.toString()) + String fromUriString = UriComponentsBuilder.fromUriString(uri.toString(), parserType) .build().getQueryParams().get("param").get(0); assertThat(fromUriString).isEqualTo(fromUri); } - @Test - void fromUriString() { - UriComponents result = UriComponentsBuilder.fromUriString("https://www.ietf.org/rfc/rfc3986.txt").build(); + @ParameterizedTest + @EnumSource(value = ParserType.class) + void fromUriString(ParserType parserType) { + UriComponents result = UriComponentsBuilder.fromUriString("https://www.ietf.org/rfc/rfc3986.txt", parserType).build(); assertThat(result.getScheme()).isEqualTo("https"); assertThat(result.getUserInfo()).isNull(); assertThat(result.getHost()).isEqualTo("www.ietf.org"); @@ -174,7 +180,7 @@ void fromUriString() { String url = "https://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(); + result = UriComponentsBuilder.fromUriString(url, parserType).build(); assertThat(result.getScheme()).isEqualTo("https"); assertThat(result.getUserInfo()).isEqualTo("arjen:foobar"); assertThat(result.getHost()).isEqualTo("java.sun.com"); @@ -186,7 +192,7 @@ void fromUriString() { assertThat(result.getQueryParams()).isEqualTo(expectedQueryParams); assertThat(result.getFragment()).isEqualTo("and(java.util.BitSet)"); - result = UriComponentsBuilder.fromUriString("mailto:java-net@java.sun.com#baz").build(); + result = UriComponentsBuilder.fromUriString("mailto:java-net@java.sun.com#baz", parserType).build(); assertThat(result.getScheme()).isEqualTo("mailto"); assertThat(result.getUserInfo()).isNull(); assertThat(result.getHost()).isNull(); @@ -196,7 +202,7 @@ void fromUriString() { assertThat(result.getQuery()).isNull(); assertThat(result.getFragment()).isEqualTo("baz"); - result = UriComponentsBuilder.fromUriString("mailto:user@example.com?subject=foo").build(); + result = UriComponentsBuilder.fromUriString("mailto:user@example.com?subject=foo", parserType).build(); assertThat(result.getScheme()).isEqualTo("mailto"); assertThat(result.getUserInfo()).isNull(); assertThat(result.getHost()).isNull(); @@ -206,7 +212,7 @@ void fromUriString() { assertThat(result.getQuery()).isNull(); assertThat(result.getFragment()).isNull(); - result = UriComponentsBuilder.fromUriString("docs/guide/collections/designfaq.html#28").build(); + result = UriComponentsBuilder.fromUriString("docs/guide/collections/designfaq.html#28", parserType).build(); assertThat(result.getScheme()).isNull(); assertThat(result.getUserInfo()).isNull(); assertThat(result.getHost()).isNull(); @@ -216,69 +222,80 @@ void fromUriString() { assertThat(result.getFragment()).isEqualTo("28"); } - @Test // SPR-9832 - void fromUriStringQueryParamWithReservedCharInValue() { + @ParameterizedTest // see SPR-9832 + @EnumSource(value = ParserType.class) + void fromUriStringQueryParamWithReservedCharInValue(ParserType parserType) { String uri = "https://www.google.com/ig/calculator?q=1USD=?EUR"; - UriComponents result = UriComponentsBuilder.fromUriString(uri).build(); + UriComponents result = UriComponentsBuilder.fromUriString(uri, parserType).build(); assertThat(result.getQuery()).isEqualTo("q=1USD=?EUR"); assertThat(result.getQueryParams().getFirst("q")).isEqualTo("1USD=?EUR"); } - @Test // SPR-14828 - void fromUriStringQueryParamEncodedAndContainingPlus() { + @ParameterizedTest // see SPR-14828 + @EnumSource(value = ParserType.class) + void fromUriStringQueryParamEncodedAndContainingPlus(ParserType parserType) { String httpUrl = "http://localhost:8080/test/print?value=%EA%B0%80+%EB%82%98"; - URI uri = UriComponentsBuilder.fromUriString(httpUrl).build(true).toUri(); + URI uri = UriComponentsBuilder.fromUriString(httpUrl, parserType).build(true).toUri(); assertThat(uri.toString()).isEqualTo(httpUrl); } - @Test // SPR-10539 - void fromUriStringIPv6Host() { + @ParameterizedTest // see SPR-10539 + @EnumSource(value = ParserType.class) + void fromUriStringIPv6Host(ParserType parserType) { UriComponents result = UriComponentsBuilder - .fromUriString("http://[1abc:2abc:3abc::5ABC:6abc]:8080/resource").build().encode(); + .fromUriString("http://[1abc:2abc:3abc::5ABC:6abc]:8080/resource", parserType).build().encode(); assertThat(result.getHost()).isEqualToIgnoringCase("[1abc:2abc:3abc::5ABC:6abc]"); } - @Test - void fromUriStringInvalidIPv6Host() { + @ParameterizedTest + @EnumSource(value = ParserType.class) + void fromUriStringInvalidIPv6Host(ParserType parserType) { assertThatIllegalArgumentException().isThrownBy(() -> - UriComponentsBuilder.fromUriString("http://[1abc:2abc:3abc::5ABC:6abc:8080/resource")); + UriComponentsBuilder.fromUriString("http://[1abc:2abc:3abc::5ABC:6abc:8080/resource", parserType)); } - @Test // SPR-11970 - void fromUriStringNoPathWithReservedCharInQuery() { - UriComponents result = UriComponentsBuilder.fromUriString("https://example.com?foo=bar@baz").build(); + @ParameterizedTest // see SPR-11970 + @EnumSource(value = ParserType.class) + void fromUriStringNoPathWithReservedCharInQuery(ParserType parserType) { + UriComponents result = UriComponentsBuilder.fromUriString("https://example.com?foo=bar@baz", parserType).build(); assertThat(result.getUserInfo()).isNull(); assertThat(result.getHost()).isEqualTo("example.com"); assertThat(result.getQueryParams()).containsKey("foo"); assertThat(result.getQueryParams().getFirst("foo")).isEqualTo("bar@baz"); } - @Test // SPR-14828 - void fromHttpUrlQueryParamEncodedAndContainingPlus() { + @ParameterizedTest // see SPR-1428 + @EnumSource(value = ParserType.class) + void fromHttpUrlQueryParamEncodedAndContainingPlus(ParserType parserType) { String httpUrl = "http://localhost:8080/test/print?value=%EA%B0%80+%EB%82%98"; - URI uri = UriComponentsBuilder.fromUriString(httpUrl).build(true).toUri(); + URI uri = UriComponentsBuilder.fromUriString(httpUrl, parserType).build(true).toUri(); assertThat(uri.toString()).isEqualTo(httpUrl); } - @Test // SPR-10779 - void fromHttpUrlCaseInsensitiveScheme() { - assertThat(UriComponentsBuilder.fromUriString("HTTP://www.google.com").build().getScheme()).isEqualTo("http"); - assertThat(UriComponentsBuilder.fromUriString("HTTPS://www.google.com").build().getScheme()).isEqualTo("https"); + @ParameterizedTest // see SPR-10779 + @EnumSource(value = ParserType.class) + void fromHttpUrlCaseInsensitiveScheme(ParserType parserType) { + assertThat(UriComponentsBuilder.fromUriString("HTTP://www.google.com", parserType).build().getScheme()) + .isEqualTo("http"); + assertThat(UriComponentsBuilder.fromUriString("HTTPS://www.google.com", parserType).build().getScheme()) + .isEqualTo("https"); } - @Test // SPR-10539 - void fromHttpUrlInvalidIPv6Host() { + @ParameterizedTest // see SPR-10539 + @EnumSource(value = ParserType.class) + void fromHttpUrlInvalidIPv6Host(ParserType parserType) { assertThatIllegalArgumentException().isThrownBy(() -> - UriComponentsBuilder.fromUriString("http://[1abc:2abc:3abc::5ABC:6abc:8080/resource")); + UriComponentsBuilder.fromUriString("http://[1abc:2abc:3abc::5ABC:6abc:8080/resource", parserType)); } - @Test - void fromHttpUrlWithoutFragment() { + @ParameterizedTest + @EnumSource(value = ParserType.class) + void fromHttpUrlWithoutFragment(ParserType parserType) { String httpUrl = "http://localhost:8080/test/print"; - UriComponents uriComponents = UriComponentsBuilder.fromUriString(httpUrl).build(); + UriComponents uriComponents = UriComponentsBuilder.fromUriString(httpUrl, parserType).build(); assertThat(uriComponents.getScheme()).isEqualTo("http"); assertThat(uriComponents.getUserInfo()).isNull(); assertThat(uriComponents.getHost()).isEqualTo("localhost"); @@ -290,7 +307,7 @@ void fromHttpUrlWithoutFragment() { assertThat(uriComponents.toUri().toString()).isEqualTo(httpUrl); httpUrl = "http://user:test@localhost:8080/test/print?foo=bar"; - uriComponents = UriComponentsBuilder.fromUriString(httpUrl).build(); + uriComponents = UriComponentsBuilder.fromUriString(httpUrl, parserType).build(); assertThat(uriComponents.getScheme()).isEqualTo("http"); assertThat(uriComponents.getUserInfo()).isEqualTo("user:test"); assertThat(uriComponents.getHost()).isEqualTo("localhost"); @@ -302,7 +319,7 @@ void fromHttpUrlWithoutFragment() { assertThat(uriComponents.toUri().toString()).isEqualTo(httpUrl); httpUrl = "http://localhost:8080/test/print?foo=bar"; - uriComponents = UriComponentsBuilder.fromUriString(httpUrl).build(); + uriComponents = UriComponentsBuilder.fromUriString(httpUrl, parserType).build(); assertThat(uriComponents.getScheme()).isEqualTo("http"); assertThat(uriComponents.getUserInfo()).isNull(); assertThat(uriComponents.getHost()).isEqualTo("localhost"); @@ -314,10 +331,11 @@ void fromHttpUrlWithoutFragment() { assertThat(uriComponents.toUri().toString()).isEqualTo(httpUrl); } - @Test // gh-25300 - void fromHttpUrlWithFragment() { + @ParameterizedTest // see gh-25300 + @EnumSource(value = ParserType.class) + void fromHttpUrlWithFragment(ParserType parserType) { String httpUrl = "https://example.com/#baz"; - UriComponents uriComponents = UriComponentsBuilder.fromUriString(httpUrl).build(); + UriComponents uriComponents = UriComponentsBuilder.fromUriString(httpUrl, parserType).build(); assertThat(uriComponents.getScheme()).isEqualTo("https"); assertThat(uriComponents.getUserInfo()).isNull(); assertThat(uriComponents.getHost()).isEqualTo("example.com"); @@ -329,7 +347,7 @@ void fromHttpUrlWithFragment() { assertThat(uriComponents.toUri().toString()).isEqualTo(httpUrl); httpUrl = "http://localhost:8080/test/print#baz"; - uriComponents = UriComponentsBuilder.fromUriString(httpUrl).build(); + uriComponents = UriComponentsBuilder.fromUriString(httpUrl, parserType).build(); assertThat(uriComponents.getScheme()).isEqualTo("http"); assertThat(uriComponents.getUserInfo()).isNull(); assertThat(uriComponents.getHost()).isEqualTo("localhost"); @@ -341,7 +359,7 @@ void fromHttpUrlWithFragment() { assertThat(uriComponents.toUri().toString()).isEqualTo(httpUrl); httpUrl = "http://localhost:8080/test/print?foo=bar#baz"; - uriComponents = UriComponentsBuilder.fromUriString(httpUrl).build(); + uriComponents = UriComponentsBuilder.fromUriString(httpUrl, parserType).build(); assertThat(uriComponents.getScheme()).isEqualTo("http"); assertThat(uriComponents.getUserInfo()).isNull(); assertThat(uriComponents.getHost()).isEqualTo("localhost"); @@ -429,30 +447,32 @@ void pathWithDuplicateSlashes() { assertThat(uriComponents.getPath()).isEqualTo("/foo/bar"); } - @Test - void replacePath() { - UriComponentsBuilder builder = UriComponentsBuilder.fromUriString("https://www.ietf.org/rfc/rfc2396.txt"); + @ParameterizedTest + @EnumSource(value = ParserType.class) + void replacePath(ParserType parserType) { + UriComponentsBuilder builder = UriComponentsBuilder.fromUriString("https://www.ietf.org/rfc/rfc2396.txt", parserType); builder.replacePath("/rfc/rfc3986.txt"); UriComponents result = builder.build(); assertThat(result.toUriString()).isEqualTo("https://www.ietf.org/rfc/rfc3986.txt"); - builder = UriComponentsBuilder.fromUriString("https://www.ietf.org/rfc/rfc2396.txt"); + builder = UriComponentsBuilder.fromUriString("https://www.ietf.org/rfc/rfc2396.txt", parserType); builder.replacePath(null); result = builder.build(); assertThat(result.toUriString()).isEqualTo("https://www.ietf.org"); } - @Test - void replaceQuery() { - UriComponentsBuilder builder = UriComponentsBuilder.fromUriString("https://example.com/foo?foo=bar&baz=qux"); + @ParameterizedTest + @EnumSource(value = ParserType.class) + void replaceQuery(ParserType parserType) { + UriComponentsBuilder builder = UriComponentsBuilder.fromUriString("https://example.com/foo?foo=bar&baz=qux", parserType); builder.replaceQuery("baz=42"); UriComponents result = builder.build(); assertThat(result.toUriString()).isEqualTo("https://example.com/foo?baz=42"); - builder = UriComponentsBuilder.fromUriString("https://example.com/foo?foo=bar&baz=qux"); + builder = UriComponentsBuilder.fromUriString("https://example.com/foo?foo=bar&baz=qux", parserType); builder.replaceQuery(null); result = builder.build(); @@ -583,36 +603,40 @@ void buildAndExpandHierarchical() { assertThat(result.toUriString()).isEqualTo("/fooValue/barValue"); } - @Test - void buildAndExpandOpaque() { - UriComponents result = UriComponentsBuilder.fromUriString("mailto:{user}@{domain}") + @ParameterizedTest + @EnumSource(value = ParserType.class) + void buildAndExpandOpaque(ParserType parserType) { + UriComponents result = UriComponentsBuilder.fromUriString("mailto:{user}@{domain}", parserType) .buildAndExpand("foo", "example.com"); assertThat(result.toUriString()).isEqualTo("mailto:foo@example.com"); Map values = new HashMap<>(); values.put("user", "foo"); values.put("domain", "example.com"); - UriComponentsBuilder.fromUriString("mailto:{user}@{domain}").buildAndExpand(values); + UriComponentsBuilder.fromUriString("mailto:{user}@{domain}", parserType).buildAndExpand(values); assertThat(result.toUriString()).isEqualTo("mailto:foo@example.com"); } - @Test - void queryParamWithValueWithEquals() { - UriComponents uriComponents = UriComponentsBuilder.fromUriString("https://example.com/foo?bar=baz").build(); + @ParameterizedTest + @EnumSource(value = ParserType.class) + void queryParamWithValueWithEquals(ParserType parserType) { + UriComponents uriComponents = UriComponentsBuilder.fromUriString("https://example.com/foo?bar=baz", parserType).build(); assertThat(uriComponents.toUriString()).isEqualTo("https://example.com/foo?bar=baz"); assertThat(uriComponents.getQueryParams().get("bar")).containsExactly("baz"); } - @Test - void queryParamWithoutValueWithEquals() { - UriComponents uriComponents = UriComponentsBuilder.fromUriString("https://example.com/foo?bar=").build(); + @ParameterizedTest + @EnumSource(value = ParserType.class) + void queryParamWithoutValueWithEquals(ParserType parserType) { + UriComponents uriComponents = UriComponentsBuilder.fromUriString("https://example.com/foo?bar=", parserType).build(); assertThat(uriComponents.toUriString()).isEqualTo("https://example.com/foo?bar="); assertThat(uriComponents.getQueryParams().get("bar")).element(0).asString().isEmpty(); } - @Test - void queryParamWithoutValueWithoutEquals() { - UriComponents uriComponents = UriComponentsBuilder.fromUriString("https://example.com/foo?bar").build(); + @ParameterizedTest + @EnumSource(value = ParserType.class) + void queryParamWithoutValueWithoutEquals(ParserType parserType) { + UriComponents uriComponents = UriComponentsBuilder.fromUriString("https://example.com/foo?bar", parserType).build(); assertThat(uriComponents.toUriString()).isEqualTo("https://example.com/foo?bar"); // TODO [SPR-13537] Change equalTo(null) to equalTo(""). @@ -634,46 +658,50 @@ void opaqueUriDoesNotResetOnNullInput() { assertThat(result.toUri()).isEqualTo(uri); } - @Test - void relativeUrls() { + @ParameterizedTest + @EnumSource(value = ParserType.class) + void relativeUrls(ParserType parserType) { String baseUrl = "https://example.com"; - assertThat(UriComponentsBuilder.fromUriString(baseUrl + "/foo/../bar").build().toString()) - .isEqualTo(baseUrl + "/foo/../bar"); - assertThat(UriComponentsBuilder.fromUriString(baseUrl + "/foo/../bar").build().toUriString()) - .isEqualTo(baseUrl + "/foo/../bar"); - assertThat(UriComponentsBuilder.fromUriString(baseUrl + "/foo/../bar").build().toUri().getPath()) - .isEqualTo("/foo/../bar"); - assertThat(UriComponentsBuilder.fromUriString(baseUrl).path("foo/../bar").build().toString()) + assertThat(UriComponentsBuilder.fromUriString(baseUrl + "/foo/../bar", parserType).build().toString()) + .isEqualTo(baseUrl + (parserType == ParserType.WHAT_WG ? "/bar" : "/foo/../bar")); + assertThat(UriComponentsBuilder.fromUriString(baseUrl + "/foo/../bar", parserType).build().toUriString()) + .isEqualTo(baseUrl + (parserType == ParserType.WHAT_WG ? "/bar" : "/foo/../bar")); + assertThat(UriComponentsBuilder.fromUriString(baseUrl + "/foo/../bar", parserType).build().toUri().getPath()) + .isEqualTo((parserType == ParserType.WHAT_WG ? "/bar" : "/foo/../bar")); + assertThat(UriComponentsBuilder.fromUriString(baseUrl, parserType).path("foo/../bar").build().toString()) .isEqualTo(baseUrl + "/foo/../bar"); - assertThat(UriComponentsBuilder.fromUriString(baseUrl).path("foo/../bar").build().toUriString()) + assertThat(UriComponentsBuilder.fromUriString(baseUrl, parserType).path("foo/../bar").build().toUriString()) .isEqualTo(baseUrl + "/foo/../bar"); - assertThat(UriComponentsBuilder.fromUriString(baseUrl).path("foo/../bar").build().toUri().getPath()) + assertThat(UriComponentsBuilder.fromUriString(baseUrl, parserType).path("foo/../bar").build().toUri().getPath()) .isEqualTo("/foo/../bar"); } - @Test - void emptySegments() { + @ParameterizedTest + @EnumSource(value = ParserType.class) + void emptySegments(ParserType parserType) { String baseUrl = "https://example.com/abc/"; - assertThat(UriComponentsBuilder.fromUriString(baseUrl).path("/x/y/z").build().toString()) + assertThat(UriComponentsBuilder.fromUriString(baseUrl, parserType).path("/x/y/z").build().toString()) .isEqualTo("https://example.com/abc/x/y/z"); - assertThat(UriComponentsBuilder.fromUriString(baseUrl).pathSegment("x", "y", "z").build().toString()) + assertThat(UriComponentsBuilder.fromUriString(baseUrl, parserType).pathSegment("x", "y", "z").build().toString()) .isEqualTo("https://example.com/abc/x/y/z"); - assertThat(UriComponentsBuilder.fromUriString(baseUrl).path("/x/").path("/y/z").build().toString()) + assertThat(UriComponentsBuilder.fromUriString(baseUrl, parserType).path("/x/").path("/y/z").build().toString()) .isEqualTo("https://example.com/abc/x/y/z"); - assertThat(UriComponentsBuilder.fromUriString(baseUrl).pathSegment("x").path("y").build().toString()) + assertThat(UriComponentsBuilder.fromUriString(baseUrl, parserType).pathSegment("x").path("y").build().toString()) .isEqualTo("https://example.com/abc/x/y"); } - @Test - void parsesEmptyFragment() { - UriComponents components = UriComponentsBuilder.fromUriString("/example#").build(); + @ParameterizedTest + @EnumSource(value = ParserType.class) + void parsesEmptyFragment(ParserType parserType) { + UriComponents components = UriComponentsBuilder.fromUriString("/example#", parserType).build(); assertThat(components.getFragment()).isNull(); assertThat(components.toString()).isEqualTo("/example"); } - @Test // SPR-13257 - void parsesEmptyUri() { - UriComponents components = UriComponentsBuilder.fromUriString("").build(); + @ParameterizedTest // SPR-13257 + @EnumSource(value = ParserType.class) + void parsesEmptyUri(ParserType parserType) { + UriComponents components = UriComponentsBuilder.fromUriString("", parserType).build(); assertThat(components.toString()).isEmpty(); } @@ -733,17 +761,18 @@ void testDeepClone() { assertThat(result1.getSchemeSpecificPart()).isNull(); } - @Test // gh-26466 - void encodeTemplateWithInvalidPlaceholderSyntax() { + @ParameterizedTest // gh-26466 + @EnumSource(value = ParserType.class) + void encodeTemplateWithInvalidPlaceholderSyntax(ParserType parserType) { BiConsumer tester = (in, out) -> - assertThat(UriComponentsBuilder.fromUriString(in).encode().toUriString()).isEqualTo(out); + assertThat(UriComponentsBuilder.fromUriString(in, parserType).encode().toUriString()).isEqualTo(out); // empty tester.accept("{}", "%7B%7D"); - tester.accept("{ \t}", "%7B%20%09%7D"); + tester.accept("{ \t}", (parserType == ParserType.WHAT_WG ? "%7B%20%7D" : "%7B%20%09%7D")); tester.accept("/a{}b", "/a%7B%7Db"); - tester.accept("/a{ \t}b", "/a%7B%20%09%7Db"); + tester.accept("/a{ \t}b", (parserType == ParserType.WHAT_WG ? "/a%7B%20%7Db" : "/a%7B%20%09%7Db")); // nested, matching tester.accept("{foo{}}", "%7Bfoo%7B%7D%7D"); @@ -762,28 +791,32 @@ void encodeTemplateWithInvalidPlaceholderSyntax() { tester.accept("/a{year:\\d{1,4}}b", "/a{year:\\d{1,4}}b"); } - @Test // SPR-16364 - void uriComponentsNotEqualAfterNormalization() { - UriComponents uri1 = UriComponentsBuilder.fromUriString("http://test.com").build().normalize(); - UriComponents uri2 = UriComponentsBuilder.fromUriString("http://test.com/").build(); + @ParameterizedTest // SPR-16364 + @EnumSource(value = ParserType.class) + void uriComponentsNotEqualAfterNormalization(ParserType parserType) { + UriComponents uri1 = UriComponentsBuilder.fromUriString("http://test.com", parserType).build().normalize(); + UriComponents uri2 = UriComponentsBuilder.fromUriString("http://test.com/", parserType).build(); assertThat(uri1.getPathSegments()).isEmpty(); assertThat(uri2.getPathSegments()).isEmpty(); assertThat(uri2).isNotEqualTo(uri1); } - @Test // SPR-17256 - void uriComponentsWithMergedQueryParams() { - String uri = UriComponentsBuilder.fromUriString("http://localhost:8081") - .uriComponents(UriComponentsBuilder.fromUriString("/{path}?sort={sort}").build()) + @ParameterizedTest // SPR-17256 + @EnumSource(value = ParserType.class) + void uriComponentsWithMergedQueryParams(ParserType parserType) { + String uri = UriComponentsBuilder.fromUriString("http://localhost:8081", parserType) + .uriComponents(UriComponentsBuilder.fromUriString("/{path}?sort={sort}", parserType).build()) .queryParam("sort", "another_value").build().toString(); assertThat(uri).isEqualTo("http://localhost:8081/{path}?sort={sort}&sort=another_value"); } - @Test // SPR-17630 - void toUriStringWithCurlyBraces() { - assertThat(UriComponentsBuilder.fromUriString("/path?q={asa}asa").toUriString()).isEqualTo("/path?q=%7Basa%7Dasa"); + @ParameterizedTest // SPR-17630 + @EnumSource(value = ParserType.class) + void toUriStringWithCurlyBraces(ParserType parserType) { + assertThat(UriComponentsBuilder.fromUriString("/path?q={asa}asa", parserType).toUriString()) + .isEqualTo("/path?q=%7Basa%7Dasa"); } @Test // gh-26012 @@ -792,34 +825,37 @@ void verifyDoubleSlashReplacedWithSingleOne() { assertThat(path).isEqualTo("/home/path"); } - @Test - void validPort() { - UriComponents uriComponents = UriComponentsBuilder.fromUriString("http://localhost:52567/path").build(); + @ParameterizedTest + @EnumSource(value = ParserType.class) + void validPort(ParserType parserType) { + UriComponents uriComponents = UriComponentsBuilder.fromUriString("http://localhost:52567/path", parserType).build(); assertThat(uriComponents.getPort()).isEqualTo(52567); assertThat(uriComponents.getPath()).isEqualTo("/path"); - uriComponents = UriComponentsBuilder.fromUriString("http://localhost:52567?trace=false").build(); + uriComponents = UriComponentsBuilder.fromUriString("http://localhost:52567?trace=false", parserType).build(); assertThat(uriComponents.getPort()).isEqualTo(52567); assertThat(uriComponents.getQuery()).isEqualTo("trace=false"); - uriComponents = UriComponentsBuilder.fromUriString("http://localhost:52567#fragment").build(); + uriComponents = UriComponentsBuilder.fromUriString("http://localhost:52567#fragment", parserType).build(); assertThat(uriComponents.getPort()).isEqualTo(52567); assertThat(uriComponents.getFragment()).isEqualTo("fragment"); } - @Test - void verifyInvalidPort() { + @ParameterizedTest + @EnumSource(value = ParserType.class) + void verifyInvalidPort(ParserType parserType) { String url = "http://localhost:XXX/path"; assertThatIllegalArgumentException() - .isThrownBy(() -> UriComponentsBuilder.fromUriString(url).build().toUri()); + .isThrownBy(() -> UriComponentsBuilder.fromUriString(url, parserType).build().toUri()); assertThatIllegalArgumentException() - .isThrownBy(() -> UriComponentsBuilder.fromUriString(url).build().toUri()); + .isThrownBy(() -> UriComponentsBuilder.fromUriString(url, parserType).build().toUri()); } - @Test // gh-27039 - void expandPortAndPathWithoutSeparator() { + @ParameterizedTest // gh-27039 + @EnumSource(value = ParserType.class) + void expandPortAndPathWithoutSeparator(ParserType parserType) { URI uri = UriComponentsBuilder - .fromUriString("ws://localhost:{port}/{path}") + .fromUriString("ws://localhost:{port}/{path}", parserType) .buildAndExpand(7777, "test") .toUri(); assertThat(uri.toString()).isEqualTo("ws://localhost:7777/test"); diff --git a/spring-web/src/test/java/org/springframework/web/util/UriComponentsTests.java b/spring-web/src/test/java/org/springframework/web/util/UriComponentsTests.java index f5003e11a5f7..f572eccbc4fd 100644 --- a/spring-web/src/test/java/org/springframework/web/util/UriComponentsTests.java +++ b/spring-web/src/test/java/org/springframework/web/util/UriComponentsTests.java @@ -25,6 +25,10 @@ import java.util.Collections; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; + +import org.springframework.web.util.UriComponentsBuilder.ParserType; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; @@ -74,78 +78,88 @@ void encodeAndExpandWithDollarSign() { assertThat(uri.expand("JavaClass$1.class").toString()).isEqualTo("/path?q=JavaClass%241.class"); } - @Test - void toUriEncoded() { - UriComponents uri = UriComponentsBuilder.fromUriString("https://example.com/hotel list/Z\u00fcrich").build(); + @ParameterizedTest + @EnumSource(value = ParserType.class) + void toUriEncoded(ParserType parserType) { + UriComponents uri = UriComponentsBuilder.fromUriString("https://example.com/hotel list/Z\u00fcrich", parserType).build(); assertThat(uri.encode().toUri()).isEqualTo(URI.create("https://example.com/hotel%20list/Z%C3%BCrich")); } - @Test - void toUriNotEncoded() { - UriComponents uri = UriComponentsBuilder.fromUriString("https://example.com/hotel list/Z\u00fcrich").build(); + @ParameterizedTest + @EnumSource(value = ParserType.class) + void toUriNotEncoded(ParserType parserType) { + UriComponents uri = UriComponentsBuilder.fromUriString("https://example.com/hotel list/Z\u00fcrich", parserType).build(); assertThat(uri.toUri()).isEqualTo(URI.create("https://example.com/hotel%20list/Z\u00fcrich")); } - @Test - void toUriAlreadyEncoded() { - UriComponents uri = UriComponentsBuilder.fromUriString("https://example.com/hotel%20list/Z%C3%BCrich").build(true); + @ParameterizedTest + @EnumSource(value = ParserType.class) + void toUriAlreadyEncoded(ParserType parserType) { + UriComponents uri = UriComponentsBuilder.fromUriString("https://example.com/hotel%20list/Z%C3%BCrich", parserType).build(true); assertThat(uri.encode().toUri()).isEqualTo(URI.create("https://example.com/hotel%20list/Z%C3%BCrich")); } - @Test - void toUriWithIpv6HostAlreadyEncoded() { + @ParameterizedTest + @EnumSource(value = ParserType.class) + void toUriWithIpv6HostAlreadyEncoded(ParserType parserType) { UriComponents uri = UriComponentsBuilder.fromUriString( - "http://[1abc:2abc:3abc::5ABC:6abc]:8080/hotel%20list/Z%C3%BCrich").build(true); + "http://[1abc:2abc:3abc::5ABC:6abc]:8080/hotel%20list/Z%C3%BCrich", parserType).build(true); assertThat(uri.encode().toUri()).isEqualTo( URI.create("http://[1abc:2abc:3abc::5ABC:6abc]:8080/hotel%20list/Z%C3%BCrich")); } - @Test - void toUriStringWithPortVariable() { + @ParameterizedTest + @EnumSource(value = ParserType.class) + void toUriStringWithPortVariable(ParserType parserType) { String url = "http://localhost:{port}/first"; - assertThat(UriComponentsBuilder.fromUriString(url).build().toUriString()).isEqualTo(url); + assertThat(UriComponentsBuilder.fromUriString(url, parserType).build().toUriString()).isEqualTo(url); } - @Test - void expand() { - UriComponents uri = UriComponentsBuilder.fromUriString("https://example.com").path("/{foo} {bar}").build(); + @ParameterizedTest + @EnumSource(value = ParserType.class) + void expand(ParserType parserType) { + UriComponents uri = UriComponentsBuilder.fromUriString("https://example.com", parserType).path("/{foo} {bar}").build(); uri = uri.expand("1 2", "3 4"); assertThat(uri.getPath()).isEqualTo("/1 2 3 4"); assertThat(uri.toUriString()).isEqualTo("https://example.com/1 2 3 4"); } - @Test // SPR-13311 - void expandWithRegexVar() { + @ParameterizedTest // SPR-13311 + @EnumSource(value = ParserType.class) + void expandWithRegexVar(ParserType parserType) { String template = "/myurl/{name:[a-z]{1,5}}/show"; - UriComponents uri = UriComponentsBuilder.fromUriString(template).build(); + UriComponents uri = UriComponentsBuilder.fromUriString(template, parserType).build(); uri = uri.expand(Collections.singletonMap("name", "test")); assertThat(uri.getPath()).isEqualTo("/myurl/test/show"); } - @Test // SPR-17630 - void uirTemplateExpandWithMismatchedCurlyBraces() { - UriComponents uri = UriComponentsBuilder.fromUriString("/myurl/?q={{{{").encode().build(); + @ParameterizedTest // SPR-17630 + @EnumSource(value = ParserType.class) + void uirTemplateExpandWithMismatchedCurlyBraces(ParserType parserType) { + UriComponents uri = UriComponentsBuilder.fromUriString("/myurl/?q={{{{", parserType).encode().build(); assertThat(uri.toUriString()).isEqualTo("/myurl/?q=%7B%7B%7B%7B"); } - @Test // gh-22447 - void expandWithFragmentOrder() { + @ParameterizedTest // gh-22447 + @EnumSource(value = ParserType.class) + void expandWithFragmentOrder(ParserType parserType) { UriComponents uri = UriComponentsBuilder - .fromUriString("https://{host}/{path}#{fragment}").build() + .fromUriString("https://{host}/{path}#{fragment}", parserType).build() .expand("example.com", "foo", "bar"); assertThat(uri.toUriString()).isEqualTo("https://example.com/foo#bar"); } - @Test // SPR-12123 - void port() { - UriComponents uri1 = fromUriString("https://example.com:8080/bar").build(); - UriComponents uri2 = fromUriString("https://example.com/bar").port(8080).build(); - UriComponents uri3 = fromUriString("https://example.com/bar").port("{port}").build().expand(8080); - UriComponents uri4 = fromUriString("https://example.com/bar").port("808{digit}").build().expand(0); + @ParameterizedTest // SPR-12123 + @EnumSource(value = ParserType.class) + void port(ParserType parserType) { + UriComponents uri1 = fromUriString("https://example.com:8080/bar", parserType).build(); + UriComponents uri2 = fromUriString("https://example.com/bar", parserType).port(8080).build(); + UriComponents uri3 = fromUriString("https://example.com/bar", parserType).port("{port}").build().expand(8080); + UriComponents uri4 = fromUriString("https://example.com/bar", parserType).port("808{digit}").build().expand(0); assertThat(uri1.getPort()).isEqualTo(8080); assertThat(uri1.toUriString()).isEqualTo("https://example.com:8080/bar"); @@ -157,11 +171,12 @@ void port() { assertThat(uri4.toUriString()).isEqualTo("https://example.com:8080/bar"); } - @Test // gh-28521 - void invalidPort() { + @ParameterizedTest // gh-28521 + @EnumSource(value = ParserType.class) + void invalidPort(ParserType parserType) { assertThatExceptionOfType(InvalidUrlException.class) - .isThrownBy(() -> fromUriString("https://example.com:XXX/bar")); - assertExceptionsForInvalidPort(fromUriString("https://example.com/bar").port("XXX").build()); + .isThrownBy(() -> fromUriString("https://example.com:XXX/bar", parserType)); + assertExceptionsForInvalidPort(fromUriString("https://example.com/bar", parserType).port("XXX").build()); } private void assertExceptionsForInvalidPort(UriComponents uriComponents) { @@ -191,16 +206,18 @@ void invalidEncodedSequence() { UriComponentsBuilder.fromPath("/fo%2o").build(true)); } - @Test - void normalize() { - UriComponents uri = UriComponentsBuilder.fromUriString("https://example.com/foo/../bar").build(); + @ParameterizedTest + @EnumSource(value = ParserType.class) + void normalize(ParserType parserType) { + UriComponents uri = UriComponentsBuilder.fromUriString("https://example.com/foo/../bar", parserType).build(); assertThat(uri.normalize().toString()).isEqualTo("https://example.com/bar"); } - @Test - void serializable() throws Exception { + @ParameterizedTest + @EnumSource(value = ParserType.class) + void serializable(ParserType parserType) throws Exception { UriComponents uri = UriComponentsBuilder.fromUriString( - "https://example.com").path("/{foo}").query("bar={baz}").build(); + "https://example.com", parserType).path("/{foo}").query("bar={baz}").build(); ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); @@ -222,12 +239,13 @@ void copyToUriComponentsBuilder() { assertThat(result.getPathSegments()).isEqualTo(Arrays.asList("foo", "bar", "ba%2Fz")); } - @Test - void equalsHierarchicalUriComponents() { + @ParameterizedTest + @EnumSource(value = ParserType.class) + void equalsHierarchicalUriComponents(ParserType parserType) { String url = "https://example.com"; - UriComponents uric1 = UriComponentsBuilder.fromUriString(url).path("/{foo}").query("bar={baz}").build(); - UriComponents uric2 = UriComponentsBuilder.fromUriString(url).path("/{foo}").query("bar={baz}").build(); - UriComponents uric3 = UriComponentsBuilder.fromUriString(url).path("/{foo}").query("bin={baz}").build(); + UriComponents uric1 = UriComponentsBuilder.fromUriString(url, parserType).path("/{foo}").query("bar={baz}").build(); + UriComponents uric2 = UriComponentsBuilder.fromUriString(url, parserType).path("/{foo}").query("bar={baz}").build(); + UriComponents uric3 = UriComponentsBuilder.fromUriString(url, parserType).path("/{foo}").query("bin={baz}").build(); assertThat(uric1).isInstanceOf(HierarchicalUriComponents.class); assertThat(uric1).isEqualTo(uric1); @@ -235,12 +253,13 @@ void equalsHierarchicalUriComponents() { assertThat(uric1).isNotEqualTo(uric3); } - @Test - void equalsOpaqueUriComponents() { + @ParameterizedTest + @EnumSource(value = ParserType.class) + void equalsOpaqueUriComponents(ParserType parserType) { String baseUrl = "http:example.com"; - UriComponents uric1 = UriComponentsBuilder.fromUriString(baseUrl + "/foo/bar").build(); - UriComponents uric2 = UriComponentsBuilder.fromUriString(baseUrl + "/foo/bar").build(); - UriComponents uric3 = UriComponentsBuilder.fromUriString(baseUrl + "/foo/bin").build(); + UriComponents uric1 = UriComponentsBuilder.fromUriString(baseUrl + "/foo/bar", parserType).build(); + UriComponents uric2 = UriComponentsBuilder.fromUriString(baseUrl + "/foo/bar", parserType).build(); + UriComponents uric3 = UriComponentsBuilder.fromUriString(baseUrl + "/foo/bin", parserType).build(); assertThat(uric1).isEqualTo(uric1); assertThat(uric1).isEqualTo(uric2);