Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions user/src/com/google/gwt/i18n/server/GwtLocaleFactoryImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,19 @@ private static boolean isDigit(String str, int min, int max) {
return matches(str, min, max, false);
}

private static boolean isAlphaNumeric(String str, int min, int max) {
int len = str.length();
if (len < min || len > max) {
return false;
}
for (int i = 0; i < len; ++i) {
if (!Character.isLetterOrDigit(str.charAt(i))) {
return false;
}
}
return true;
}

/**
* Check if the supplied string matches length and composition requirements.
*
Expand Down Expand Up @@ -143,6 +156,14 @@ public GwtLocale fromString(String localeName) {
ArrayList<String> localeParts = new ArrayList<String>();
String[] parts = localeName.split("[-_]");
for (int i = 0; i < parts.length; ++i) {
// The split only breaks on '-'/'_', so any other character stays inside
// a part. Require each subtag to be alphanumeric and 1-8 chars, matching
// BCP47, so an untrusted server-side locale can't smuggle '.', '$' or
// '/' into the class name LocalizableInstantiator resolves reflectively.
if (!isAlphaNumeric(parts[i], 1, 8)) {
throw new IllegalArgumentException("Unrecognized locale format: "
+ localeName);
}
if (parts[i].length() == 1 && i + 1 < parts.length) {
localeParts.add(parts[i] + '-' + parts[++i]);
} else {
Expand Down
22 changes: 22 additions & 0 deletions user/test/com/google/gwt/i18n/server/GwtLocaleTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,28 @@
}
}

public void testFromStringRejectsInvalidLanguage() {
// The language subtag is concatenated into class names resolved reflectively
// on the server, so it must not carry characters like '.', '$' or '/'.
String[] invalid = {
"com.google.gwt.dev.Compiler", "java.lang.Runtime", "x$Evil", "a/b/c",
"en.US",
};
for (String locale : invalid) {
try {
factory.fromString(locale);
fail("Should have thrown IllegalArgumentException on " + locale);
} catch (IllegalArgumentException expected) {

Check warning on line 188 in user/test/com/google/gwt/i18n/server/GwtLocaleTest.java

View workflow job for this annotation

GitHub Actions / build (21)

[] reported by reviewdog 🐶 [EmptyCatch] Caught exceptions should not be ignored Raw Output: [javac] /home/runner/work/gwt/gwt/gwt/user/test/com/google/gwt/i18n/server/GwtLocaleTest.java:188: warning: [EmptyCatch] Caught exceptions should not be ignored
}
}
// Well-formed tags, including extended-language and private-use forms, are
// still accepted with the language preserved verbatim.
assertEquals("en", factory.fromString("en_US").getLanguage());
assertEquals("zh-cmn", factory.fromString("zh-cmn").getLanguage());
assertEquals("i-klingon", factory.fromString("i-klingon").getLanguage());
assertEquals("x-foo123", factory.fromString("x-foo123").getLanguage());
}

public void testInheritance() {
GwtLocale en = factory.fromString("en_Latn_US_VARIANT");
List<GwtLocale> chain = en.getInheritanceChain();
Expand Down
Loading