diff --git a/spring-web/src/main/java/org/springframework/http/converter/json/AbstractJackson2HttpMessageConverter.java b/spring-web/src/main/java/org/springframework/http/converter/json/AbstractJackson2HttpMessageConverter.java index 48e62c789e3..d7ce67d4809 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/json/AbstractJackson2HttpMessageConverter.java +++ b/spring-web/src/main/java/org/springframework/http/converter/json/AbstractJackson2HttpMessageConverter.java @@ -285,7 +285,15 @@ public abstract class AbstractJackson2HttpMessageConverter extends AbstractGener } } - private static Charset getCharset(@Nullable MediaType contentType) { + /** + * Return the charset to use for JSON input. + *
By default this is either the charset from the input {@code MediaType}
+ * or otherwise falling back on {@code UTF-8}.
+ * @param contentType the content type of the HTTP input message
+ * @return the charset to use
+ * @since 5.1.18
+ */
+ protected static Charset getCharset(@Nullable MediaType contentType) {
if (contentType != null && contentType.getCharset() != null) {
return contentType.getCharset();
}
diff --git a/spring-web/src/main/java/org/springframework/web/filter/ForwardedHeaderFilter.java b/spring-web/src/main/java/org/springframework/web/filter/ForwardedHeaderFilter.java
index dac3ab709f1..40d74ae24f7 100644
--- a/spring-web/src/main/java/org/springframework/web/filter/ForwardedHeaderFilter.java
+++ b/spring-web/src/main/java/org/springframework/web/filter/ForwardedHeaderFilter.java
@@ -81,20 +81,11 @@ public class ForwardedHeaderFilter extends OncePerRequestFilter {
}
- private final UrlPathHelper pathHelper;
-
private boolean removeOnly;
private boolean relativeRedirects;
- public ForwardedHeaderFilter() {
- this.pathHelper = new UrlPathHelper();
- this.pathHelper.setUrlDecode(false);
- this.pathHelper.setRemoveSemicolonContent(false);
- }
-
-
/**
* Enables mode in which any "Forwarded" or "X-Forwarded-*" headers are
* removed only and the information in them ignored.
@@ -151,7 +142,7 @@ public class ForwardedHeaderFilter extends OncePerRequestFilter {
}
else {
HttpServletRequest wrappedRequest =
- new ForwardedHeaderExtractingRequest(request, this.pathHelper);
+ new ForwardedHeaderExtractingRequest(request);
HttpServletResponse wrappedResponse = this.relativeRedirects ?
RelativeRedirectResponseWrapper.wrapIfNecessary(response, HttpStatus.SEE_OTHER) :
@@ -235,7 +226,7 @@ public class ForwardedHeaderFilter extends OncePerRequestFilter {
private final ForwardedPrefixExtractor forwardedPrefixExtractor;
- ForwardedHeaderExtractingRequest(HttpServletRequest servletRequest, UrlPathHelper pathHelper) {
+ ForwardedHeaderExtractingRequest(HttpServletRequest servletRequest) {
super(servletRequest);
ServerHttpRequest request = new ServletServerHttpRequest(servletRequest);
@@ -251,7 +242,7 @@ public class ForwardedHeaderFilter extends OncePerRequestFilter {
String baseUrl = this.scheme + "://" + this.host + (port == -1 ? "" : ":" + port);
Supplier Note: the components in the resulting builder will be
+ * in fully encoded (raw) form and further changes must also supply values
+ * that are fully encoded, for example via methods in {@link UriUtils}.
+ * In addition please use {@link #build(boolean)} with a value of "true" to
+ * build the {@link UriComponents} instance in order to indicate that the
+ * components are encoded.
* @param uri the URI to initialize with
* @return the new {@code UriComponentsBuilder}
*/
@@ -439,11 +445,13 @@ public class UriComponentsBuilder implements UriBuilder, Cloneable {
}
/**
- * Build a {@code UriComponents} instance from the various components
- * contained in this builder.
- * @param encoded whether all the components set in this builder are
- * encoded ({@code true}) or not ({@code false})
+ * Variant of {@link #build()} to create a {@link UriComponents} instance
+ * when components are already fully encoded. This is useful for example if
+ * the builder was created via {@link UriComponentsBuilder#fromUri(URI)}.
+ * @param encoded whether the components in this builder are already encoded
* @return the URI components
+ * @throws IllegalArgumentException if any of the components contain illegal
+ * characters that should have been encoded.
*/
public UriComponents build(boolean encoded) {
return buildInternal(encoded ?
diff --git a/spring-web/src/main/java/org/springframework/web/util/UrlPathHelper.java b/spring-web/src/main/java/org/springframework/web/util/UrlPathHelper.java
index 96ddf07a51e..fbeb51f3fe5 100644
--- a/spring-web/src/main/java/org/springframework/web/util/UrlPathHelper.java
+++ b/spring-web/src/main/java/org/springframework/web/util/UrlPathHelper.java
@@ -85,6 +85,8 @@ public class UrlPathHelper {
private String defaultEncoding = WebUtils.DEFAULT_CHARACTER_ENCODING;
+ private boolean readOnly = false;
+
/**
* Whether URL lookups should always use the full path within the current
@@ -96,6 +98,7 @@ public class UrlPathHelper {
* By default this is set to "false".
*/
public void setAlwaysUseFullPath(boolean alwaysUseFullPath) {
+ checkReadOnly();
this.alwaysUseFullPath = alwaysUseFullPath;
}
@@ -118,6 +121,7 @@ public class UrlPathHelper {
* @see java.net.URLDecoder#decode(String, String)
*/
public void setUrlDecode(boolean urlDecode) {
+ checkReadOnly();
this.urlDecode = urlDecode;
}
@@ -134,6 +138,7 @@ public class UrlPathHelper {
* Default is "true".
*/
public void setRemoveSemicolonContent(boolean removeSemicolonContent) {
+ checkReadOnly();
this.removeSemicolonContent = removeSemicolonContent;
}
@@ -141,6 +146,7 @@ public class UrlPathHelper {
* Whether configured to remove ";" (semicolon) content from the request URI.
*/
public boolean shouldRemoveSemicolonContent() {
+ checkReadOnly();
return this.removeSemicolonContent;
}
@@ -158,6 +164,7 @@ public class UrlPathHelper {
* @see WebUtils#DEFAULT_CHARACTER_ENCODING
*/
public void setDefaultEncoding(String defaultEncoding) {
+ checkReadOnly();
this.defaultEncoding = defaultEncoding;
}
@@ -168,6 +175,17 @@ public class UrlPathHelper {
return this.defaultEncoding;
}
+ /**
+ * Switch to read-only mode where further configuration changes are not allowed.
+ */
+ private void setReadOnly() {
+ this.readOnly = true;
+ }
+
+ private void checkReadOnly() {
+ Assert.isTrue(!this.readOnly, "This instance cannot be modified");
+ }
+
/**
* {@link #getLookupPathForRequest Resolve} the lookupPath and cache it in a
@@ -590,8 +608,7 @@ public class UrlPathHelper {
* @return the updated URI string
*/
public String removeSemicolonContent(String requestUri) {
- return (this.removeSemicolonContent ?
- removeSemicolonContentInternal(requestUri) : removeJsessionid(requestUri));
+ return (this.removeSemicolonContent ? removeSemicolonContentInternal(requestUri) : requestUri);
}
private String removeSemicolonContentInternal(String requestUri) {
@@ -605,16 +622,6 @@ public class UrlPathHelper {
return requestUri;
}
- private String removeJsessionid(String requestUri) {
- int startIndex = requestUri.toLowerCase().indexOf(";jsessionid=");
- if (startIndex != -1) {
- int endIndex = requestUri.indexOf(';', startIndex + 12);
- String start = requestUri.substring(0, startIndex);
- requestUri = (endIndex != -1) ? start + requestUri.substring(endIndex) : start;
- }
- return requestUri;
- }
-
/**
* Decode the given URI path variables via {@link #decodeRequestString} unless
* {@link #setUrlDecode} is set to {@code true} in which case it is assumed
@@ -695,7 +702,7 @@ public class UrlPathHelper {
/**
- * Shared, read-only instance of {@code UrlPathHelper}. Uses default settings:
+ * Shared, read-only instance with defaults. The following apply:
*
*
*/
- public static final UrlPathHelper defaultInstance = new UrlPathHelper() {
+ public static final UrlPathHelper defaultInstance = new UrlPathHelper();
- @Override
- public void setAlwaysUseFullPath(boolean alwaysUseFullPath) {
- throw new UnsupportedOperationException();
- }
+ static {
+ defaultInstance.setReadOnly();
+ }
- @Override
- public void setUrlDecode(boolean urlDecode) {
- throw new UnsupportedOperationException();
- }
- @Override
- public void setRemoveSemicolonContent(boolean removeSemicolonContent) {
- throw new UnsupportedOperationException();
- }
+ /**
+ * Shared, read-only instance for the full, encoded path. The following apply:
+ *
+ *
+ */
+ public static final UrlPathHelper rawPathInstance = new UrlPathHelper();
- @Override
- public void setDefaultEncoding(String defaultEncoding) {
- throw new UnsupportedOperationException();
- }
- };
+ static {
+ rawPathInstance.setAlwaysUseFullPath(true);
+ rawPathInstance.setUrlDecode(false);
+ rawPathInstance.setRemoveSemicolonContent(false);
+ rawPathInstance.setReadOnly();
+ }
}
diff --git a/spring-web/src/main/java/org/springframework/web/util/WebUtils.java b/spring-web/src/main/java/org/springframework/web/util/WebUtils.java
index fec0cfdbe87..8a0e76127ae 100644
--- a/spring-web/src/main/java/org/springframework/web/util/WebUtils.java
+++ b/spring-web/src/main/java/org/springframework/web/util/WebUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2019 the original author or authors.
+ * Copyright 2002-2020 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.
@@ -733,6 +733,9 @@ public abstract class WebUtils {
int index = pair.indexOf('=');
if (index != -1) {
String name = pair.substring(0, index);
+ if (name.equalsIgnoreCase("jsessionid")) {
+ continue;
+ }
String rawValue = pair.substring(index + 1);
for (String value : StringUtils.commaDelimitedListToStringArray(rawValue)) {
result.add(name, value);
diff --git a/spring-web/src/test/java/org/springframework/web/util/UrlPathHelperTests.java b/spring-web/src/test/java/org/springframework/web/util/UrlPathHelperTests.java
index ee53ff82079..9bd57cb1bab 100644
--- a/spring-web/src/test/java/org/springframework/web/util/UrlPathHelperTests.java
+++ b/spring-web/src/test/java/org/springframework/web/util/UrlPathHelperTests.java
@@ -126,14 +126,7 @@ public class UrlPathHelperTests {
assertThat(helper.getRequestUri(request)).isEqualTo("/foo;a=b;c=d");
request.setRequestURI("/foo;jsessionid=c0o7fszeb1");
- assertThat(helper.getRequestUri(request)).as("jsessionid should always be removed").isEqualTo("/foo");
-
- request.setRequestURI("/foo;a=b;jsessionid=c0o7fszeb1;c=d");
- assertThat(helper.getRequestUri(request)).as("jsessionid should always be removed").isEqualTo("/foo;a=b;c=d");
-
- // SPR-10398
- request.setRequestURI("/foo;a=b;JSESSIONID=c0o7fszeb1;c=d");
- assertThat(helper.getRequestUri(request)).as("JSESSIONID should always be removed").isEqualTo("/foo;a=b;c=d");
+ assertThat(helper.getRequestUri(request)).isEqualTo("/foo;jsessionid=c0o7fszeb1");
}
@Test
diff --git a/spring-web/src/test/java/org/springframework/web/util/WebUtilsTests.java b/spring-web/src/test/java/org/springframework/web/util/WebUtilsTests.java
index 68226877b16..998af1c9eb1 100644
--- a/spring-web/src/test/java/org/springframework/web/util/WebUtilsTests.java
+++ b/spring-web/src/test/java/org/springframework/web/util/WebUtilsTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2019 the original author or authors.
+ * Copyright 2002-2020 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.
@@ -16,7 +16,6 @@
package org.springframework.web.util;
-import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@@ -65,29 +64,42 @@ public class WebUtilsTests {
MultiValueMap>() { }.getType();
- private static final UrlPathHelper decodingUrlPathHelper = UrlPathHelper.defaultInstance;
-
- private static final UrlPathHelper rawUrlPathHelper = new UrlPathHelper();
-
- static {
- rawUrlPathHelper.setRemoveSemicolonContent(false);
- rawUrlPathHelper.setUrlDecode(false);
- }
-
-
private final ContentNegotiationManager contentNegotiationManager;
private final Set