SPR-5973: Cleaning it up
This commit is contained in:
parent
5f208936ec
commit
b6c1e88e4a
|
|
@ -19,6 +19,7 @@ package org.springframework.web.util;
|
|||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
|
@ -120,56 +121,27 @@ public class UriBuilder {
|
|||
* @return the resulting URI
|
||||
*/
|
||||
public URI build() {
|
||||
StringBuilder uriBuilder = new StringBuilder();
|
||||
|
||||
if (scheme != null) {
|
||||
uriBuilder.append(scheme);
|
||||
uriBuilder.append(':');
|
||||
}
|
||||
|
||||
if (userInfo != null || host != null || port != -1) {
|
||||
uriBuilder.append("//");
|
||||
|
||||
if (StringUtils.hasLength(userInfo)) {
|
||||
uriBuilder.append(userInfo);
|
||||
uriBuilder.append('@');
|
||||
}
|
||||
|
||||
if (host != null) {
|
||||
uriBuilder.append(host);
|
||||
}
|
||||
|
||||
if (port != -1) {
|
||||
uriBuilder.append(':');
|
||||
uriBuilder.append(port);
|
||||
}
|
||||
}
|
||||
|
||||
String port = portAsString();
|
||||
String path = null;
|
||||
if (!pathSegments.isEmpty()) {
|
||||
StringBuilder pathBuilder = new StringBuilder();
|
||||
for (String pathSegment : pathSegments) {
|
||||
boolean startsWithSlash = pathSegment.charAt(0) == '/';
|
||||
boolean endsWithSlash = uriBuilder.length() > 0 && uriBuilder.charAt(uriBuilder.length() - 1) == '/';
|
||||
boolean endsWithSlash = pathBuilder.length() > 0 && pathBuilder.charAt(pathBuilder.length() - 1) == '/';
|
||||
|
||||
if (!endsWithSlash && !startsWithSlash) {
|
||||
uriBuilder.append('/');
|
||||
pathBuilder.append('/');
|
||||
}
|
||||
else if (endsWithSlash && startsWithSlash) {
|
||||
pathSegment = pathSegment.substring(1);
|
||||
}
|
||||
uriBuilder.append(pathSegment);
|
||||
pathBuilder.append(pathSegment);
|
||||
}
|
||||
path = pathBuilder.toString();
|
||||
}
|
||||
String query = queryAsString();
|
||||
|
||||
if (queryBuilder.length() > 0) {
|
||||
uriBuilder.append('?');
|
||||
uriBuilder.append(queryBuilder);
|
||||
}
|
||||
|
||||
if (StringUtils.hasLength(fragment)) {
|
||||
uriBuilder.append('#');
|
||||
uriBuilder.append(fragment);
|
||||
}
|
||||
String uri = uriBuilder.toString();
|
||||
String uri = UriUtils.buildUri(scheme, null, userInfo, host, port, path, query, fragment);
|
||||
|
||||
uri = StringUtils.replace(uri, "{", "%7B");
|
||||
uri = StringUtils.replace(uri, "}", "%7D");
|
||||
|
|
@ -186,7 +158,7 @@ public class UriBuilder {
|
|||
* @return the resulting URI
|
||||
*/
|
||||
public URI build(Map<String, ?> uriVariables) {
|
||||
return buildFromMap(true, uriVariables);
|
||||
return buildFromMap(uriVariables, true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -197,72 +169,54 @@ public class UriBuilder {
|
|||
* @return the resulting URI
|
||||
*/
|
||||
public URI buildFromEncoded(Map<String, ?> uriVariables) {
|
||||
return buildFromMap(false, uriVariables);
|
||||
return buildFromMap(uriVariables, false);
|
||||
}
|
||||
|
||||
private URI buildFromMap(boolean encodeUriVariableValues, Map<String, ?> uriVariables) {
|
||||
private URI buildFromMap(Map<String, ?> uriVariables, boolean encodeUriVariableValues) {
|
||||
if (CollectionUtils.isEmpty(uriVariables)) {
|
||||
return build();
|
||||
}
|
||||
|
||||
StringBuilder uriBuilder = new StringBuilder();
|
||||
|
||||
UriTemplate template;
|
||||
|
||||
if (scheme != null) {
|
||||
template = new UriComponentTemplate(scheme, UriComponent.SCHEME, encodeUriVariableValues);
|
||||
uriBuilder.append(template.expandAsString(uriVariables));
|
||||
uriBuilder.append(':');
|
||||
}
|
||||
|
||||
if (userInfo != null || host != null || port != -1) {
|
||||
uriBuilder.append("//");
|
||||
|
||||
if (StringUtils.hasLength(userInfo)) {
|
||||
template = new UriComponentTemplate(userInfo, UriComponent.USER_INFO, encodeUriVariableValues);
|
||||
uriBuilder.append(template.expandAsString(uriVariables));
|
||||
uriBuilder.append('@');
|
||||
}
|
||||
|
||||
if (host != null) {
|
||||
template = new UriComponentTemplate(host, UriComponent.HOST, encodeUriVariableValues);
|
||||
uriBuilder.append(template.expandAsString(uriVariables));
|
||||
}
|
||||
|
||||
if (port != -1) {
|
||||
uriBuilder.append(':');
|
||||
uriBuilder.append(port);
|
||||
}
|
||||
}
|
||||
|
||||
if (!pathSegments.isEmpty()) {
|
||||
for (String pathSegment : pathSegments) {
|
||||
String scheme = expand(this.scheme, UriComponent.SCHEME, uriVariables, encodeUriVariableValues);
|
||||
String userInfo = expand(this.userInfo, UriComponent.USER_INFO, uriVariables, encodeUriVariableValues);
|
||||
String host = expand(this.host, UriComponent.HOST, uriVariables, encodeUriVariableValues);
|
||||
String port = expand(this.portAsString(), UriComponent.PORT, uriVariables, encodeUriVariableValues);
|
||||
String path = null;
|
||||
if (!this.pathSegments.isEmpty()) {
|
||||
StringBuilder pathBuilder = new StringBuilder();
|
||||
for (String pathSegment : this.pathSegments) {
|
||||
boolean startsWithSlash = pathSegment.charAt(0) == '/';
|
||||
boolean endsWithSlash = uriBuilder.length() > 0 && uriBuilder.charAt(uriBuilder.length() - 1) == '/';
|
||||
boolean endsWithSlash = pathBuilder.length() > 0 && pathBuilder.charAt(pathBuilder.length() - 1) == '/';
|
||||
|
||||
if (!endsWithSlash && !startsWithSlash) {
|
||||
uriBuilder.append('/');
|
||||
pathBuilder.append('/');
|
||||
}
|
||||
else if (endsWithSlash && startsWithSlash) {
|
||||
pathSegment = pathSegment.substring(1);
|
||||
}
|
||||
template = new UriComponentTemplate(pathSegment, UriComponent.PATH_SEGMENT, encodeUriVariableValues);
|
||||
uriBuilder.append(template.expandAsString(uriVariables));
|
||||
pathSegment = expand(pathSegment, UriComponent.PATH_SEGMENT, uriVariables, encodeUriVariableValues);
|
||||
pathBuilder.append(pathSegment);
|
||||
}
|
||||
path = pathBuilder.toString();
|
||||
}
|
||||
if (queryBuilder.length() > 0) {
|
||||
uriBuilder.append('?');
|
||||
template = new UriComponentTemplate(queryBuilder.toString(), UriComponent.QUERY, encodeUriVariableValues);
|
||||
uriBuilder.append(template.expandAsString(uriVariables));
|
||||
}
|
||||
String query = expand(this.queryAsString(), UriComponent.QUERY, uriVariables, encodeUriVariableValues);
|
||||
String fragment = expand(this.fragment, UriComponent.FRAGMENT, uriVariables, encodeUriVariableValues);
|
||||
|
||||
if (StringUtils.hasLength(fragment)) {
|
||||
uriBuilder.append('#');
|
||||
template = new UriComponentTemplate(fragment, UriComponent.FRAGMENT, encodeUriVariableValues);
|
||||
uriBuilder.append(template.expandAsString(uriVariables));
|
||||
}
|
||||
String uri = UriUtils.buildUri(scheme, null, userInfo, host, port, path, query, fragment);
|
||||
return URI.create(uri);
|
||||
}
|
||||
|
||||
return URI.create(uriBuilder.toString());
|
||||
private String expand(String source,
|
||||
UriComponent uriComponent,
|
||||
Map<String, ?> uriVariables,
|
||||
boolean encodeUriVariableValues) {
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
if (source.indexOf('{') == -1) {
|
||||
return source;
|
||||
}
|
||||
UriTemplate template = new UriComponentTemplate(source, uriComponent, encodeUriVariableValues);
|
||||
return template.expandAsString(uriVariables);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -403,7 +357,7 @@ public class UriBuilder {
|
|||
public UriBuilder scheme(String scheme) {
|
||||
if (scheme != null) {
|
||||
Assert.hasLength(scheme, "'scheme' must not be empty");
|
||||
this.scheme = UriUtils.encode(scheme, UriComponent.SCHEME, true);
|
||||
this.scheme = encodeUriComponent(scheme, UriComponent.SCHEME);
|
||||
}
|
||||
else {
|
||||
this.scheme = null;
|
||||
|
|
@ -421,7 +375,7 @@ public class UriBuilder {
|
|||
public UriBuilder userInfo(String userInfo) {
|
||||
if (userInfo != null) {
|
||||
Assert.hasLength(userInfo, "'userInfo' must not be empty");
|
||||
this.userInfo = UriUtils.encode(userInfo, UriComponent.USER_INFO, true);
|
||||
this.userInfo = encodeUriComponent(userInfo, UriComponent.USER_INFO);
|
||||
}
|
||||
else {
|
||||
this.userInfo = null;
|
||||
|
|
@ -439,7 +393,7 @@ public class UriBuilder {
|
|||
public UriBuilder host(String host) {
|
||||
if (host != null) {
|
||||
Assert.hasLength(host, "'host' must not be empty");
|
||||
this.host = UriUtils.encode(host, UriComponent.HOST, true);
|
||||
this.host = encodeUriComponent(host, UriComponent.HOST);
|
||||
}
|
||||
else {
|
||||
this.host = null;
|
||||
|
|
@ -459,6 +413,10 @@ public class UriBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
private String portAsString() {
|
||||
return this.port != -1 ? Integer.toString(this.port) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the given path to the existing path of this builder. The given path may contain URI template variables.
|
||||
*
|
||||
|
|
@ -482,7 +440,7 @@ public class UriBuilder {
|
|||
public UriBuilder pathSegment(String... segments) throws IllegalArgumentException {
|
||||
Assert.notNull(segments, "'segments' must not be null");
|
||||
for (String segment : segments) {
|
||||
this.pathSegments.add(UriUtils.encode(segment, UriComponent.PATH_SEGMENT, true));
|
||||
this.pathSegments.add(encodeUriComponent(segment, UriComponent.PATH_SEGMENT));
|
||||
}
|
||||
|
||||
return this;
|
||||
|
|
@ -500,7 +458,7 @@ public class UriBuilder {
|
|||
public UriBuilder queryParam(String name, Object... values) {
|
||||
Assert.notNull(name, "'name' must not be null");
|
||||
|
||||
String encodedName = UriUtils.encode(name, UriComponent.QUERY_PARAM, true);
|
||||
String encodedName = encodeUriComponent(name, UriComponent.QUERY_PARAM);
|
||||
|
||||
if (ObjectUtils.isEmpty(values)) {
|
||||
if (queryBuilder.length() != 0) {
|
||||
|
|
@ -518,7 +476,7 @@ public class UriBuilder {
|
|||
String valueAsString = value != null ? value.toString() : "";
|
||||
if (valueAsString.length() != 0) {
|
||||
queryBuilder.append('=');
|
||||
queryBuilder.append(UriUtils.encode(valueAsString, UriComponent.QUERY_PARAM, true));
|
||||
queryBuilder.append(encodeUriComponent(valueAsString, UriComponent.QUERY_PARAM));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -526,6 +484,10 @@ public class UriBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
private String queryAsString() {
|
||||
return queryBuilder.length() != 0 ? queryBuilder.toString() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the URI fragment. The given fragment may contain URI template variables, and may also be {@code null} to clear
|
||||
* the fragment of this builder.
|
||||
|
|
@ -536,7 +498,7 @@ public class UriBuilder {
|
|||
public UriBuilder fragment(String fragment) {
|
||||
if (fragment != null) {
|
||||
Assert.hasLength(fragment, "'fragment' must not be empty");
|
||||
this.fragment = UriUtils.encode(fragment, UriComponent.FRAGMENT, true);
|
||||
this.fragment = encodeUriComponent(fragment, UriComponent.FRAGMENT);
|
||||
}
|
||||
else {
|
||||
this.fragment = null;
|
||||
|
|
@ -545,4 +507,9 @@ public class UriBuilder {
|
|||
}
|
||||
|
||||
|
||||
private String encodeUriComponent(String source, UriComponent uriComponent) {
|
||||
return UriUtils.encodeUriComponent(source, uriComponent, EnumSet.of(UriUtils.EncodingOption.ALLOW_TEMPLATE_VARS));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ class UriComponentTemplate extends UriTemplate {
|
|||
@Override
|
||||
protected String getVariableValueAsString(Object variableValue) {
|
||||
String variableValueString = super.getVariableValueAsString(variableValue);
|
||||
return encodeUriVariableValues ? UriUtils.encode(variableValueString, uriComponent, false) :
|
||||
return encodeUriVariableValues ? UriUtils.encodeUriComponent(variableValueString, uriComponent) :
|
||||
variableValueString;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,8 +18,10 @@ package org.springframework.web.util;
|
|||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
|
|
@ -29,10 +31,12 @@ import org.springframework.util.Assert;
|
|||
* Utility class for URI encoding and decoding based on RFC 3986. Offers encoding methods for the various URI
|
||||
* components.
|
||||
*
|
||||
* <p>All {@code encode*(String, String} methods in this class operate in a similar way: <ul> <li>Valid characters for
|
||||
* the specific URI component as defined in RFC 3986 stay the same. <li>All other characters are converted into one or
|
||||
* more bytes in the given encoding scheme. Each of the resulting bytes is written as a hexadecimal string in the
|
||||
* "<code>%<i>xy</i></code>" format. </ul>
|
||||
* <p>All {@code encode*(String, String} methods in this class operate in a similar way:
|
||||
* <ul>
|
||||
* <li>Valid characters for the specific URI component as defined in RFC 3986 stay the same.</li>
|
||||
* <li>All other characters are converted into one or more bytes in the given encoding scheme. Each of the
|
||||
* resulting bytes is written as a hexadecimal string in the "<code>%<i>xy</i></code>" format.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>
|
||||
|
|
@ -127,15 +131,13 @@ public abstract class UriUtils {
|
|||
* <li>{@link UriComponent#PORT}</li>
|
||||
* <li>{@link UriComponent#PATH}</li>
|
||||
* <li>{@link UriComponent#QUERY}</li>
|
||||
* <li>{@link UriComponent#FRAGMENT}</li>
|
||||
* </ul>
|
||||
* though the values assigned to these keys is {@code null} if they do not occur in the given source URI.
|
||||
*
|
||||
* <p><strong>Note</strong> that the returned map will never contain mappings for {@link UriComponent#PATH_SEGMENT},
|
||||
* nor {@link UriComponent#QUERY_PARAM}, since those components can occur multiple times in the URI.
|
||||
*
|
||||
* <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.
|
||||
* nor {@link UriComponent#QUERY_PARAM}, since those components can occur multiple times in the URI. Nor does it
|
||||
* contain a mapping for {@link UriComponent#FRAGMENT}, as fragments are not supposed to be sent to the server, but
|
||||
* retained by the client.
|
||||
*
|
||||
* @param httpUrl the source URI
|
||||
* @return the URI components of the URI
|
||||
|
|
@ -292,11 +294,12 @@ public abstract class UriUtils {
|
|||
public static String encodeUriComponents(Map<UriComponent, String> uriComponents,
|
||||
String encoding) throws UnsupportedEncodingException {
|
||||
Assert.notEmpty(uriComponents, "'uriComponents' must not be empty");
|
||||
Assert.hasLength(encoding, "'encoding' must not be empty");
|
||||
|
||||
Map<UriComponent, String> encodedUriComponents = new EnumMap<UriComponent, String>(UriComponent.class);
|
||||
for (Map.Entry<UriComponent, String> entry : uriComponents.entrySet()) {
|
||||
if (entry.getValue() != null) {
|
||||
String encodedValue = encode(entry.getValue(), encoding, entry.getKey(), false);
|
||||
String encodedValue = encodeUriComponent(entry.getValue(), encoding, entry.getKey(), null);
|
||||
encodedUriComponents.put(entry.getKey(), encodedValue);
|
||||
}
|
||||
}
|
||||
|
|
@ -329,7 +332,6 @@ public abstract class UriUtils {
|
|||
String query,
|
||||
String fragment,
|
||||
String encoding) throws UnsupportedEncodingException {
|
||||
|
||||
Assert.hasLength(encoding, "'encoding' must not be empty");
|
||||
|
||||
if (scheme != null) {
|
||||
|
|
@ -360,168 +362,88 @@ public abstract class UriUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* Encodes the given URI scheme with the given encoding.
|
||||
*
|
||||
* @param scheme the scheme to be encoded
|
||||
* @param encoding the character encoding to encode to
|
||||
* @return the encoded scheme
|
||||
* @throws UnsupportedEncodingException when the given encoding parameter is not supported
|
||||
*/
|
||||
public static String encodeScheme(String scheme, String encoding) throws UnsupportedEncodingException {
|
||||
return encode(scheme, encoding, UriComponent.SCHEME, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given URI authority with the given encoding.
|
||||
*
|
||||
* @param authority the authority to be encoded
|
||||
* @param encoding the character encoding to encode to
|
||||
* @return the encoded authority
|
||||
* @throws UnsupportedEncodingException when the given encoding parameter is not supported
|
||||
*/
|
||||
public static String encodeAuthority(String authority, String encoding) throws UnsupportedEncodingException {
|
||||
return encode(authority, encoding, UriComponent.AUTHORITY, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given URI user info with the given encoding.
|
||||
*
|
||||
* @param userInfo the user info to be encoded
|
||||
* @param encoding the character encoding to encode to
|
||||
* @return the encoded user info
|
||||
* @throws UnsupportedEncodingException when the given encoding parameter is not supported
|
||||
*/
|
||||
public static String encodeUserInfo(String userInfo, String encoding) throws UnsupportedEncodingException {
|
||||
return encode(userInfo, encoding, UriComponent.USER_INFO, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given URI host with the given encoding.
|
||||
*
|
||||
* @param host the host to be encoded
|
||||
* @param encoding the character encoding to encode to
|
||||
* @return the encoded host
|
||||
* @throws UnsupportedEncodingException when the given encoding parameter is not supported
|
||||
*/
|
||||
public static String encodeHost(String host, String encoding) throws UnsupportedEncodingException {
|
||||
return encode(host, encoding, UriComponent.HOST, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given URI port with the given encoding.
|
||||
*
|
||||
* @param port the port to be encoded
|
||||
* @param encoding the character encoding to encode to
|
||||
* @return the encoded port
|
||||
* @throws UnsupportedEncodingException when the given encoding parameter is not supported
|
||||
*/
|
||||
public static String encodePort(String port, String encoding) throws UnsupportedEncodingException {
|
||||
return encode(port, encoding, UriComponent.PORT, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given URI path with the given encoding.
|
||||
*
|
||||
* @param path the path to be encoded
|
||||
* @param encoding the character encoding to encode to
|
||||
* @return the encoded path
|
||||
* @throws UnsupportedEncodingException when the given encoding parameter is not supported
|
||||
*/
|
||||
public static String encodePath(String path, String encoding) throws UnsupportedEncodingException {
|
||||
return encode(path, encoding, UriComponent.PATH, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given URI path segment with the given encoding.
|
||||
*
|
||||
* @param segment the segment to be encoded
|
||||
* @param encoding the character encoding to encode to
|
||||
* @return the encoded segment
|
||||
* @throws UnsupportedEncodingException when the given encoding parameter is not supported
|
||||
*/
|
||||
public static String encodePathSegment(String segment, String encoding) throws UnsupportedEncodingException {
|
||||
return encode(segment, encoding, UriComponent.PATH_SEGMENT, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given URI query with the given encoding.
|
||||
*
|
||||
* @param query the query to be encoded
|
||||
* @param encoding the character encoding to encode to
|
||||
* @return the encoded query
|
||||
* @throws UnsupportedEncodingException when the given encoding parameter is not supported
|
||||
*/
|
||||
public static String encodeQuery(String query, String encoding) throws UnsupportedEncodingException {
|
||||
return encode(query, encoding, UriComponent.QUERY, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given URI query parameter with the given encoding.
|
||||
*
|
||||
* @param queryParam the query parameter to be encoded
|
||||
* @param encoding the character encoding to encode to
|
||||
* @return the encoded query parameter
|
||||
* @throws UnsupportedEncodingException when the given encoding parameter is not supported
|
||||
*/
|
||||
public static String encodeQueryParam(String queryParam, String encoding) throws UnsupportedEncodingException {
|
||||
return encode(queryParam, encoding, UriComponent.QUERY_PARAM, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given URI fragment with the given encoding.
|
||||
*
|
||||
* @param fragment the fragment to be encoded
|
||||
* @param encoding the character encoding to encode to
|
||||
* @return the encoded fragment
|
||||
* @throws UnsupportedEncodingException when the given encoding parameter is not supported
|
||||
*/
|
||||
public static String encodeFragment(String fragment, String encoding) throws UnsupportedEncodingException {
|
||||
return encode(fragment, encoding, UriComponent.FRAGMENT, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given source into an encoded String using the rules specified by the given component. This method
|
||||
* encodes with the default encoding (i.e. UTF-8).
|
||||
* Encodes the given source into an encoded String using the rules specified by the given component.
|
||||
*
|
||||
* @param source the source string
|
||||
* @param uriComponent the URI component for the source
|
||||
* @param allowTemplateVars whether URI template variables are allowed. If {@code true}, '{' and '}' characters are not
|
||||
* encoded, even though they might not be valid for the component
|
||||
* @return the encoded URI
|
||||
* @throws IllegalArgumentException when the given uri parameter is not a valid URI
|
||||
*/
|
||||
public static String encode(String source, UriComponent uriComponent, boolean allowTemplateVars) {
|
||||
public static String encodeUriComponent(String source, UriComponent uriComponent) {
|
||||
return encodeUriComponent(source, uriComponent, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given source into an encoded String using the rules specified by the given component and with the
|
||||
* given options.
|
||||
*
|
||||
* @param source the source string
|
||||
* @param encoding the encoding of the source string
|
||||
* @param uriComponent the URI component for the source
|
||||
* @param encodingOptions the options used when encoding. May be {@code null}.
|
||||
* @return the encoded URI
|
||||
* @throws IllegalArgumentException when the given uri parameter is not a valid URI
|
||||
* @see EncodingOption
|
||||
*/
|
||||
public static String encodeUriComponent(String source,
|
||||
UriComponent uriComponent,
|
||||
Set<EncodingOption> encodingOptions) {
|
||||
try {
|
||||
return encode(source, DEFAULT_ENCODING, uriComponent, allowTemplateVars);
|
||||
return encodeUriComponent(source, DEFAULT_ENCODING, uriComponent, encodingOptions);
|
||||
}
|
||||
catch (UnsupportedEncodingException e) {
|
||||
throw new InternalError("'" + DEFAULT_ENCODING + "' encoding not supported");
|
||||
catch (UnsupportedEncodingException ex) {
|
||||
throw new InternalError("\"" + DEFAULT_ENCODING + "\" not supported");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Encodes the given source into an encoded String using the rules specified by the given component.
|
||||
*
|
||||
* @param source the source string
|
||||
* @param encoding the encoding of the source string
|
||||
* @param uriComponent the URI component for the source
|
||||
* @param allowTemplateVars whether URI template variables are allowed. If {@code true}, '{' and '}' characters are not
|
||||
* encoded, even though they might not be valid for the component
|
||||
* @return the encoded URI
|
||||
* @throws IllegalArgumentException when the given uri parameter is not a valid URI
|
||||
*/
|
||||
public static String encode(String source, String encoding, UriComponent uriComponent, boolean allowTemplateVars)
|
||||
throws UnsupportedEncodingException {
|
||||
public static String encodeUriComponent(String source,
|
||||
String encoding,
|
||||
UriComponent uriComponent) throws UnsupportedEncodingException {
|
||||
return encodeUriComponent(source, encoding, uriComponent, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given source into an encoded String using the rules specified by the given component and with the
|
||||
* given options.
|
||||
*
|
||||
* @param source the source string
|
||||
* @param encoding the encoding of the source string
|
||||
* @param uriComponent the URI component for the source
|
||||
* @param encodingOptions the options used when encoding. May be {@code null}.
|
||||
* @return the encoded URI
|
||||
* @throws IllegalArgumentException when the given uri parameter is not a valid URI
|
||||
* @see EncodingOption
|
||||
*/
|
||||
public static String encodeUriComponent(String source,
|
||||
String encoding,
|
||||
UriComponent uriComponent,
|
||||
Set<EncodingOption> encodingOptions) throws UnsupportedEncodingException {
|
||||
Assert.hasLength(encoding, "'encoding' must not be empty");
|
||||
|
||||
byte[] bytes = encodeInternal(source.getBytes(encoding), uriComponent, allowTemplateVars);
|
||||
byte[] bytes = encodeInternal(source.getBytes(encoding), uriComponent, encodingOptions);
|
||||
return new String(bytes, "US-ASCII");
|
||||
}
|
||||
|
||||
private static byte[] encodeInternal(byte[] source, UriComponent uriComponent, boolean allowTemplateVars) {
|
||||
private static byte[] encodeInternal(byte[] source,
|
||||
UriComponent uriComponent,
|
||||
Set<EncodingOption> encodingOptions) {
|
||||
Assert.notNull(source, "'source' must not be null");
|
||||
Assert.notNull(uriComponent, "'uriComponent' must not be null");
|
||||
|
||||
if (encodingOptions == null) {
|
||||
encodingOptions = Collections.emptySet();
|
||||
}
|
||||
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream(source.length);
|
||||
for (int i = 0; i < source.length; i++) {
|
||||
int b = source[i];
|
||||
|
|
@ -531,7 +453,7 @@ public abstract class UriUtils {
|
|||
if (uriComponent.isAllowed(b)) {
|
||||
bos.write(b);
|
||||
}
|
||||
else if (allowTemplateVars && (b == '{' || b == '}')) {
|
||||
else if (encodingOptions.contains(EncodingOption.ALLOW_TEMPLATE_VARS) && (b == '{' || b == '}')) {
|
||||
bos.write(b);
|
||||
}
|
||||
else {
|
||||
|
|
@ -547,13 +469,139 @@ public abstract class UriUtils {
|
|||
return bos.toByteArray();
|
||||
}
|
||||
|
||||
// encoding convenience methods
|
||||
|
||||
/**
|
||||
* Decodes the given encoded source String into an URI. Based on the following rules: <ul> <li>Alphanumeric characters
|
||||
* {@code "a"} through {@code "z"}, {@code "A"} through {@code "Z"}, and {@code "0"} through {@code "9"} stay the same.
|
||||
* <li>Special characters {@code "-"}, {@code "_"}, {@code "."}, and {@code "*"} stay the same. <li>All other
|
||||
* characters are converted into one or more bytes using the given encoding scheme. Each of the resulting bytes is
|
||||
* written as a hexadecimal string in the {@code %xy} format. <li>A sequence "<code>%<i>xy</i></code>" is interpreted
|
||||
* as a hexadecimal representation of the character. </ul>
|
||||
* Encodes the given URI scheme with the given encoding.
|
||||
*
|
||||
* @param scheme the scheme to be encoded
|
||||
* @param encoding the character encoding to encode to
|
||||
* @return the encoded scheme
|
||||
* @throws UnsupportedEncodingException when the given encoding parameter is not supported
|
||||
*/
|
||||
public static String encodeScheme(String scheme, String encoding) throws UnsupportedEncodingException {
|
||||
return encodeUriComponent(scheme, encoding, UriComponent.SCHEME, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given URI authority with the given encoding.
|
||||
*
|
||||
* @param authority the authority to be encoded
|
||||
* @param encoding the character encoding to encode to
|
||||
* @return the encoded authority
|
||||
* @throws UnsupportedEncodingException when the given encoding parameter is not supported
|
||||
*/
|
||||
public static String encodeAuthority(String authority, String encoding) throws UnsupportedEncodingException {
|
||||
return encodeUriComponent(authority, encoding, UriComponent.AUTHORITY, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given URI user info with the given encoding.
|
||||
*
|
||||
* @param userInfo the user info to be encoded
|
||||
* @param encoding the character encoding to encode to
|
||||
* @return the encoded user info
|
||||
* @throws UnsupportedEncodingException when the given encoding parameter is not supported
|
||||
*/
|
||||
public static String encodeUserInfo(String userInfo, String encoding) throws UnsupportedEncodingException {
|
||||
return encodeUriComponent(userInfo, encoding, UriComponent.USER_INFO, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given URI host with the given encoding.
|
||||
*
|
||||
* @param host the host to be encoded
|
||||
* @param encoding the character encoding to encode to
|
||||
* @return the encoded host
|
||||
* @throws UnsupportedEncodingException when the given encoding parameter is not supported
|
||||
*/
|
||||
public static String encodeHost(String host, String encoding) throws UnsupportedEncodingException {
|
||||
return encodeUriComponent(host, encoding, UriComponent.HOST, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given URI port with the given encoding.
|
||||
*
|
||||
* @param port the port to be encoded
|
||||
* @param encoding the character encoding to encode to
|
||||
* @return the encoded port
|
||||
* @throws UnsupportedEncodingException when the given encoding parameter is not supported
|
||||
*/
|
||||
public static String encodePort(String port, String encoding) throws UnsupportedEncodingException {
|
||||
return encodeUriComponent(port, encoding, UriComponent.PORT, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given URI path with the given encoding.
|
||||
*
|
||||
* @param path the path to be encoded
|
||||
* @param encoding the character encoding to encode to
|
||||
* @return the encoded path
|
||||
* @throws UnsupportedEncodingException when the given encoding parameter is not supported
|
||||
*/
|
||||
public static String encodePath(String path, String encoding) throws UnsupportedEncodingException {
|
||||
return encodeUriComponent(path, encoding, UriComponent.PATH, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given URI path segment with the given encoding.
|
||||
*
|
||||
* @param segment the segment to be encoded
|
||||
* @param encoding the character encoding to encode to
|
||||
* @return the encoded segment
|
||||
* @throws UnsupportedEncodingException when the given encoding parameter is not supported
|
||||
*/
|
||||
public static String encodePathSegment(String segment, String encoding) throws UnsupportedEncodingException {
|
||||
return encodeUriComponent(segment, encoding, UriComponent.PATH_SEGMENT, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given URI query with the given encoding.
|
||||
*
|
||||
* @param query the query to be encoded
|
||||
* @param encoding the character encoding to encode to
|
||||
* @return the encoded query
|
||||
* @throws UnsupportedEncodingException when the given encoding parameter is not supported
|
||||
*/
|
||||
public static String encodeQuery(String query, String encoding) throws UnsupportedEncodingException {
|
||||
return encodeUriComponent(query, encoding, UriComponent.QUERY, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given URI query parameter with the given encoding.
|
||||
*
|
||||
* @param queryParam the query parameter to be encoded
|
||||
* @param encoding the character encoding to encode to
|
||||
* @return the encoded query parameter
|
||||
* @throws UnsupportedEncodingException when the given encoding parameter is not supported
|
||||
*/
|
||||
public static String encodeQueryParam(String queryParam, String encoding) throws UnsupportedEncodingException {
|
||||
return encodeUriComponent(queryParam, encoding, UriComponent.QUERY_PARAM, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given URI fragment with the given encoding.
|
||||
*
|
||||
* @param fragment the fragment to be encoded
|
||||
* @param encoding the character encoding to encode to
|
||||
* @return the encoded fragment
|
||||
* @throws UnsupportedEncodingException when the given encoding parameter is not supported
|
||||
*/
|
||||
public static String encodeFragment(String fragment, String encoding) throws UnsupportedEncodingException {
|
||||
return encodeUriComponent(fragment, encoding, UriComponent.FRAGMENT, null);
|
||||
}
|
||||
|
||||
|
||||
// decoding
|
||||
|
||||
/**
|
||||
* Decodes the given encoded source String into an URI. Based on the following rules:
|
||||
* <ul>
|
||||
* <li>Alphanumeric characters {@code "a"} through {@code "z"}, {@code "A"} through {@code "Z"}, and
|
||||
* {@code "0"} through {@code "9"} stay the same.</li>
|
||||
* <li>Special characters {@code "-"}, {@code "_"}, {@code "."}, and {@code "*"} stay the same.</li>
|
||||
* <li>A sequence "<code>%<i>xy</i></code>" is interpreted as a hexadecimal representation of the character.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param source the source string
|
||||
* @param encoding the encoding
|
||||
|
|
@ -590,4 +638,16 @@ public abstract class UriUtils {
|
|||
return changed ? new String(bos.toByteArray(), encoding) : source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumeration used to control how URIs are encoded.
|
||||
*/
|
||||
public enum EncodingOption {
|
||||
|
||||
/**
|
||||
* Allow for URI template variables to occur in the URI component (i.e. '{foo}')
|
||||
*/
|
||||
ALLOW_TEMPLATE_VARS
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,9 +19,10 @@ package org.springframework.web.util;
|
|||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
|
@ -55,11 +56,11 @@ public class UriBuilderTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
@Ignore("Working on it")
|
||||
public void templateVarsVarArgs() throws URISyntaxException {
|
||||
UriBuilder builder = UriBuilder.newInstance();
|
||||
URI result = builder.scheme("http").host("example.com").path("{foo}").build("bar");
|
||||
URI result = UriBuilder.fromPath("/{foo}/{bar}").build("baz", "qux");
|
||||
|
||||
URI expected = new URI("http://example.com/bar");
|
||||
URI expected = new URI("http://example.com/baz/qux");
|
||||
assertEquals("Invalid result URI", expected, result);
|
||||
}
|
||||
|
||||
|
|
@ -82,11 +83,11 @@ public class UriBuilderTests {
|
|||
|
||||
@Test
|
||||
public void templateVarsMap() throws URISyntaxException {
|
||||
Map<String, String> vars = Collections.singletonMap("foo", "bar");
|
||||
UriBuilder builder = UriBuilder.newInstance();
|
||||
URI result = builder.scheme("http").host("example.com").path("{foo}").build(vars);
|
||||
|
||||
URI expected = new URI("http://example.com/bar");
|
||||
Map<String, String> vars = new HashMap<String, String>(2);
|
||||
vars.put("bar", "qux");
|
||||
vars.put("foo", "baz");
|
||||
URI result = UriBuilder.fromPath("/{foo}/{bar}").build(vars);
|
||||
URI expected = new URI("/baz/qux");
|
||||
assertEquals("Invalid result URI", expected, result);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue