servo: Merge #19761 - implement range input sanitization (from tigercosmos:m1); r=KiChjang
authortigercosmos <phy.tiger@gmail.com>
Wed, 17 Jan 2018 04:30:58 -0600
changeset 453909 2028080562ac6e5594f4900ca9bb554e7b404421
parent 453908 f49f83a6971acb892e5272a4fa84d07af4133bc3
child 453910 fb618bea01d793a7cc1d3283aa6e3f6a32807df8
push id1648
push usermtabara@mozilla.com
push dateThu, 01 Mar 2018 12:45:47 +0000
treeherdermozilla-release@cbb9688c2eeb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersKiChjang
milestone59.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
servo: Merge #19761 - implement range input sanitization (from tigercosmos:m1); r=KiChjang <!-- Please describe your changes on the following line: --> implement range input sanitation. Since there is no `min`, `max`, `step` implementation currently, this should be continued in the future. r? KiChjang --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [X] These changes fix #19172 (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [ ] These changes do not require tests because _____ <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: 4f099876116c91173a104e32dfcfc32a6d644155
servo/components/script/dom/bindings/str.rs
servo/components/script/dom/htmlinputelement.rs
--- a/servo/components/script/dom/bindings/str.rs
+++ b/servo/components/script/dom/bindings/str.rs
@@ -281,41 +281,47 @@ impl DOMString {
             _ => false
         }
     }
 
     /// A valid date string should be "YYYY-MM-DD"
     /// YYYY must be four or more digits, MM and DD both must be two digits
     /// https://html.spec.whatwg.org/multipage/#valid-date-string
     pub fn is_valid_date_string(&self) -> bool {
-        parse_date_string(&*self.0).is_ok()
+        parse_date_string(&self.0).is_ok()
     }
 
     /// A valid month string should be "YYYY-MM"
     /// YYYY must be four or more digits, MM both must be two digits
     /// https://html.spec.whatwg.org/multipage/#valid-month-string
     pub fn is_valid_month_string(&self) -> bool {
-        parse_month_string(&*self.0).is_ok()
+        parse_month_string(&self.0).is_ok()
     }
 
     /// A valid week string should be like {YYYY}-W{WW}, such as "2017-W52"
     /// YYYY must be four or more digits, WW both must be two digits
     /// https://html.spec.whatwg.org/multipage/#valid-week-string
     pub fn is_valid_week_string(&self) -> bool {
-        parse_week_string(&*self.0).is_ok()
+        parse_week_string(&self.0).is_ok()
     }
 
-    /// A valid number is the same as what rust considers to be valid,
-    /// except for +1., NaN, and Infinity.
     /// https://html.spec.whatwg.org/multipage/#valid-floating-point-number
-    pub fn is_valid_number_string(&self) -> bool {
-        let input = &self.0;
-        input.parse::<f64>().ok().map_or(false, |val| {
-            !(val.is_infinite() || val.is_nan() || input.ends_with(".") || input.starts_with("+"))
-        })
+    pub fn is_valid_floating_point_number_string(&self) -> bool {
+        // for the case that `parse_floating_point_number` cannot handle
+        if self.0.contains(" ") {
+            return false;
+        }
+        parse_floating_point_number(&self.0).is_ok()
+    }
+
+    /// https://html.spec.whatwg.org/multipage/#best-representation-of-the-number-as-a-floating-point-number
+    pub fn set_best_representation_of_the_floating_point_number(&mut self) {
+        if let Ok(val) = parse_floating_point_number(&self.0) {
+            self.0 = val.to_string();
+        }
     }
 
     /// A valid normalized local date and time string should be "{date}T{time}"
     /// where date and time are both valid, and the time string must be as short as possible
     /// https://html.spec.whatwg.org/multipage/#valid-normalised-local-date-and-time-string
     pub fn convert_valid_normalized_local_date_and_time_string(&mut self) -> Result<(), ()> {
         let ((year, month, day), (hour, minute, second)) = parse_local_date_and_time_string(&*self.0)?;
         if second == 0.0 {
@@ -612,17 +618,17 @@ fn parse_time_component(value: &str) -> 
         },
         None => 0.0
     };
 
     // Step 8
     Ok((hour_int, minute_int, second_float))
 }
 
-// https://html.spec.whatwg.org/multipage/#parse-a-local-date-and-time-string
+/// https://html.spec.whatwg.org/multipage/#parse-a-local-date-and-time-string
 fn parse_local_date_and_time_string(value: &str) ->  Result<((u32, u32, u32), (u32, u32, f32)), ()> {
     // Step 1, 2, 4
     let mut iterator = if value.contains('T') {
         value.split('T')
     } else {
         value.split(' ')
     };
 
@@ -653,21 +659,36 @@ fn max_day_in_month(year_num: u32, month
             } else {
                 Ok(28)
             }
         },
         _ => Err(())
     }
 }
 
-// https://html.spec.whatwg.org/multipage/#week-number-of-the-last-day
+/// https://html.spec.whatwg.org/multipage/#week-number-of-the-last-day
 fn max_week_in_year(year: u32) -> u32 {
     match Utc.ymd(year as i32, 1, 1).weekday() {
         Weekday::Thu => 53,
         Weekday::Wed if is_leap_year(year) => 53,
         _ => 52
     }
 }
 
 #[inline]
 fn is_leap_year(year: u32) -> bool {
     year % 400 == 0 || (year % 4 == 0 && year % 100 != 0)
 }
+
+/// https://html.spec.whatwg.org/multipage/#rules-for-parsing-floating-point-number-values
+fn parse_floating_point_number(input: &str) -> Result<f64, ()> {
+    match input.trim().parse::<f64>() {
+        Ok(val) if !(
+            // A valid number is the same as what rust considers to be valid,
+            // except for +1., NaN, and Infinity.
+            val.is_infinite() || val.is_nan() || input.ends_with(".") || input.starts_with("+")
+        ) => {
+            // TODO(#19773): need consider `min`, `max`, `step`, when they are implemented
+            Ok(val.round())
+        },
+        _ => Err(())
+    }
+}
--- a/servo/components/script/dom/htmlinputelement.rs
+++ b/servo/components/script/dom/htmlinputelement.rs
@@ -1042,21 +1042,27 @@ impl HTMLInputElement {
                 let mut textinput = self.textinput.borrow_mut();
                 if textinput.single_line_content_mut()
                     .convert_valid_normalized_local_date_and_time_string().is_err() {
                         textinput.single_line_content_mut().clear();
                 }
             }
             InputType::Number => {
                 let mut textinput = self.textinput.borrow_mut();
-                if !textinput.single_line_content().is_valid_number_string() {
+                if !textinput.single_line_content().is_valid_floating_point_number_string() {
                     textinput.single_line_content_mut().clear();
                 }
             }
-            // TODO: Implement more value sanitization algorithms for different types of inputs
+            // https://html.spec.whatwg.org/multipage/#range-state-(type=range):value-sanitization-algorithm
+            InputType::Range => {
+                self.textinput
+                    .borrow_mut()
+                    .single_line_content_mut()
+                    .set_best_representation_of_the_floating_point_number();
+            }
             _ => ()
         }
     }
 }
 
 impl VirtualMethods for HTMLInputElement {
     fn super_type(&self) -> Option<&VirtualMethods> {
         Some(self.upcast::<HTMLElement>() as &VirtualMethods)