Bug 1870570 - Only allow exact matches for time zone and AM/PM keywords r=arai

Differential Revision: https://phabricator.services.mozilla.com/D196941
This commit is contained in:
Vinny Diehl 2023-12-21 06:57:59 +00:00
parent 5d7f90295f
commit 015bc0177d
2 changed files with 87 additions and 18 deletions

View File

@ -1093,6 +1093,23 @@ bool IsPrefixOfKeyword(const CharT* s, size_t len, const char* keyword) {
return len == 0;
}
template <typename CharT>
bool MatchesKeyword(const CharT* s, size_t len, const char* keyword) {
while (len > 0) {
MOZ_ASSERT(IsAsciiAlpha(*s));
MOZ_ASSERT(IsAsciiLowercaseAlpha(*keyword));
if (unicode::ToLowerCase(static_cast<Latin1Char>(*s)) != *keyword) {
return false;
}
++s, ++keyword;
--len;
}
return *keyword == '\0';
}
static constexpr const char* const month_prefixes[] = {
"jan", "feb", "mar", "apr", "may", "jun",
"jul", "aug", "sep", "oct", "nov", "dec",
@ -1318,19 +1335,15 @@ struct CharsAndAction {
int action;
};
static constexpr const char* const days_of_week[] = {
"monday", "tuesday", "wednesday", "thursday",
"friday", "saturday", "sunday"};
static constexpr CharsAndAction keywords[] = {
// clang-format off
// AM/PM
{ "am", -1 },
{ "pm", -2 },
// Days of week.
{ "monday", 0 },
{ "tuesday", 0 },
{ "wednesday", 0 },
{ "thursday", 0 },
{ "friday", 0 },
{ "saturday", 0 },
{ "sunday", 0 },
// Time zone abbreviations.
{ "gmt", 10000 + 0 },
{ "z", 10000 + 0 },
@ -1650,6 +1663,21 @@ static bool ParseDate(DateTimeInfo::ForceUTC forceUTC, const CharT* s,
return false;
}
// Completely ignore days of the week, and don't derive any semantics
// from them.
bool isLateWeekday = false;
for (const char* weekday : days_of_week) {
if (IsPrefixOfKeyword(s + start, index - start, weekday)) {
isLateWeekday = true;
seenLateWeekday = true;
break;
}
}
if (isLateWeekday) {
prevc = 0;
continue;
}
size_t k = std::size(keywords);
while (k-- > 0) {
// Record a month if it is a month name. Note that some numbers are
@ -1692,21 +1720,13 @@ static bool ParseDate(DateTimeInfo::ForceUTC forceUTC, const CharT* s,
const CharsAndAction& keyword = keywords[k];
// If the field isn't a prefix of the keyword (an exact match is *not*
// required), try the next one.
if (!IsPrefixOfKeyword(s + start, index - start, keyword.chars)) {
// If the field doesn't match the keyword, try the next one.
if (!MatchesKeyword(s + start, index - start, keyword.chars)) {
continue;
}
int action = keyword.action;
// Completely ignore days of the week, and don't derive any semantics
// from them.
if (action == 0) {
seenLateWeekday = true;
break;
}
if (action == 10000) {
seenGmtAbbr = true;
}

View File

@ -0,0 +1,49 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const accepted = {
"Sep 26 1995 UT": "1995-09-26T00:00:00Z",
"Sep 26 1995 UTC": "1995-09-26T00:00:00Z",
"Sep 26 1995 GMT": "1995-09-26T00:00:00Z",
"Sep 26 1995 EST": "1995-09-26T00:00:00-0500",
"Sep 26 1995 est": "1995-09-26T00:00:00-0500",
"Sep 26 1995 10:00 am": "1995-09-26T10:00:00",
"Sep 26 1995 10:00 AM": "1995-09-26T10:00:00",
"Sep 26 1995 10:00 pm": "1995-09-26T22:00:00",
"Sep 26 Thurs 1995 Mon 10:thursday:00": "1995-09-26T10:00:00",
};
const rejected = [
"Sep 26 1995 G",
"Sep 26 1995 GM",
"Sep 26 1995 E",
"Sep 26 1995 ES",
"Sep 26 1995 10:00 a",
"Sep 26 1995 10:00 p",
];
for (const [test, expected] of Object.entries(accepted)) {
const testDate = new Date(test);
const expectedDate = new Date(expected);
assertEq(
false, isNaN(testDate),
`${test} should be accepted.`
);
assertEq(
testDate.getTime(), expectedDate.getTime(),
`"${test}" should be ${expectedDate} (got ${testDate}).`
);
}
for (const reject of rejected) {
assertEq(
true, isNaN(new Date(reject)),
`"${reject}" should be rejected.`
);
}
if (typeof reportCompare === "function")
reportCompare(true, true);