diff --git a/Libraries/LibJS/Runtime/DateParser.h b/Libraries/LibJS/Runtime/DateParser.h index cc34f58df6..7a474f5502 100644 --- a/Libraries/LibJS/Runtime/DateParser.h +++ b/Libraries/LibJS/Runtime/DateParser.h @@ -6,6 +6,7 @@ #pragma once +#include #include #include #include @@ -15,8 +16,6 @@ #include #include -#include // Not included by default on macOS. - // Parse simplified ISO8601 and non-standard date formats to milliseconds // from epoch (double). Synopsis: // (1) Try to parse the string as simplified ISO8601 (case sensitive). @@ -50,6 +49,8 @@ class DateParser : public GenericLexer { public: ALWAYS_INLINE static double parse(StringView string) { + if (!string.is_ascii()) + return NAN; return DateParser(string).parse().value_or(NAN); } @@ -107,13 +108,13 @@ private: ParsedNumber result; for (; result.digits < MaxLength; ++result.digits) { - if (is_eof() || !next_is(isdigit)) + if (is_eof() || !next_is(is_ascii_digit)) return result; result.number *= 10; result.number += consume() - '0'; } - ignore_while(isdigit); + ignore_while(is_ascii_digit); return result; } @@ -331,7 +332,7 @@ private: case '(': ignore_until(')'); // Consume time zone name (Anything in brackets). ignore(); - ignore_while(isspace); + ignore_while(is_ascii_space); return true; } @@ -342,7 +343,7 @@ private: { VERIFY(m_hours.has_value()); - consume_while(isspace); + consume_while(is_ascii_space); if (consume_specific("AM"sv)) { if (!separator()) @@ -588,7 +589,7 @@ private: m_timezone_utc = true; - bool space = consume_while(isspace).length() > 0; + bool space = consume_while(is_ascii_space).length() > 0; switch (peek()) { case '+': case '-': @@ -622,7 +623,7 @@ private: if (str[i] != peek(i)) return false; - ignore_while(isalpha); // ... which can followed by anything. Just like Firefox and Chrome. + ignore_while(is_ascii_alpha); // ... which can followed by anything. Just like Firefox and Chrome. m_month = month; return separator(); // Must end with a separator. @@ -630,7 +631,7 @@ private: ALWAYS_INLINE bool word() // Alphanumeric strings that are not date "keywords". { - consume_while(isalpha); + consume_while(is_ascii_alpha); // Just like Firefox and Chrome: // - Ignore junk (bare words) at the beginning (before time or a date fragment has been read). // - Fail if a word is read later in the date string (exception: final time zone name, in brackets). diff --git a/Tests/LibJS/Runtime/builtins/Date/Date.parse.nonStandard.js b/Tests/LibJS/Runtime/builtins/Date/Date.parse.nonStandard.js index c12a381431..1b3ecf7cf1 100644 --- a/Tests/LibJS/Runtime/builtins/Date/Date.parse.nonStandard.js +++ b/Tests/LibJS/Runtime/builtins/Date/Date.parse.nonStandard.js @@ -698,3 +698,13 @@ test("multiple month names", () => { setTimeZone(originalTimeZone); }); + +test("non-ASCII input", () => { + expect(Date.parse("2024\uff01")).toBeNaN(); + expect(Date.parse("1234567\uff01")).toBeNaN(); + expect(Date.parse("Jan\uff01 01 2024")).toBeNaN(); + expect(Date.parse("hello\uff01 Jan 01 2024")).toBeNaN(); + expect(Date.parse("Jan 01 2024 12:34\u00a0PM")).toBeNaN(); + expect(Date.parse("Jan 01 2024 GMT\u00a0")).toBeNaN(); + expect(Date.parse("Jan 01 2024 (UTC)\u00a0")).toBeNaN(); +});