mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-28 11:49:44 +00:00
LibWeb/HTML: Handle missing second component in datetime-local
We were previously not checking for EOF which meant we were not handling seconds being missing in the time component.
This commit is contained in:
parent
a457ebeec5
commit
894c51e8e7
Notes:
github-actions[bot]
2025-03-18 19:06:05 +00:00
Author: https://github.com/shannonbooth
Commit: 894c51e8e7
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3981
Reviewed-by: https://github.com/trflynn89 ✅
3 changed files with 46 additions and 37 deletions
|
@ -414,13 +414,16 @@ static Optional<HourMinuteSecond> parse_a_time_component(GenericLexer& input)
|
||||||
if (!maybe_hour.has_value())
|
if (!maybe_hour.has_value())
|
||||||
return {};
|
return {};
|
||||||
auto hour = maybe_hour.value();
|
auto hour = maybe_hour.value();
|
||||||
|
|
||||||
// 2. If hour is not a number in the range 0 ≤ hour ≤ 23, then fail.
|
// 2. If hour is not a number in the range 0 ≤ hour ≤ 23, then fail.
|
||||||
if (hour < 0 || hour > 23)
|
if (hour < 0 || hour > 23)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
// 3. If position is beyond the end of input or if the character at position is not a U+003A COLON character, then
|
// 3. If position is beyond the end of input or if the character at position is not a U+003A COLON character, then
|
||||||
// fail. Otherwise, move position forwards one character.
|
// fail. Otherwise, move position forwards one character.
|
||||||
if (!input.consume_specific(':'))
|
if (!input.consume_specific(':'))
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
// 4. Collect a sequence of code points that are ASCII digits from input given position. If the collected sequence
|
// 4. Collect a sequence of code points that are ASCII digits from input given position. If the collected sequence
|
||||||
// is not exactly two characters long, then fail. Otherwise, interpret the resulting sequence as a base-ten integer.
|
// is not exactly two characters long, then fail. Otherwise, interpret the resulting sequence as a base-ten integer.
|
||||||
// Let that number be the minute.
|
// Let that number be the minute.
|
||||||
|
@ -431,44 +434,50 @@ static Optional<HourMinuteSecond> parse_a_time_component(GenericLexer& input)
|
||||||
if (!maybe_minute.has_value())
|
if (!maybe_minute.has_value())
|
||||||
return {};
|
return {};
|
||||||
auto minute = maybe_minute.value();
|
auto minute = maybe_minute.value();
|
||||||
|
|
||||||
// 5. If minute is not a number in the range 0 ≤ minute ≤ 59, then fail.
|
// 5. If minute is not a number in the range 0 ≤ minute ≤ 59, then fail.
|
||||||
if (minute < 0 || hour > 59)
|
if (minute < 0 || hour > 59)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
// 6. Let second be 0.
|
// 6. Let second be 0.
|
||||||
i32 second = 0;
|
i32 second = 0;
|
||||||
|
|
||||||
// 7. If position is not beyond the end of input and the character at position is U+003A (:), then:
|
// 7. If position is not beyond the end of input and the character at position is U+003A (:), then:
|
||||||
if (!input.consume_specific(':'))
|
if (input.consume_specific(':')) {
|
||||||
return {};
|
// 1. Advance position to the next character in input.
|
||||||
// 7.1. Advance position to the next character in input.
|
// 2. If position is beyond the end of input, or at the last character in input, or if the next two characters in
|
||||||
// 7.2. If position is beyond the end of input, or at the last character in input, or if the next two characters in
|
// input starting at position are not both ASCII digits, then fail.
|
||||||
// input starting at position are not both ASCII digits, then fail.
|
if (input.is_eof() || input.tell_remaining() == 1 || (!is_ascii_digit(input.peek()) && !is_ascii_digit(input.peek(1))))
|
||||||
if (input.is_eof() || input.tell_remaining() == 1 || (!is_ascii_digit(input.peek()) && !is_ascii_digit(input.peek(1))))
|
return {};
|
||||||
return {};
|
|
||||||
// 7.3. Collect a sequence of code points that are either ASCII digits or U+002E FULL STOP characters from input
|
// 3. Collect a sequence of code points that are either ASCII digits or U+002E FULL STOP characters from input
|
||||||
// given position.
|
// given position.
|
||||||
auto second_string = input.consume_while([](auto ch) { return is_ascii_digit(ch) || ch == '.'; });
|
auto second_string = input.consume_while([](auto ch) { return is_ascii_digit(ch) || ch == '.'; });
|
||||||
// If the collected sequence is three characters long, or if it is longer than three characters long and the third
|
// If the collected sequence is three characters long, or if it is longer than three characters long and the third
|
||||||
// character is not a U+002E FULL STOP character, or if it has more than one U+002E FULL STOP character, then fail.
|
// character is not a U+002E FULL STOP character, or if it has more than one U+002E FULL STOP character, then fail.
|
||||||
if (second_string.length() == 3)
|
if (second_string.length() == 3)
|
||||||
return {};
|
return {};
|
||||||
if (second_string.length() > 3 && second_string[2] != '.')
|
if (second_string.length() > 3 && second_string[2] != '.')
|
||||||
return {};
|
return {};
|
||||||
if (second_string.find_all("."sv).size() > 1)
|
if (second_string.find_all("."sv).size() > 1)
|
||||||
return {};
|
return {};
|
||||||
// Otherwise, interpret the resulting sequence as a base-ten number (possibly with a fractional part). Set second
|
// Otherwise, interpret the resulting sequence as a base-ten number (possibly with a fractional part). Set second
|
||||||
// to that number.
|
// to that number.
|
||||||
// NB: The spec doesn't state requirements for what we must do with the fractional part of the second(s) string.
|
// NB: The spec doesn't state requirements for what we must do with the fractional part of the second(s) string.
|
||||||
// The spec neither requires that we separately preserve it nor requires that we completely discard it. If we
|
// The spec neither requires that we separately preserve it nor requires that we completely discard it. If we
|
||||||
// did have any reason at all to preserve it, we could parse the string into a float here. But there doesn't
|
// did have any reason at all to preserve it, we could parse the string into a float here. But there doesn't
|
||||||
// seem to be any point in doing that, because there’s nothing in the corresponding calling algorithm(s) in the
|
// seem to be any point in doing that, because there’s nothing in the corresponding calling algorithm(s) in the
|
||||||
// spec that takes a milliseconds field and does anything with it anyway.
|
// spec that takes a milliseconds field and does anything with it anyway.
|
||||||
auto maybe_second = second_string.to_number<i32>();
|
auto maybe_second = second_string.to_number<i32>();
|
||||||
if (!maybe_second.has_value())
|
if (!maybe_second.has_value())
|
||||||
return {};
|
return {};
|
||||||
second = maybe_second.value();
|
second = maybe_second.value();
|
||||||
// 7.4. If second is not a number in the range 0 ≤ second < 60, then fail.
|
|
||||||
if (second < 0 || second > 60)
|
// 4. If second is not a number in the range 0 ≤ second < 60, then fail.
|
||||||
return {};
|
if (second < 0 || second > 60)
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
// 8. Return hour, minute, and second.
|
// 8. Return hour, minute, and second.
|
||||||
return HourMinuteSecond { hour, minute, second };
|
return HourMinuteSecond { hour, minute, second };
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ date did not throw: 0
|
||||||
month did not throw: 100
|
month did not throw: 100
|
||||||
week did not throw: 345600000
|
week did not throw: 345600000
|
||||||
time did not throw: 0
|
time did not throw: 0
|
||||||
datetime-local did not throw: NaN
|
datetime-local did not throw: 0
|
||||||
color threw exception: InvalidStateError: valueAsNumber: Invalid input type used
|
color threw exception: InvalidStateError: valueAsNumber: Invalid input type used
|
||||||
checkbox threw exception: InvalidStateError: valueAsNumber: Invalid input type used
|
checkbox threw exception: InvalidStateError: valueAsNumber: Invalid input type used
|
||||||
radio threw exception: InvalidStateError: valueAsNumber: Invalid input type used
|
radio threw exception: InvalidStateError: valueAsNumber: Invalid input type used
|
||||||
|
|
|
@ -2,8 +2,8 @@ Harness status: OK
|
||||||
|
|
||||||
Found 60 tests
|
Found 60 tests
|
||||||
|
|
||||||
56 Pass
|
58 Pass
|
||||||
4 Fail
|
2 Fail
|
||||||
Pass valueAsNumber getter on type date (actual value: , expected valueAsNumber: NaN)
|
Pass valueAsNumber getter on type date (actual value: , expected valueAsNumber: NaN)
|
||||||
Pass valueAsNumber getter on type date (actual value: 0000-12-10, expected valueAsNumber: NaN)
|
Pass valueAsNumber getter on type date (actual value: 0000-12-10, expected valueAsNumber: NaN)
|
||||||
Pass valueAsNumber getter on type date (actual value: 2019-00-12, expected valueAsNumber: NaN)
|
Pass valueAsNumber getter on type date (actual value: 2019-00-12, expected valueAsNumber: NaN)
|
||||||
|
@ -41,8 +41,8 @@ Pass valueAsNumber setter on type time (actual valueAsNumber: 0, expected value:
|
||||||
Pass valueAsNumber setter on type time (actual valueAsNumber: 43200000, expected value: 12:00)
|
Pass valueAsNumber setter on type time (actual valueAsNumber: 43200000, expected value: 12:00)
|
||||||
Pass valueAsNumber setter on type time (actual valueAsNumber: 86340000, expected value: 23:59)
|
Pass valueAsNumber setter on type time (actual valueAsNumber: 86340000, expected value: 23:59)
|
||||||
Pass valueAsNumber getter on type datetime-local (actual value: , expected valueAsNumber: NaN)
|
Pass valueAsNumber getter on type datetime-local (actual value: , expected valueAsNumber: NaN)
|
||||||
Fail valueAsNumber getter on type datetime-local (actual value: 2019-12-10T00:00, expected valueAsNumber: 1575936000000)
|
Pass valueAsNumber getter on type datetime-local (actual value: 2019-12-10T00:00, expected valueAsNumber: 1575936000000)
|
||||||
Fail valueAsNumber getter on type datetime-local (actual value: 2019-12-10T12:00, expected valueAsNumber: 1575979200000)
|
Pass valueAsNumber getter on type datetime-local (actual value: 2019-12-10T12:00, expected valueAsNumber: 1575979200000)
|
||||||
Pass valueAsNumber setter on type datetime-local (actual valueAsNumber: 1575936000000, expected value: 2019-12-10T00:00)
|
Pass valueAsNumber setter on type datetime-local (actual valueAsNumber: 1575936000000, expected value: 2019-12-10T00:00)
|
||||||
Pass valueAsNumber setter on type datetime-local (actual valueAsNumber: 1575979200000, expected value: 2019-12-10T12:00)
|
Pass valueAsNumber setter on type datetime-local (actual valueAsNumber: 1575979200000, expected value: 2019-12-10T12:00)
|
||||||
Pass valueAsNumber getter on type number (actual value: , expected valueAsNumber: NaN)
|
Pass valueAsNumber getter on type number (actual value: , expected valueAsNumber: NaN)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue