|
|
|
|
@ -36,13 +36,13 @@ import org.springframework.util.Assert;
@@ -36,13 +36,13 @@ import org.springframework.util.Assert;
|
|
|
|
|
* </ul> |
|
|
|
|
* |
|
|
|
|
* @author Arjen Poutsma |
|
|
|
|
* @since 3.0 |
|
|
|
|
* @see <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a> |
|
|
|
|
* @since 3.0 |
|
|
|
|
*/ |
|
|
|
|
public abstract class UriUtils { |
|
|
|
|
|
|
|
|
|
private static final BitSet SCHEME; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static final BitSet USER_INFO; |
|
|
|
|
|
|
|
|
|
private static final BitSet HOST; |
|
|
|
|
@ -61,6 +61,8 @@ public abstract class UriUtils {
@@ -61,6 +61,8 @@ 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 = "([^/?#:]*)"; |
|
|
|
|
@ -71,15 +73,16 @@ public abstract class UriUtils {
@@ -71,15 +73,16 @@ public abstract class UriUtils {
|
|
|
|
|
|
|
|
|
|
private static final String QUERY_PATTERN = "([^#]*)"; |
|
|
|
|
|
|
|
|
|
private static final String FRAGMENT_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 + ")?" + |
|
|
|
|
"(#" + FRAGMENT_PATTERN + ")?"); |
|
|
|
|
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 + ")?"); |
|
|
|
|
|
|
|
|
|
static { |
|
|
|
|
// variable names refer to RFC 3986, appendix A
|
|
|
|
|
@ -181,10 +184,10 @@ public abstract class UriUtils {
@@ -181,10 +184,10 @@ public abstract class UriUtils {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Encodes the given source URI into an encoded String. All various URI components are encoded according to |
|
|
|
|
* their respective valid character sets. |
|
|
|
|
* Encodes the given source URI into an encoded String. All various URI components are encoded according to their |
|
|
|
|
* respective valid character sets. |
|
|
|
|
* |
|
|
|
|
* @param uri the URI to be encoded |
|
|
|
|
* @param uri the URI to be encoded |
|
|
|
|
* @param encoding the character encoding to encode to |
|
|
|
|
* @return the encoded URI |
|
|
|
|
* @throws IllegalArgumentException when the given uri parameter is not a valid URI |
|
|
|
|
@ -204,50 +207,115 @@ public abstract class UriUtils {
@@ -204,50 +207,115 @@ public abstract class UriUtils {
|
|
|
|
|
String query = m.group(11); |
|
|
|
|
String fragment = m.group(13); |
|
|
|
|
|
|
|
|
|
StringBuilder sb = new StringBuilder(); |
|
|
|
|
return encodeUriComponents(scheme, authority, userinfo, host, port, path, query, fragment, encoding); |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
throw new IllegalArgumentException("[" + uri + "] is not a valid URI"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (scheme != null) { |
|
|
|
|
sb.append(encodeScheme(scheme, encoding)); |
|
|
|
|
sb.append(':'); |
|
|
|
|
} |
|
|
|
|
/** |
|
|
|
|
* Encodes the given HTTP URI into an encoded String. All various URI components are encoded according to their |
|
|
|
|
* respective valid character sets. |
|
|
|
|
* |
|
|
|
|
* <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. |
|
|
|
|
* |
|
|
|
|
* @param httpUrl the HTTP URL to be encoded |
|
|
|
|
* @param encoding the character encoding to encode to |
|
|
|
|
* @return the encoded URL |
|
|
|
|
* @throws IllegalArgumentException when the given uri parameter is not a valid URI |
|
|
|
|
* @throws UnsupportedEncodingException when the given encoding parameter is not supported |
|
|
|
|
*/ |
|
|
|
|
public static String encodeHttpUrl(String httpUrl, String encoding) throws UnsupportedEncodingException { |
|
|
|
|
Assert.notNull(httpUrl, "'httpUrl' must not be null"); |
|
|
|
|
Assert.hasLength(encoding, "'encoding' must not be empty"); |
|
|
|
|
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"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
/** |
|
|
|
|
* Encodes the given source URI components into an encoded String. All various URI components are optional, but encoded according |
|
|
|
|
* to their respective valid character sets. |
|
|
|
|
* |
|
|
|
|
* @param scheme the scheme |
|
|
|
|
* @param authority the authority |
|
|
|
|
* @param userinfo the user info |
|
|
|
|
* @param host the host |
|
|
|
|
* @param port the port |
|
|
|
|
* @param path the path |
|
|
|
|
* @param query the query |
|
|
|
|
* @param fragment the fragment |
|
|
|
|
* @param encoding the character encoding to encode to |
|
|
|
|
* @return the encoded URI |
|
|
|
|
* @throws IllegalArgumentException when the given uri parameter is not a valid URI |
|
|
|
|
* @throws UnsupportedEncodingException when the given encoding parameter is not supported |
|
|
|
|
*/ |
|
|
|
|
public static String encodeUriComponents(String scheme, |
|
|
|
|
String authority, |
|
|
|
|
String userinfo, |
|
|
|
|
String host, |
|
|
|
|
String port, |
|
|
|
|
String path, |
|
|
|
|
String query, |
|
|
|
|
String fragment, |
|
|
|
|
String encoding) throws UnsupportedEncodingException { |
|
|
|
|
|
|
|
|
|
Assert.hasLength(encoding, "'encoding' must not be empty"); |
|
|
|
|
StringBuilder sb = new StringBuilder(); |
|
|
|
|
|
|
|
|
|
sb.append(encodePath(path, encoding)); |
|
|
|
|
if (scheme != null) { |
|
|
|
|
sb.append(encodeScheme(scheme, encoding)); |
|
|
|
|
sb.append(':'); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (query != null) { |
|
|
|
|
sb.append('?'); |
|
|
|
|
sb.append(encodeQuery(query, encoding)); |
|
|
|
|
if (authority != null) { |
|
|
|
|
sb.append("//"); |
|
|
|
|
if (userinfo != null) { |
|
|
|
|
sb.append(encodeUserInfo(userinfo, encoding)); |
|
|
|
|
sb.append('@'); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (fragment != null) { |
|
|
|
|
sb.append('#'); |
|
|
|
|
sb.append(encodeFragment(fragment, encoding)); |
|
|
|
|
if (host != null) { |
|
|
|
|
sb.append(encodeHost(host, encoding)); |
|
|
|
|
} |
|
|
|
|
if (port != null) { |
|
|
|
|
sb.append(':'); |
|
|
|
|
sb.append(encodePort(port, encoding)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return sb.toString(); |
|
|
|
|
} else { |
|
|
|
|
throw new IllegalArgumentException("[" + uri + "] is not a valid URI"); |
|
|
|
|
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(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Encodes the given URI scheme. |
|
|
|
|
* |
|
|
|
|
* @param scheme the scheme to be encoded |
|
|
|
|
* @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 |
|
|
|
|
@ -271,7 +339,7 @@ public abstract class UriUtils {
@@ -271,7 +339,7 @@ public abstract class UriUtils {
|
|
|
|
|
/** |
|
|
|
|
* Encodes the given URI host. |
|
|
|
|
* |
|
|
|
|
* @param host the host to be encoded |
|
|
|
|
* @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 |
|
|
|
|
@ -283,7 +351,7 @@ public abstract class UriUtils {
@@ -283,7 +351,7 @@ public abstract class UriUtils {
|
|
|
|
|
/** |
|
|
|
|
* Encodes the given URI port. |
|
|
|
|
* |
|
|
|
|
* @param port the port to be encoded |
|
|
|
|
* @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 |
|
|
|
|
@ -295,7 +363,7 @@ public abstract class UriUtils {
@@ -295,7 +363,7 @@ public abstract class UriUtils {
|
|
|
|
|
/** |
|
|
|
|
* Encodes the given URI path. |
|
|
|
|
* |
|
|
|
|
* @param path the path to be encoded |
|
|
|
|
* @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 |
|
|
|
|
@ -307,7 +375,7 @@ public abstract class UriUtils {
@@ -307,7 +375,7 @@ public abstract class UriUtils {
|
|
|
|
|
/** |
|
|
|
|
* Encodes the given URI path segment. |
|
|
|
|
* |
|
|
|
|
* @param segment the segment to be encoded |
|
|
|
|
* @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 |
|
|
|
|
@ -319,7 +387,7 @@ public abstract class UriUtils {
@@ -319,7 +387,7 @@ public abstract class UriUtils {
|
|
|
|
|
/** |
|
|
|
|
* Encodes the given URI query. |
|
|
|
|
* |
|
|
|
|
* @param query the query to be encoded |
|
|
|
|
* @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 |
|
|
|
|
@ -332,7 +400,7 @@ public abstract class UriUtils {
@@ -332,7 +400,7 @@ public abstract class UriUtils {
|
|
|
|
|
* Encodes the given URI query parameter. |
|
|
|
|
* |
|
|
|
|
* @param queryParam the query parameter to be encoded |
|
|
|
|
* @param encoding the character encoding to encode to |
|
|
|
|
* @param encoding the character encoding to encode to |
|
|
|
|
* @return the encoded query parameter |
|
|
|
|
* @throws UnsupportedEncodingException when the given encoding parameter is not supported |
|
|
|
|
*/ |
|
|
|
|
@ -352,7 +420,8 @@ public abstract class UriUtils {
@@ -352,7 +420,8 @@ public abstract class UriUtils {
|
|
|
|
|
return encode(fragment, encoding, FRAGMENT); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private static String encode(String source, String encoding, BitSet notEncoded) throws UnsupportedEncodingException { |
|
|
|
|
private static String encode(String source, String encoding, BitSet notEncoded) |
|
|
|
|
throws UnsupportedEncodingException { |
|
|
|
|
Assert.notNull(source, "'source' must not be null"); |
|
|
|
|
Assert.hasLength(encoding, "'encoding' must not be empty"); |
|
|
|
|
ByteArrayOutputStream bos = new ByteArrayOutputStream(source.length() * 2); |
|
|
|
|
@ -388,8 +457,9 @@ public abstract class UriUtils {
@@ -388,8 +457,9 @@ public abstract class UriUtils {
|
|
|
|
|
* <li>A sequence "<code>%<i>xy</i></code>" is interpreted as a hexadecimal |
|
|
|
|
* representation of the character. |
|
|
|
|
* </ul> |
|
|
|
|
* @param source |
|
|
|
|
* @param encoding |
|
|
|
|
* |
|
|
|
|
* @param source the source string |
|
|
|
|
* @param encoding the encoding |
|
|
|
|
* @return the decoded URI |
|
|
|
|
* @throws UnsupportedEncodingException when the given encoding parameter is not supported |
|
|
|
|
* @see java.net.URLDecoder#decode(String, String) |
|
|
|
|
|