Bug 1325009 - Find separator index dynamically when sanitizing input type=datetime-local. r=smaug
authorJessica Jong <jjong@mozilla.com>
Wed, 21 Dec 2016 19:32:00 +0800
changeset 374275 3fe0ff6bef8b295865440d3a5ba4ce4ce6ebeea6
parent 374274 38f5c47acbe1b9fb0008d60d7f16e217b4d4e027
child 374276 7a7dbaf2e06f0b6535affe7cd35fd126a52ddd38
push id1419
push userjlund@mozilla.com
push dateMon, 10 Apr 2017 20:44:07 +0000
treeherdermozilla-release@5e6801b73ef6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1325009
milestone53.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
Bug 1325009 - Find separator index dynamically when sanitizing input type=datetime-local. r=smaug
dom/html/HTMLInputElement.cpp
dom/html/test/forms/test_input_sanitization.html
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -5479,19 +5479,23 @@ HTMLInputElement::ParseDateTimeLocal(con
   // 'yyyy-mm-ddThh:mm[:ss.s] or 'yyyy-mm-dd hh:mm[:ss.s]', where fractions of
   // seconds can be 1 to 3 digits.
   // The minimum length allowed is 16, which is of the form 'yyyy-mm-ddThh:mm'
   // or 'yyyy-mm-dd hh:mm'.
   if (aValue.Length() < 16) {
     return false;
   }
 
-  const uint32_t sepIndex = 10;
-  if (aValue[sepIndex] != 'T' && aValue[sepIndex] != ' ') {
-    return false;
+  int32_t sepIndex = aValue.FindChar('T');
+  if (sepIndex == -1) {
+    sepIndex = aValue.FindChar(' ');
+
+    if (sepIndex == -1) {
+      return false;
+    }
   }
 
   const nsAString& dateStr = Substring(aValue, 0, sepIndex);
   if (!ParseDate(dateStr, aYear, aMonth, aDay)) {
     return false;
   }
 
   const nsAString& timeStr = Substring(aValue, sepIndex + 1,
@@ -5506,52 +5510,59 @@ HTMLInputElement::ParseDateTimeLocal(con
 void
 HTMLInputElement::NormalizeDateTimeLocal(nsAString& aValue) const
 {
   if (aValue.IsEmpty()) {
     return;
   }
 
   // Use 'T' as the separator between date string and time string.
-  const uint32_t sepIndex = 10;
-  if (aValue[sepIndex] == ' ') {
+  int32_t sepIndex = aValue.FindChar(' ');
+  if (sepIndex != -1) {
     aValue.Replace(sepIndex, 1, NS_LITERAL_STRING("T"));
-  }
-
-  // Time expressed as the shortest possible string.
-  if (aValue.Length() == 16) {
+  } else {
+    sepIndex = aValue.FindChar('T');
+  }
+
+  // Time expressed as the shortest possible string, which is hh:mm.
+  if ((aValue.Length() - sepIndex) == 6) {
     return;
   }
 
   // Fractions of seconds part is optional, ommit it if it's 0.
-  if (aValue.Length() > 19) {
+  if ((aValue.Length() - sepIndex) > 9) {
+    const uint32_t millisecSepIndex = sepIndex + 9;
     uint32_t milliseconds;
-    if (!DigitSubStringToNumber(aValue, 20, aValue.Length() - 20,
+    if (!DigitSubStringToNumber(aValue, millisecSepIndex + 1,
+                                aValue.Length() - (millisecSepIndex + 1),
                                 &milliseconds)) {
       return;
     }
 
     if (milliseconds != 0) {
       return;
     }
 
-    aValue.Cut(19, aValue.Length() - 19);
+    aValue.Cut(millisecSepIndex, aValue.Length() - millisecSepIndex);
   }
 
   // Seconds part is optional, ommit it if it's 0.
+  const uint32_t secondSepIndex = sepIndex + 6;
   uint32_t seconds;
-  if (!DigitSubStringToNumber(aValue, 17, aValue.Length() - 17, &seconds)) {
+  if (!DigitSubStringToNumber(aValue, secondSepIndex + 1,
+                              aValue.Length() - (secondSepIndex + 1),
+                              &seconds)) {
     return;
   }
 
   if (seconds != 0) {
     return;
   }
 
-  aValue.Cut(16, aValue.Length() - 16);
+  aValue.Cut(secondSepIndex, aValue.Length() - secondSepIndex);
 }
 
 double
 HTMLInputElement::DaysSinceEpochFromWeek(uint32_t aYear, uint32_t aWeek) const
 {
   double days = JS::DayFromYear(aYear) + (aWeek - 1) * 7;
   uint32_t dayOneIsoWeekday = DayOfWeek(aYear, 1, 1, true);
 
--- a/dom/html/test/forms/test_input_sanitization.html
+++ b/dom/html/test/forms/test_input_sanitization.html
@@ -150,53 +150,56 @@ function sanitizeTime(aValue)
 
 function sanitizeDateTimeLocal(aValue)
 {
   // https://html.spec.whatwg.org/multipage/infrastructure.html#valid-local-date-and-time-string
   if (aValue.length < 16) {
     return "";
   }
 
-  var separator = aValue[10];
-  if (separator != "T" && separator != " ") {
-    return "";
+  var sepIndex = aValue.indexOf("T");
+  if (sepIndex == -1) {
+    sepIndex = aValue.indexOf(" ");
+    if (sepIndex == -1) {
+      return "";
+    }
   }
 
-  var [date, time] = aValue.split(separator);
+  var [date, time] = aValue.split(aValue[sepIndex]);
   if (!sanitizeDate(date)) {
     return "";
   }
 
   if (!sanitizeTime(time)) {
     return "";
   }
 
   // Normalize datetime-local string.
   // https://html.spec.whatwg.org/multipage/infrastructure.html#valid-normalised-local-date-and-time-string
-  if (separator == " ") {
+  if (aValue[sepIndex] == " ") {
     aValue = date + "T" + time;
   }
 
-  if (aValue.length == 16) {
+  if ((aValue.length - sepIndex) == 6) {
     return aValue;
   }
 
-  if (aValue.length > 19) {
-    var milliseconds = aValue.substring(20);
+  if ((aValue.length - sepIndex) > 9) {
+    var milliseconds = aValue.substring(sepIndex + 10);
     if (Number(milliseconds) != 0) {
       return aValue;
     }
-    aValue = aValue.slice(0, 19);
+    aValue = aValue.slice(0, sepIndex + 9);
   }
 
-  var seconds = aValue.substring(17);
+  var seconds = aValue.substring(sepIndex + 7);
   if (Number(seconds) != 0) {
     return aValue;
   }
-  aValue = aValue.slice(0, 16);
+  aValue = aValue.slice(0, sepIndex + 6);
 
   return aValue;
 }
 
 function sanitizeValue(aType, aValue)
 {
   // http://www.whatwg.org/html/#value-sanitization-algorithm
   switch (aType) {
@@ -469,17 +472,34 @@ function checkSanitizing(element, inputT
     // For datetime-local
     "1970-01-01T00:00",
     "1970-01-01Z12:00",
     "1970-01-01 00:00:00",
     "1970-01-01T00:00:00.0",
     "1970-01-01T00:00:00.00",
     "1970-01-01T00:00:00.000",
     "1970-01-01 00:00:00.20",
-    "1234567-01-01T12:00",
+    "1969-12-31 23:59",
+    "1969-12-31 23:59:00",
+    "1969-12-31 23:59:00.000",
+    "1969-12-31 23:59:00.30",
+    "123456-01-01T12:00",
+    "123456-01-01T12:00:00",
+    "123456-01-01T12:00:00.0",
+    "123456-01-01T12:00:00.00",
+    "123456-01-01T12:00:00.000",
+    "123456-01-01T12:00:30",
+    "123456-01-01T12:00:00.123",
+    "10000-12-31 20:00",
+    "10000-12-31 20:00:00",
+    "10000-12-31 20:00:00.0",
+    "10000-12-31 20:00:00.00",
+    "10000-12-31 20:00:00.000",
+    "10000-12-31 20:00:30",
+    "10000-12-31 20:00:00.123",
     "2016-13-01T12:00",
     "2016-12-32T12:00",
     "2016-11-08 15:40:30.0",
     "2016-11-08T15:40:30.00",
     "2016-11-07T17:30:10",
     "2016-12-1T12:45",
     "2016-12-01T12:45:30.123456",
     "2016-12-01T24:00",