SPR-8974 Fix regression in UriUtils.java
This commit is contained in:
parent
9c45acd43a
commit
bcd8355e61
|
|
@ -23,7 +23,10 @@ Changes in version 3.1.1 (2012-02-06)
|
||||||
* corrected fix for QuartzJobBean to work with Quartz 2.0/2.1
|
* corrected fix for QuartzJobBean to work with Quartz 2.0/2.1
|
||||||
* JMS CachingConnectionFactory never caches consumers for temporary queues and topics
|
* JMS CachingConnectionFactory never caches consumers for temporary queues and topics
|
||||||
* JMS SimpleMessageListenerContainer silently falls back to lazy registration of consumers
|
* JMS SimpleMessageListenerContainer silently falls back to lazy registration of consumers
|
||||||
|
* fix regresion in UriUtils
|
||||||
|
* allow adding flash attributes in methods with a ModelAndView return value
|
||||||
|
* preserve quotes in MediaType parameters
|
||||||
|
* make flash attributes available in the model of ParameterizableViewController and UrlFilenameViewController
|
||||||
|
|
||||||
Changes in version 3.1 GA (2011-12-12)
|
Changes in version 3.1 GA (2011-12-12)
|
||||||
--------------------------------------
|
--------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@ package org.springframework.web.util;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
|
@ -38,21 +40,68 @@ import org.springframework.util.Assert;
|
||||||
*/
|
*/
|
||||||
public abstract class UriUtils {
|
public abstract class UriUtils {
|
||||||
|
|
||||||
|
private static final String SCHEME_PATTERN = "([^:/?#]+):";
|
||||||
|
|
||||||
|
private static final String HTTP_PATTERN = "(http|https):";
|
||||||
|
|
||||||
|
private static final String USERINFO_PATTERN = "([^@/]*)";
|
||||||
|
|
||||||
|
private static final String HOST_PATTERN = "([^/?#:]*)";
|
||||||
|
|
||||||
|
private static final String PORT_PATTERN = "(\\d*)";
|
||||||
|
|
||||||
|
private static final String PATH_PATTERN = "([^?#]*)";
|
||||||
|
|
||||||
|
private static final String QUERY_PATTERN = "([^#]*)";
|
||||||
|
|
||||||
|
private static final String LAST_PATTERN = "(.*)";
|
||||||
|
|
||||||
|
// Regex patterns that matches URIs. See RFC 3986, appendix B
|
||||||
|
private static final Pattern URI_PATTERN = Pattern.compile(
|
||||||
|
"^(" + SCHEME_PATTERN + ")?" + "(//(" + USERINFO_PATTERN + "@)?" + HOST_PATTERN + "(:" + PORT_PATTERN +
|
||||||
|
")?" + ")?" + PATH_PATTERN + "(\\?" + QUERY_PATTERN + ")?" + "(#" + LAST_PATTERN + ")?");
|
||||||
|
|
||||||
|
private static final Pattern HTTP_URL_PATTERN = Pattern.compile(
|
||||||
|
"^" + HTTP_PATTERN + "(//(" + USERINFO_PATTERN + "@)?" + HOST_PATTERN + "(:" + PORT_PATTERN + ")?" + ")?" +
|
||||||
|
PATH_PATTERN + "(\\?" + LAST_PATTERN + ")?");
|
||||||
// encoding
|
// encoding
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encodes the given source URI into an encoded String. All various URI components are
|
* Encodes the given source URI into an encoded String. All various URI components are
|
||||||
* encoded according to their respective valid character sets.
|
* encoded according to their respective valid character sets.
|
||||||
|
* <p><strong>Note</strong> that this method does not attempt to encode "=" and "&"
|
||||||
|
* characters in query parameter names and query parameter values because they cannot
|
||||||
|
* be parsed in a reliable way. Instead use:
|
||||||
|
* <pre>
|
||||||
|
* UriComponents uriComponents = UriComponentsBuilder.fromUri("/path?name={value}").buildAndExpand("a=b");
|
||||||
|
* String encodedUri = uriComponents.encode().toUriString();
|
||||||
|
* </pre>
|
||||||
* @param uri the URI to be encoded
|
* @param uri the URI to be encoded
|
||||||
* @param encoding the character encoding to encode to
|
* @param encoding the character encoding to encode to
|
||||||
* @return the encoded URI
|
* @return the encoded URI
|
||||||
* @throws IllegalArgumentException when the given uri parameter is not a valid URI
|
* @throws IllegalArgumentException when the given uri parameter is not a valid URI
|
||||||
* @throws UnsupportedEncodingException when the given encoding parameter is not supported
|
* @throws UnsupportedEncodingException when the given encoding parameter is not supported
|
||||||
|
* @deprecated in favor of {@link UriComponentsBuilder}; see note about query param encoding
|
||||||
*/
|
*/
|
||||||
public static String encodeUri(String uri, String encoding) throws UnsupportedEncodingException {
|
public static String encodeUri(String uri, String encoding) throws UnsupportedEncodingException {
|
||||||
UriComponents uriComponents = UriComponentsBuilder.fromUriString(uri).build();
|
Assert.notNull(uri, "'uri' must not be null");
|
||||||
UriComponents encoded = uriComponents.encode(encoding);
|
Assert.hasLength(encoding, "'encoding' must not be empty");
|
||||||
return encoded.toUriString();
|
Matcher m = URI_PATTERN.matcher(uri);
|
||||||
|
if (m.matches()) {
|
||||||
|
String scheme = m.group(2);
|
||||||
|
String authority = m.group(3);
|
||||||
|
String userinfo = m.group(5);
|
||||||
|
String host = m.group(6);
|
||||||
|
String port = m.group(8);
|
||||||
|
String path = m.group(9);
|
||||||
|
String query = m.group(11);
|
||||||
|
String fragment = m.group(13);
|
||||||
|
|
||||||
|
return encodeUriComponents(scheme, authority, userinfo, host, port, path, query, fragment, encoding);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new IllegalArgumentException("[" + uri + "] is not a valid URI");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -60,16 +109,38 @@ public abstract class UriUtils {
|
||||||
* encoded according to their respective valid character sets.
|
* encoded according to their respective valid character sets.
|
||||||
* <p><strong>Note</strong> that this method does not support fragments ({@code #}),
|
* <p><strong>Note</strong> that this method does not support fragments ({@code #}),
|
||||||
* as these are not supposed to be sent to the server, but retained by the client.
|
* as these are not supposed to be sent to the server, but retained by the client.
|
||||||
|
* <p><strong>Note</strong> that this method does not attempt to encode "=" and "&"
|
||||||
|
* characters in query parameter names and query parameter values because they cannot
|
||||||
|
* be parsed in a reliable way. Instead use:
|
||||||
|
* <pre>
|
||||||
|
* UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl("/path?name={value}").buildAndExpand("a=b");
|
||||||
|
* String encodedUri = uriComponents.encode().toUriString();
|
||||||
|
* </pre>
|
||||||
* @param httpUrl the HTTP URL to be encoded
|
* @param httpUrl the HTTP URL to be encoded
|
||||||
* @param encoding the character encoding to encode to
|
* @param encoding the character encoding to encode to
|
||||||
* @return the encoded URL
|
* @return the encoded URL
|
||||||
* @throws IllegalArgumentException when the given uri parameter is not a valid URI
|
* @throws IllegalArgumentException when the given uri parameter is not a valid URI
|
||||||
* @throws UnsupportedEncodingException when the given encoding parameter is not supported
|
* @throws UnsupportedEncodingException when the given encoding parameter is not supported
|
||||||
|
* @deprecated in favor of {@link UriComponentsBuilder}; see note about query param encoding
|
||||||
*/
|
*/
|
||||||
public static String encodeHttpUrl(String httpUrl, String encoding) throws UnsupportedEncodingException {
|
public static String encodeHttpUrl(String httpUrl, String encoding) throws UnsupportedEncodingException {
|
||||||
UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl(httpUrl).build();
|
Assert.notNull(httpUrl, "'httpUrl' must not be null");
|
||||||
UriComponents encoded = uriComponents.encode(encoding);
|
Assert.hasLength(encoding, "'encoding' must not be empty");
|
||||||
return encoded.toUriString();
|
Matcher m = HTTP_URL_PATTERN.matcher(httpUrl);
|
||||||
|
if (m.matches()) {
|
||||||
|
String scheme = m.group(1);
|
||||||
|
String authority = m.group(2);
|
||||||
|
String userinfo = m.group(4);
|
||||||
|
String host = m.group(5);
|
||||||
|
String portString = m.group(7);
|
||||||
|
String path = m.group(8);
|
||||||
|
String query = m.group(10);
|
||||||
|
|
||||||
|
return encodeUriComponents(scheme, authority, userinfo, host, portString, path, query, null, encoding);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new IllegalArgumentException("[" + httpUrl + "] is not a valid HTTP URL");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -87,20 +158,48 @@ public abstract class UriUtils {
|
||||||
* @return the encoded URI
|
* @return the encoded URI
|
||||||
* @throws IllegalArgumentException when the given uri parameter is not a valid URI
|
* @throws IllegalArgumentException when the given uri parameter is not a valid URI
|
||||||
* @throws UnsupportedEncodingException when the given encoding parameter is not supported
|
* @throws UnsupportedEncodingException when the given encoding parameter is not supported
|
||||||
|
* @deprecated in favor of {@link UriComponentsBuilder}
|
||||||
*/
|
*/
|
||||||
public static String encodeUriComponents(String scheme, String authority, String userInfo,
|
public static String encodeUriComponents(String scheme, String authority, String userInfo,
|
||||||
String host, String port, String path, String query, String fragment, String encoding)
|
String host, String port, String path, String query, String fragment, String encoding)
|
||||||
throws UnsupportedEncodingException {
|
throws UnsupportedEncodingException {
|
||||||
|
|
||||||
int portAsInt = (port != null ? Integer.parseInt(port) : -1);
|
Assert.hasLength(encoding, "'encoding' must not be empty");
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
UriComponentsBuilder builder = UriComponentsBuilder.newInstance();
|
if (scheme != null) {
|
||||||
builder.scheme(scheme).userInfo(userInfo).host(host).port(portAsInt);
|
sb.append(encodeScheme(scheme, encoding));
|
||||||
builder.path(path).query(query).fragment(fragment);
|
sb.append(':');
|
||||||
|
}
|
||||||
|
|
||||||
UriComponents encoded = builder.build().encode(encoding);
|
if (authority != null) {
|
||||||
|
sb.append("//");
|
||||||
|
if (userInfo != null) {
|
||||||
|
sb.append(encodeUserInfo(userInfo, encoding));
|
||||||
|
sb.append('@');
|
||||||
|
}
|
||||||
|
if (host != null) {
|
||||||
|
sb.append(encodeHost(host, encoding));
|
||||||
|
}
|
||||||
|
if (port != null) {
|
||||||
|
sb.append(':');
|
||||||
|
sb.append(encodePort(port, encoding));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return encoded.toUriString();
|
sb.append(encodePath(path, encoding));
|
||||||
|
|
||||||
|
if (query != null) {
|
||||||
|
sb.append('?');
|
||||||
|
sb.append(encodeQuery(query, encoding));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fragment != null) {
|
||||||
|
sb.append('#');
|
||||||
|
sb.append(encodeFragment(fragment, encoding));
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -128,6 +128,9 @@ public class UriUtilsTests {
|
||||||
assertEquals("Invalid encoded URI", "http://example.com/query=foo@bar",
|
assertEquals("Invalid encoded URI", "http://example.com/query=foo@bar",
|
||||||
UriUtils.encodeUri("http://example.com/query=foo@bar", ENC));
|
UriUtils.encodeUri("http://example.com/query=foo@bar", ENC));
|
||||||
|
|
||||||
|
// SPR-8974
|
||||||
|
assertEquals("http://example.org?format=json&url=http://another.com?foo=bar",
|
||||||
|
UriUtils.encodeUri("http://example.org?format=json&url=http://another.com?foo=bar", ENC));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue