Refine StringUtils#uriDecode and update documentation
This commit adds another optimization mainly for the use case where there is no encoded sequence, and updates the Javadoc of both StringUtils#uriDecode and UriUtils#decode to match the implementation. Closes gh-34673
This commit is contained in:
@@ -800,32 +800,27 @@ public abstract class StringUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 "<i>{@code %xy}</i>" is interpreted as a hexadecimal representation of the character.</li>
|
||||
* <li>For all other characters (including those already decoded), the output is undefined.</li>
|
||||
* </ul>
|
||||
* @param source the encoded String
|
||||
* @param charset the character set
|
||||
* Decode the given encoded URI component value by replacing "<i>{@code %xy}</i>" sequences
|
||||
* by an hexadecimal representation of the character in the specified charset, letting other
|
||||
* characters unchanged.
|
||||
* @param source the encoded {@code String}
|
||||
* @param charset the character encoding to use to decode the "<i>{@code %xy}</i>" sequences
|
||||
* @return the decoded value
|
||||
* @throws IllegalArgumentException when the given source contains invalid encoded sequences
|
||||
* @since 5.0
|
||||
* @see java.net.URLDecoder#decode(String, String)
|
||||
* @see java.net.URLDecoder#decode(String, String) java.net.URLDecoder#decode for HTML form decoding
|
||||
*/
|
||||
public static String uriDecode(String source, Charset charset) {
|
||||
Assert.notNull(charset, "Charset must not be null");
|
||||
int length = source.length();
|
||||
if (length == 0) {
|
||||
int firstPercentIndex = source.indexOf('%');
|
||||
if (length == 0 || firstPercentIndex < 0) {
|
||||
return source;
|
||||
}
|
||||
|
||||
StringBuilder output = new StringBuilder(length);
|
||||
boolean changed = false;
|
||||
output.append(source, 0, firstPercentIndex);
|
||||
byte[] bytes = null;
|
||||
int i = 0;
|
||||
int i = firstPercentIndex;
|
||||
while (i < length) {
|
||||
char ch = source.charAt(i);
|
||||
if (ch == '%') {
|
||||
@@ -848,7 +843,6 @@ public abstract class StringUtils {
|
||||
}
|
||||
|
||||
output.append(new String(bytes, 0, pos, charset));
|
||||
changed = true;
|
||||
}
|
||||
catch (NumberFormatException ex) {
|
||||
throw new IllegalArgumentException("Invalid encoded sequence \"" + source.substring(i) + "\"");
|
||||
@@ -859,7 +853,7 @@ public abstract class StringUtils {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return (changed ? output.toString() : source);
|
||||
return output.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2025 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.
|
||||
@@ -374,15 +374,16 @@ public abstract class UriUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode the given encoded URI component.
|
||||
* <p>See {@link StringUtils#uriDecode(String, Charset)} for the decoding rules.
|
||||
* @param source the encoded String
|
||||
* @param charset the character encoding to use
|
||||
* Decode the given encoded URI component value by replacing "<i>{@code %xy}</i>" sequences
|
||||
* by an hexadecimal representation of the character in the specified charset, letting other
|
||||
* characters unchanged.
|
||||
* @param source the encoded {@code String}
|
||||
* @param charset the character encoding to use to decode the "<i>{@code %xy}</i>" sequences
|
||||
* @return the decoded value
|
||||
* @throws IllegalArgumentException when the given source contains invalid encoded sequences
|
||||
* @since 5.0
|
||||
* @see StringUtils#uriDecode(String, Charset)
|
||||
* @see java.net.URLDecoder#decode(String, String)
|
||||
* @see java.net.URLDecoder#decode(String, String) java.net.URLDecoder#decode for HTML form decoding
|
||||
*/
|
||||
public static String decode(String source, Charset charset) {
|
||||
return StringUtils.uriDecode(source, charset);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2025 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.
|
||||
@@ -108,6 +108,8 @@ class UriUtilsTests {
|
||||
assertThat(UriUtils.decode("/Z%C3%BCrich", CHARSET)).as("Invalid encoded result").isEqualTo("/Z\u00fcrich");
|
||||
assertThat(UriUtils.decode("T\u014dky\u014d", CHARSET)).as("Invalid encoded result").isEqualTo("T\u014dky\u014d");
|
||||
assertThat(UriUtils.decode("%20\u2019", CHARSET)).as("Invalid encoded result").isEqualTo(" \u2019");
|
||||
assertThat(UriUtils.decode("\u015bp\u0159\u00ec\u0144\u0121", CHARSET)).as("Invalid encoded result").isEqualTo("śpřìńġ");
|
||||
assertThat(UriUtils.decode("%20\u015bp\u0159\u00ec\u0144\u0121", CHARSET)).as("Invalid encoded result").isEqualTo(" śpřìńġ");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user