diff options
author | Simon Wörner <git@simon-woerner.de> | 2017-11-26 15:13:02 +0100 |
---|---|---|
committer | Simon Wörner <fixed-term.Simon.Woerner3@boschrexroth.de> | 2017-12-04 11:21:28 +0100 |
commit | a999239f28672aed053c9c3db001a2e6a26efa7f (patch) | |
tree | 77165e3391a6ee6cc4155aa0d14380e41fb91a3a | |
parent | ac6e04ebfbf27317fea00ea93e855520237b538d (diff) | |
download | servo-a999239f28672aed053c9c3db001a2e6a26efa7f.tar.gz servo-a999239f28672aed053c9c3db001a2e6a26efa7f.zip |
Added time input sanitization:
- Implemented is_valid_time_string for DOMString.
- Use is_valid_time_string for sanitize_value with time input.
- Improved input type change test
8 files changed, 228 insertions, 157 deletions
diff --git a/components/script/dom/bindings/str.rs b/components/script/dom/bindings/str.rs index 3667dddf92d..6601d8e6856 100644 --- a/components/script/dom/bindings/str.rs +++ b/components/script/dom/bindings/str.rs @@ -208,6 +208,77 @@ impl DOMString { self.0.truncate(last_non_whitespace); let _ = self.0.splice(0..first_non_whitespace, ""); } + + /// Validates this `DOMString` is a time string according to + /// <https://html.spec.whatwg.org/multipage/#valid-time-string>. + pub fn is_valid_time_string(&self) -> bool { + enum State { + HourHigh, + HourLow09, + HourLow03, + MinuteColon, + MinuteHigh, + MinuteLow, + SecondColon, + SecondHigh, + SecondLow, + MilliStop, + MilliHigh, + MilliMiddle, + MilliLow, + Done, + Error, + } + let next_state = |valid: bool, next: State| -> State { if valid { next } else { State::Error } }; + + let state = self.chars().fold(State::HourHigh, |state, c| { + match state { + // Step 1 "HH" + State::HourHigh => { + match c { + '0' | '1' => State::HourLow09, + '2' => State::HourLow03, + _ => State::Error, + } + }, + State::HourLow09 => next_state(c.is_digit(10), State::MinuteColon), + State::HourLow03 => next_state(c.is_digit(4), State::MinuteColon), + + // Step 2 ":" + State::MinuteColon => next_state(c == ':', State::MinuteHigh), + + // Step 3 "mm" + State::MinuteHigh => next_state(c.is_digit(6), State::MinuteLow), + State::MinuteLow => next_state(c.is_digit(10), State::SecondColon), + + // Step 4.1 ":" + State::SecondColon => next_state(c == ':', State::SecondHigh), + // Step 4.2 "ss" + State::SecondHigh => next_state(c.is_digit(6), State::SecondLow), + State::SecondLow => next_state(c.is_digit(10), State::MilliStop), + + // Step 4.3.1 "." + State::MilliStop => next_state(c == '.', State::MilliHigh), + // Step 4.3.2 "SSS" + State::MilliHigh => next_state(c.is_digit(6), State::MilliMiddle), + State::MilliMiddle => next_state(c.is_digit(10), State::MilliLow), + State::MilliLow => next_state(c.is_digit(10), State::Done), + + _ => State::Error, + } + }); + + match state { + State::Done | + // Step 4 (optional) + State::SecondColon | + // Step 4.3 (optional) + State::MilliStop | + // Step 4.3.2 (only 1 digit required) + State::MilliMiddle | State::MilliLow => true, + _ => false + } + } } impl Borrow<str> for DOMString { diff --git a/components/script/dom/htmlinputelement.rs b/components/script/dom/htmlinputelement.rs index 7f995671d8d..0725fafcaac 100755 --- a/components/script/dom/htmlinputelement.rs +++ b/components/script/dom/htmlinputelement.rs @@ -895,6 +895,13 @@ impl HTMLInputElement { textinput.set_content("#000000".into()); } } + atom!("time") => { + let mut textinput = self.textinput.borrow_mut(); + + if ! textinput.single_line_content().is_valid_time_string() { + *textinput.single_line_content_mut() = "".into(); + } + } // TODO: Implement more value sanitization algorithms for different types of inputs _ => () } diff --git a/tests/wpt/metadata/MANIFEST.json b/tests/wpt/metadata/MANIFEST.json index 32fd7e9e58e..a7ac7615441 100644 --- a/tests/wpt/metadata/MANIFEST.json +++ b/tests/wpt/metadata/MANIFEST.json @@ -543020,7 +543020,7 @@ "testharness" ], "html/semantics/forms/the-input-element/type-change-state.html": [ - "95e8bfd7d2f14068b0d3e41e3f017da3647bc382", + "d731573ee091b7e658ea0b1ded46a764e8165f6c", "testharness" ], "html/semantics/forms/the-input-element/url.html": [ diff --git a/tests/wpt/metadata/html/semantics/forms/the-input-element/time-2.html.ini b/tests/wpt/metadata/html/semantics/forms/the-input-element/time-2.html.ini deleted file mode 100644 index 3d6a79f4c24..00000000000 --- a/tests/wpt/metadata/html/semantics/forms/the-input-element/time-2.html.ini +++ /dev/null @@ -1,23 +0,0 @@ -[time-2.html] - type: testharness - [Invalid value: fraction should have one, two or three ASCII digits. Value should be empty] - expected: FAIL - - [Invalid value: hour should have two ASCII digits. Value should be empty] - expected: FAIL - - [Invalid value: minutes should have two ASCII digits. Value should be empty] - expected: FAIL - - [Invalid value: seconds should have two ASCII digits. Value should be empty] - expected: FAIL - - [Invalid value: hour > 23. Value should be empty] - expected: FAIL - - [Invalid value: minute > 59. Value should be empty] - expected: FAIL - - [Invalid value: second > 59. Value should be empty] - expected: FAIL - diff --git a/tests/wpt/metadata/html/semantics/forms/the-input-element/time.html.ini b/tests/wpt/metadata/html/semantics/forms/the-input-element/time.html.ini index a9d391f1797..8c6c3d92631 100644 --- a/tests/wpt/metadata/html/semantics/forms/the-input-element/time.html.ini +++ b/tests/wpt/metadata/html/semantics/forms/the-input-element/time.html.ini @@ -69,9 +69,6 @@ [ empty value of stepUp] expected: FAIL - [set value on not time format value] - expected: FAIL - [stepUp on step value with fractional seconds] expected: FAIL diff --git a/tests/wpt/metadata/html/semantics/forms/the-input-element/type-change-state.html.ini b/tests/wpt/metadata/html/semantics/forms/the-input-element/type-change-state.html.ini index c090fb26995..cc3c76ce1ab 100644 --- a/tests/wpt/metadata/html/semantics/forms/the-input-element/type-change-state.html.ini +++ b/tests/wpt/metadata/html/semantics/forms/the-input-element/type-change-state.html.ini @@ -15,9 +15,6 @@ [change state from hidden to week] expected: FAIL - [change state from hidden to time] - expected: FAIL - [change state from hidden to number] expected: FAIL @@ -39,9 +36,6 @@ [change state from text to week] expected: FAIL - [change state from text to time] - expected: FAIL - [change state from text to number] expected: FAIL @@ -63,9 +57,6 @@ [change state from search to week] expected: FAIL - [change state from search to time] - expected: FAIL - [change state from search to number] expected: FAIL @@ -87,9 +78,6 @@ [change state from tel to week] expected: FAIL - [change state from tel to time] - expected: FAIL - [change state from tel to number] expected: FAIL @@ -120,9 +108,6 @@ [change state from url to week] expected: FAIL - [change state from url to time] - expected: FAIL - [change state from url to number] expected: FAIL @@ -162,9 +147,6 @@ [change state from email to week] expected: FAIL - [change state from email to time] - expected: FAIL - [change state from email to number] expected: FAIL @@ -186,9 +168,6 @@ [change state from password to week] expected: FAIL - [change state from password to time] - expected: FAIL - [change state from password to number] expected: FAIL @@ -222,9 +201,6 @@ [change state from datetime to week] expected: FAIL - [change state from datetime to time] - expected: FAIL - [change state from datetime to number] expected: FAIL @@ -264,9 +240,6 @@ [change state from date to week] expected: FAIL - [change state from date to time] - expected: FAIL - [change state from date to number] expected: FAIL @@ -306,9 +279,6 @@ [change state from month to week] expected: FAIL - [change state from month to time] - expected: FAIL - [change state from month to number] expected: FAIL @@ -348,57 +318,12 @@ [change state from week to month] expected: FAIL - [change state from week to time] - expected: FAIL - [change state from week to number] expected: FAIL [change state from week to range] expected: FAIL - [change state from time to hidden] - expected: FAIL - - [change state from time to checkbox] - expected: FAIL - - [change state from time to radio] - expected: FAIL - - [change state from time to submit] - expected: FAIL - - [change state from time to image] - expected: FAIL - - [change state from time to reset] - expected: FAIL - - [change state from time to button] - expected: FAIL - - [change state from time to email] - expected: FAIL - - [change state from time to datetime] - expected: FAIL - - [change state from time to date] - expected: FAIL - - [change state from time to month] - expected: FAIL - - [change state from time to week] - expected: FAIL - - [change state from time to number] - expected: FAIL - - [change state from time to range] - expected: FAIL - [change state from number to hidden] expected: FAIL @@ -435,9 +360,6 @@ [change state from number to week] expected: FAIL - [change state from number to time] - expected: FAIL - [change state from number to range] expected: FAIL @@ -477,9 +399,6 @@ [change state from range to week] expected: FAIL - [change state from range to time] - expected: FAIL - [change state from range to number] expected: FAIL @@ -498,9 +417,6 @@ [change state from checkbox to week] expected: FAIL - [change state from checkbox to time] - expected: FAIL - [change state from checkbox to number] expected: FAIL @@ -522,9 +438,6 @@ [change state from radio to week] expected: FAIL - [change state from radio to time] - expected: FAIL - [change state from radio to number] expected: FAIL @@ -546,9 +459,6 @@ [change state from submit to week] expected: FAIL - [change state from submit to time] - expected: FAIL - [change state from submit to number] expected: FAIL @@ -570,9 +480,6 @@ [change state from image to week] expected: FAIL - [change state from image to time] - expected: FAIL - [change state from image to number] expected: FAIL @@ -594,9 +501,6 @@ [change state from reset to week] expected: FAIL - [change state from reset to time] - expected: FAIL - [change state from reset to number] expected: FAIL @@ -618,9 +522,6 @@ [change state from button to week] expected: FAIL - [change state from button to time] - expected: FAIL - [change state from button to number] expected: FAIL @@ -681,9 +582,6 @@ [change state from datetime-local to week] expected: FAIL - [change state from datetime-local to time] - expected: FAIL - [change state from datetime-local to number] expected: FAIL @@ -699,9 +597,6 @@ [change state from week to datetime-local] expected: FAIL - [change state from time to datetime-local] - expected: FAIL - [change state from number to datetime-local] expected: FAIL @@ -726,3 +621,120 @@ [change state from button to datetime-local] expected: FAIL + + [change state from datetime-local to text] + expected: FAIL + + [change state from datetime-local to search] + expected: FAIL + + [change state from datetime-local to tel] + expected: FAIL + + [change state from datetime-local to url] + expected: FAIL + + [change state from datetime-local to password] + expected: FAIL + + + [change state from date to text] + expected: FAIL + + [change state from date to search] + expected: FAIL + + [change state from date to tel] + expected: FAIL + + [change state from date to url] + expected: FAIL + + [change state from date to password] + expected: FAIL + + + [change state from month to text] + expected: FAIL + + [change state from month to search] + expected: FAIL + + [change state from month to tel] + expected: FAIL + + [change state from month to url] + expected: FAIL + + [change state from month to password] + expected: FAIL + + + [change state from week to text] + expected: FAIL + + [change state from week to search] + expected: FAIL + + [change state from week to tel] + expected: FAIL + + [change state from week to url] + expected: FAIL + + [change state from week to password] + expected: FAIL + + + [change state from number to text] + expected: FAIL + + [change state from number to search] + expected: FAIL + + [change state from number to tel] + expected: FAIL + + [change state from number to url] + expected: FAIL + + [change state from number to password] + expected: FAIL + + + [change state from color to datetime-local] + expected: FAIL + + [change state from color to date] + expected: FAIL + + [change state from color to month] + expected: FAIL + + [change state from color to week] + expected: FAIL + + [change state from color to number] + expected: FAIL + + [change state from color to range] + expected: FAIL + + + [change state from time to range] + expected: FAIL + + [change state from range to text] + expected: FAIL + + [change state from range to search] + expected: FAIL + + [change state from range to tel] + expected: FAIL + + [change state from range to url] + expected: FAIL + + [change state from range to password] + expected: FAIL diff --git a/tests/wpt/metadata/html/semantics/forms/the-input-element/valueMode.html.ini b/tests/wpt/metadata/html/semantics/forms/the-input-element/valueMode.html.ini index eaf6e37bccc..8c54f4d21d9 100644 --- a/tests/wpt/metadata/html/semantics/forms/the-input-element/valueMode.html.ini +++ b/tests/wpt/metadata/html/semantics/forms/the-input-element/valueMode.html.ini @@ -24,12 +24,6 @@ [value IDL attribute of input type week with value attribute] expected: FAIL - [value IDL attribute of input type time without value attribute] - expected: FAIL - - [value IDL attribute of input type time with value attribute] - expected: FAIL - [value IDL attribute of input type number without value attribute] expected: FAIL diff --git a/tests/wpt/web-platform-tests/html/semantics/forms/the-input-element/type-change-state.html b/tests/wpt/web-platform-tests/html/semantics/forms/the-input-element/type-change-state.html index ed64cf789a1..82d36cda481 100644 --- a/tests/wpt/web-platform-tests/html/semantics/forms/the-input-element/type-change-state.html +++ b/tests/wpt/web-platform-tests/html/semantics/forms/the-input-element/type-change-state.html @@ -15,16 +15,16 @@ { type: "url", sanitizedValue: "foobar" }, { type: "email", sanitizedValue: "foobar" }, { type: "password", sanitizedValue: " foobar " }, - { type: "datetime-local", sanitizedValue: "" }, - { type: "date", sanitizedValue: "" }, - { type: "month", sanitizedValue: "" }, - { type: "week", sanitizedValue: "" }, - { type: "time", sanitizedValue: "" }, - { type: "number", sanitizedValue: "" }, - { type: "range", sanitizedValue: "50" }, - { type: "color", sanitizedValue: "#000000" }, - { type: "checkbox" }, - { type: "radio" }, + { type: "datetime-local", sanitizedValue: "", overridesSanitization: true }, + { type: "date", sanitizedValue: "", overridesSanitization: true }, + { type: "month", sanitizedValue: "", overridesSanitization: true }, + { type: "week", sanitizedValue: "", overridesSanitization: true }, + { type: "time", sanitizedValue: "", overridesSanitization: true }, + { type: "number", sanitizedValue: "", overridesSanitization: true }, + { type: "range", sanitizedValue: "50", overridesSanitization: true }, + { type: "color", sanitizedValue: "#000000", overridesSanitization: true }, + { type: "checkbox", defaultValue: "on" }, + { type: "radio", defaultValue: "on" }, { type: "file" }, { type: "submit" }, { type: "image" }, @@ -36,26 +36,39 @@ if (types[i] != types[j]) { test(function() { var input = document.createElement("input"); + var expected = " foo\rbar "; input.type = types[i].type; if (types[i].type === "file") { assert_throws("INVALID_STATE_ERR", function() { - input.value = " foo\rbar "; + input.value = expected; }); assert_equals(input.value, ""); } else if (types[j].type === "file") { - input.value = " foo\rbar "; + input.value = expected; input.type = types[j].type; // change state assert_equals(input.value, ""); } else { - input.value = " foo\rbar "; + input.value = expected; input.type = types[j].type; // change state - if (types[i].type !== "color" && (types[j].sanitizedValue || types[j].sanitizedValue === "")) { - assert_equals(input.value, types[j].sanitizedValue, "input.value should be " + types[j].sanitizedValue + " after change of state"); - } else if (types[i].sanitizedValue || types[i].sanitizedValue === "") { - assert_equals(input.value, types[i].sanitizedValue, "input.value should be " + types[i].sanitizedValue + " after change of state"); - } else { - assert_equals(input.value, " foo\rbar ", "input.value should be ' foo\\rbar ' after change of state"); + + // type[i] sanitization + if (types[i].sanitizedValue || types[i].sanitizedValue === "") { + expected = types[i].sanitizedValue; } + + // type[j] sanitization + if (types[j].sanitizedValue || types[j].sanitizedValue === "") { + if ((expected !== "" && !types[i].overridesSanitization) || types[j].overridesSanitization) { + expected = types[j].sanitizedValue; + } + } + + // type[j] defaultValue + if (expected === "" && types[j].defaultValue) { + expected = types[j].defaultValue; + } + + assert_equals(input.value, expected, "input.value should be '" + expected + "' after change of state"); } }, "change state from " + types[i].type + " to " + types[j].type); } |