diff --git a/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/HeaderAndCookieTests.java b/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/HeaderAndCookieTests.java index 301a998b87..1a030ea11a 100644 --- a/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/HeaderAndCookieTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/HeaderAndCookieTests.java @@ -47,7 +47,7 @@ public class HeaderAndCookieTests { @Test public void headerMultipleValues() throws Exception { - this.client.get().uri("header-multi-value") + this.client.get().uri("/header-multi-value") .exchange() .expectStatus().isOk() .expectHeader().valueEquals("h1", "v1", "v2", "v3"); diff --git a/spring-web/src/main/java/org/springframework/web/util/DefaultUriBuilderFactory.java b/spring-web/src/main/java/org/springframework/web/util/DefaultUriBuilderFactory.java index 08953acf63..dbfff83176 100644 --- a/spring-web/src/main/java/org/springframework/web/util/DefaultUriBuilderFactory.java +++ b/spring-web/src/main/java/org/springframework/web/util/DefaultUriBuilderFactory.java @@ -20,11 +20,9 @@ import java.net.URI; import java.nio.charset.Charset; import java.util.Collections; import java.util.HashMap; -import java.util.List; import java.util.Map; import org.springframework.lang.Nullable; -import org.springframework.util.Assert; import org.springframework.util.MultiValueMap; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; @@ -51,43 +49,33 @@ public class DefaultUriBuilderFactory implements UriBuilderFactory { public enum EncodingMode { /** - * The default way of encoding that {@link UriComponents} supports: - *
This mode does not encode all characters with - * reserved meaning but only the ones that are illegal within a given - * URI component as defined in RFC 396. This matches the way the - * multi-argument {@link URI} constructor does encoding. + * Apply strict encoding to URI variables at the time of expanding, + * quoting both illegal characters and characters with reserved meaning + * via {@link UriUtils#encode(String, Charset)}. */ - URI_COMPONENT, + VALUES_ONLY, /** - * Comprehensive encoding of URI variable values prior to expanding: - *
This mode encodes all characters with reserved meaning, therefore
- * ensuring that expanded URI variable do not have any impact on the
- * structure or meaning of the URI.
+ * Expand URI variables first, then encode the resulting URI component
+ * values, quoting only illegal characters within a given URI
+ * component type, but not all characters with reserved meaning.
*/
- VALUES_ONLY,
+ URI_COMPONENT,
/**
* No encoding should be applied.
*/
- NONE }
+ NONE
+ }
+ @Nullable
private final UriComponentsBuilder baseUri;
- private final Map The target address must be specified on each UriBuilder.
*/
public DefaultUriBuilderFactory() {
- this(UriComponentsBuilder.newInstance());
+ this.baseUri = null;
}
/**
@@ -109,7 +97,7 @@ public class DefaultUriBuilderFactory implements UriBuilderFactory {
* @param baseUriTemplate the URI template to use a base URL
*/
public DefaultUriBuilderFactory(String baseUriTemplate) {
- this(UriComponentsBuilder.fromUriString(baseUriTemplate));
+ this.baseUri = UriComponentsBuilder.fromUriString(baseUriTemplate);
}
/**
@@ -117,11 +105,27 @@ public class DefaultUriBuilderFactory implements UriBuilderFactory {
* {@code UriComponentsBuilder}.
*/
public DefaultUriBuilderFactory(UriComponentsBuilder baseUri) {
- Assert.notNull(baseUri, "'baseUri' is required");
this.baseUri = baseUri;
}
+ /**
+ * Specify the {@link EncodingMode EncodingMode} to use when building URIs.
+ * By default set to
+ * {@link EncodingMode#URI_COMPONENT EncodingMode.URI_COMPONENT}.
+ * @param encodingMode the encoding mode to use
+ */
+ public void setEncodingMode(EncodingMode encodingMode) {
+ this.encodingMode = encodingMode;
+ }
+
+ /**
+ * Return the configured encoding mode.
+ */
+ public EncodingMode getEncodingMode() {
+ return this.encodingMode;
+ }
+
/**
* Provide default URI variable values to use when expanding URI templates
* with a Map of variables.
@@ -142,30 +146,10 @@ public class DefaultUriBuilderFactory implements UriBuilderFactory {
}
/**
- * Specify the {@link EncodingMode EncodingMode} to use when building URIs.
- * By default set to
- * {@link EncodingMode#URI_COMPONENT EncodingMode.URI_COMPONENT}.
- * @param encodingMode the encoding mode to use
- */
- public void setEncodingMode(EncodingMode encodingMode) {
- this.encodingMode = encodingMode;
- }
-
- /**
- * Return the configured encoding mode.
- */
- public EncodingMode getEncodingMode() {
- return this.encodingMode;
- }
-
- /**
- * Whether to parse the path into path segments for the URI string passed
- * into {@link #uriString(String)} or one of the expand methods.
- * Setting this property to {@code true} ensures that URI variables
- * expanded into the path are subject to path segment encoding rules and
- * "/" characters are percent-encoded. If set to {@code false} the path is
- * kept as a full path and expanded URI variables will have "/" characters
- * preserved.
+ * Whether to parse the input path into path segments if the encoding mode
+ * is set to {@link EncodingMode#URI_COMPONENT EncodingMode.URI_COMPONENT},
+ * which ensures that URI variables in the path are encoded according to
+ * path segment rules and for example a '/' is encoded.
* By default this is set to {@code true}.
* @param parsePath whether to parse the path into path segments
*/
@@ -174,7 +158,8 @@ public class DefaultUriBuilderFactory implements UriBuilderFactory {
}
/**
- * Whether the handler is configured to parse the path into path segments.
+ * Whether to parse the path into path segments if the encoding mode is set
+ * to {@link EncodingMode#URI_COMPONENT EncodingMode.URI_COMPONENT}.
*/
public boolean shouldParsePath() {
return this.parsePath;
@@ -210,30 +195,47 @@ public class DefaultUriBuilderFactory implements UriBuilderFactory {
private final UriComponentsBuilder uriComponentsBuilder;
+
public DefaultUriBuilder(String uriTemplate) {
this.uriComponentsBuilder = initUriComponentsBuilder(uriTemplate);
}
private UriComponentsBuilder initUriComponentsBuilder(String uriTemplate) {
- UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUriString(uriTemplate);
- UriComponents uriComponents = uriComponentsBuilder.build();
- UriComponentsBuilder result = (uriComponents.getHost() == null ?
- baseUri.cloneBuilder().uriComponents(uriComponents) : uriComponentsBuilder);
- if (shouldParsePath()) {
+ if (StringUtils.isEmpty(uriTemplate)) {
+ return baseUri != null ? baseUri.cloneBuilder() : UriComponentsBuilder.newInstance();
+ }
+
+ UriComponentsBuilder result;
+ if (baseUri != null) {
+ UriComponentsBuilder uricBuilder = UriComponentsBuilder.fromUriString(uriTemplate);
+ UriComponents uric = uricBuilder.build();
+ result = uric.getHost() == null ? baseUri.cloneBuilder().uriComponents(uric) : uricBuilder;
+ }
+ else {
+ result = UriComponentsBuilder.fromUriString(uriTemplate);
+ }
+
+ parsePathIfNecessary(result);
+
+ return result;
+ }
+
+ private void parsePathIfNecessary(UriComponentsBuilder result) {
+ if (shouldParsePath() && encodingMode.equals(EncodingMode.URI_COMPONENT)) {
UriComponents uric = result.build();
String path = uric.getPath();
- List