From ea9075305900a8a017cb32e4a8c07925d7a605a9 Mon Sep 17 00:00:00 2001 From: Hanabi <317387557+Hanabi9248@users.noreply.github.com> Date: Mon, 26 Oct 2026 13:26:01 +0800 Subject: [PATCH] fix: separate Base64 text encoding from payload charset Use ASCII for the Base64 carrier in basic and URL-safe string codecs. Keep the requested charset for original and recovered payload bytes. Add UTF-16 interoperability and round-trip regressions with UTF-8 and Latin-1 controls against the complete production class. Signed-off-by: Hanabi <317387557+Hanabi9248@users.noreply.github.com> --- .../highgo/cloud/util/toolkit/Base64Util.java | 10 ++- tests/Base64CharsetRegression.java | 79 +++++++++++++++++++ 2 files changed, 85 insertions(+), 4 deletions(-) create mode 100644 tests/Base64CharsetRegression.java diff --git a/common/src/main/java/com/highgo/cloud/util/toolkit/Base64Util.java b/common/src/main/java/com/highgo/cloud/util/toolkit/Base64Util.java index 5901592..f61b05d 100644 --- a/common/src/main/java/com/highgo/cloud/util/toolkit/Base64Util.java +++ b/common/src/main/java/com/highgo/cloud/util/toolkit/Base64Util.java @@ -19,6 +19,8 @@ import com.highgo.cloud.util.toolkit.support.Charsets; +import java.nio.charset.StandardCharsets; + /** * Base64工具 * @@ -45,7 +47,7 @@ public static String encode(String value) { */ public static String encode(String value, java.nio.charset.Charset charset) { byte[] val = value.getBytes(charset); - return new String(Base64Util.encode(val), charset); + return new String(Base64Util.encode(val), StandardCharsets.US_ASCII); } /** @@ -67,7 +69,7 @@ public static String encodeUrlSafe(String value) { */ public static String encodeUrlSafe(String value, java.nio.charset.Charset charset) { byte[] val = value.getBytes(charset); - return new String(Base64Util.encodeUrlSafe(val), charset); + return new String(Base64Util.encodeUrlSafe(val), StandardCharsets.US_ASCII); } /** @@ -88,7 +90,7 @@ public static String decode(String value) { * @return {String} */ public static String decode(String value, java.nio.charset.Charset charset) { - byte[] val = value.getBytes(charset); + byte[] val = value.getBytes(StandardCharsets.US_ASCII); byte[] decodedValue = Base64Util.decode(val); return new String(decodedValue, charset); } @@ -111,7 +113,7 @@ public static String decodeUrlSafe(String value) { * @return {String} */ public static String decodeUrlSafe(String value, java.nio.charset.Charset charset) { - byte[] val = value.getBytes(charset); + byte[] val = value.getBytes(StandardCharsets.US_ASCII); byte[] decodedValue = Base64Util.decodeUrlSafe(val); return new String(decodedValue, charset); } diff --git a/tests/Base64CharsetRegression.java b/tests/Base64CharsetRegression.java new file mode 100644 index 0000000..73db684 --- /dev/null +++ b/tests/Base64CharsetRegression.java @@ -0,0 +1,79 @@ +import com.highgo.cloud.util.toolkit.Base64Util; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.Base64; + +/** Calls the complete production codec; JDK Base64 is the independent oracle. */ +public final class Base64CharsetRegression { + private static int failures; + + private interface CheckedCase { + void run(); + } + + private static void check(String name, CheckedCase test) { + try { + test.run(); + System.out.println("PASS " + name); + } catch (RuntimeException | AssertionError failure) { + failures++; + System.err.println("FAIL " + name + ": " + failure); + } + } + + private static void equal(String expected, String actual) { + if (!expected.equals(actual)) { + throw new AssertionError("expected <" + expected + "> but was <" + actual + ">"); + } + } + + private static String expected(String payload, Charset charset, boolean urlSafe) { + Base64.Encoder encoder = urlSafe ? Base64.getUrlEncoder() : Base64.getEncoder(); + return encoder.encodeToString(payload.getBytes(charset)); + } + + private static String encode(String payload, Charset charset, boolean urlSafe) { + return urlSafe ? Base64Util.encodeUrlSafe(payload, charset) : Base64Util.encode(payload, charset); + } + + private static String decode(String encoded, Charset charset, boolean urlSafe) { + return urlSafe ? Base64Util.decodeUrlSafe(encoded, charset) : Base64Util.decode(encoded, charset); + } + + private static void runMode(boolean urlSafe) { + String prefix = urlSafe ? "url-safe-" : "basic-"; + check(prefix + "UTF16-ASCII-carrier", () -> + equal(expected("A", StandardCharsets.UTF_16, urlSafe), + encode("A", StandardCharsets.UTF_16, urlSafe))); + check(prefix + "UTF16-canonical-decode", () -> + equal("A", decode(expected("A", StandardCharsets.UTF_16, urlSafe), + StandardCharsets.UTF_16, urlSafe))); + check(prefix + "UTF16-round-trip", () -> + equal("A", decode(encode("A", StandardCharsets.UTF_16, urlSafe), + StandardCharsets.UTF_16, urlSafe))); + check(prefix + "UTF16LE-ASCII-carrier", () -> + equal(expected("A", StandardCharsets.UTF_16LE, urlSafe), + encode("A", StandardCharsets.UTF_16LE, urlSafe))); + check(prefix + "default-UTF8-control", () -> { + String payload = "\u4e2d\u6587"; + String encoded = urlSafe ? Base64Util.encodeUrlSafe(payload) : Base64Util.encode(payload); + equal(expected(payload, StandardCharsets.UTF_8, urlSafe), encoded); + equal(payload, urlSafe ? Base64Util.decodeUrlSafe(encoded) : Base64Util.decode(encoded)); + }); + check(prefix + "explicit-Latin1-control", () -> { + String payload = "caf\u00e9"; + String encoded = encode(payload, StandardCharsets.ISO_8859_1, urlSafe); + equal(expected(payload, StandardCharsets.ISO_8859_1, urlSafe), encoded); + equal(payload, decode(encoded, StandardCharsets.ISO_8859_1, urlSafe)); + }); + } + + public static void main(String[] args) { + runMode(false); + runMode(true); + if (failures != 0) { + throw new AssertionError(failures + " codec cases failed"); + } + } +} +