This is an automated email from the ASF dual-hosted git repository. yuzelin pushed a commit to branch release-1.4 in repository https://gitbox.apache.org/repos/asf/paimon.git
commit de76b56763d01ace65a450f72ce088cc49606857 Author: Jiajia Li <[email protected]> AuthorDate: Thu Apr 2 13:43:42 2026 +0800 [api] Fix locale-sensitive date formatting in DLFOpenApiSigner (#7577) Pin DateTimeFormatter to Locale.ENGLISH so RFC 1123 date headers are always in English regardless of JVM default locale. Add tests for Chinese and Japanese locales. Fix locale-sensitive date formatting in `DLFOpenApiSigner`. The `DateTimeFormatter` for RFC 1123 dates was not pinned to `Locale.ENGLISH`, causing day/month names to be localized on non-English JVM locales (e.g. zh_CN, ja_JP), which breaks the Aliyun OpenAPI signature. --- .../apache/paimon/rest/auth/DLFOpenApiSigner.java | 3 +- .../paimon/rest/auth/DLFRequestSignerTest.java | 41 ++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/paimon-api/src/main/java/org/apache/paimon/rest/auth/DLFOpenApiSigner.java b/paimon-api/src/main/java/org/apache/paimon/rest/auth/DLFOpenApiSigner.java index 80f8761850..aaf3713828 100644 --- a/paimon-api/src/main/java/org/apache/paimon/rest/auth/DLFOpenApiSigner.java +++ b/paimon-api/src/main/java/org/apache/paimon/rest/auth/DLFOpenApiSigner.java @@ -31,6 +31,7 @@ import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.util.Base64; import java.util.HashMap; +import java.util.Locale; import java.util.Map; import java.util.TreeMap; import java.util.UUID; @@ -65,7 +66,7 @@ public class DLFOpenApiSigner implements DLFRequestSigner { private static final String API_VERSION = "2026-01-18"; private static final DateTimeFormatter GMT_DATE_FORMATTER = - DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss 'GMT'") + DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss 'GMT'", Locale.ENGLISH) .withZone(ZoneId.of("GMT")); @Override diff --git a/paimon-api/src/test/java/org/apache/paimon/rest/auth/DLFRequestSignerTest.java b/paimon-api/src/test/java/org/apache/paimon/rest/auth/DLFRequestSignerTest.java index ef9d44aa5e..e1b67e3a9e 100644 --- a/paimon-api/src/test/java/org/apache/paimon/rest/auth/DLFRequestSignerTest.java +++ b/paimon-api/src/test/java/org/apache/paimon/rest/auth/DLFRequestSignerTest.java @@ -26,6 +26,7 @@ import java.time.ZonedDateTime; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.concurrent.CountDownLatch; @@ -274,6 +275,46 @@ public class DLFRequestSignerTest { assertEquals("2026-01-18", headers.get("x-acs-version")); } + @Test + public void testOpenApiDateFormatWithNonEnglishLocale() { + Locale originalLocale = Locale.getDefault(); + try { + // Simulate Chinese locale environment (e.g., zh_CN, zh_US_#Hans) + Locale.setDefault(Locale.CHINA); + + DLFOpenApiSigner signer = new DLFOpenApiSigner(); + Instant now = ZonedDateTime.of(2025, 4, 16, 3, 44, 46, 0, ZoneOffset.UTC).toInstant(); + String host = "dlfnext.cn-hangzhou.aliyuncs.com"; + + Map<String, String> headers = signer.signHeaders(null, now, null, host); + String dateValue = headers.get("Date"); + + // Date must always be in English RFC 1123 format regardless of JVM locale + assertEquals("Wed, 16 Apr 2025 03:44:46 GMT", dateValue); + } finally { + Locale.setDefault(originalLocale); + } + } + + @Test + public void testOpenApiDateFormatWithJapaneseLocale() { + Locale originalLocale = Locale.getDefault(); + try { + Locale.setDefault(Locale.JAPAN); + + DLFOpenApiSigner signer = new DLFOpenApiSigner(); + Instant now = ZonedDateTime.of(2025, 4, 16, 3, 44, 46, 0, ZoneOffset.UTC).toInstant(); + String host = "dlfnext.cn-hangzhou.aliyuncs.com"; + + Map<String, String> headers = signer.signHeaders(null, now, null, host); + String dateValue = headers.get("Date"); + + assertEquals("Wed, 16 Apr 2025 03:44:46 GMT", dateValue); + } finally { + Locale.setDefault(originalLocale); + } + } + @Test public void testConcurrentNonceGeneration() throws InterruptedException { DLFOpenApiSigner signer = new DLFOpenApiSigner();
