Revised Charset handling and common StringUtils.uriDecode delegate

Issue: SPR-14492
This commit is contained in:
Juergen Hoeller
2017-01-18 00:09:06 +01:00
parent 8417831602
commit d21b6e596f
7 changed files with 131 additions and 144 deletions

View File

@@ -16,6 +16,8 @@
package org.springframework.util;
import java.io.ByteArrayOutputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -690,6 +692,59 @@ public abstract class StringUtils {
return cleanPath(path1).equals(cleanPath(path2));
}
/**
* Decode the given encoded URI component value. 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>}" is interpreted as a hexadecimal representation of the character.</li>
* </ul>
* @param source the encoded String (may be {@code null})
* @param charset the character set
* @return the decoded value
* @throws IllegalArgumentException when the given source contains invalid encoded sequences
* @since 5.0
* @see java.net.URLDecoder#decode(String, String)
*/
public static String uriDecode(String source, Charset charset) {
if (source == null) {
return null;
}
int length = source.length();
if (length == 0) {
return source;
}
Assert.notNull(charset, "Charset must not be null");
ByteArrayOutputStream bos = new ByteArrayOutputStream(length);
boolean changed = false;
for (int i = 0; i < length; i++) {
int ch = source.charAt(i);
if (ch == '%') {
if (i + 2 < length) {
char hex1 = source.charAt(i + 1);
char hex2 = source.charAt(i + 2);
int u = Character.digit(hex1, 16);
int l = Character.digit(hex2, 16);
if (u == -1 || l == -1) {
throw new IllegalArgumentException("Invalid encoded sequence \"" + source.substring(i) + "\"");
}
bos.write((char) ((u << 4) + l));
i += 2;
changed = true;
}
else {
throw new IllegalArgumentException("Invalid encoded sequence \"" + source.substring(i) + "\"");
}
}
else {
bos.write(ch);
}
}
return (changed ? new String(bos.toByteArray(), charset) : source);
}
/**
* Parse the given {@code localeString} value into a {@link Locale}.
* <p>This is the inverse operation of {@link Locale#toString Locale's toString}.