gecko-dev/dom/html/test/forms/test_input_sanitization.html

416 строки
11 KiB
HTML

<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=549475
-->
<head>
<title>Test for Bug 549475</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=549475">Mozilla Bug 549475</a>
<p id="display"></p>
<pre id="test">
<div id='content'>
<form>
</form>
</div>
<script type="application/javascript">
/**
* This files tests the 'value sanitization algorithm' for the various input
* types. Note that an input's value is affected by more than just its type's
* value sanitization algorithm; e.g. some type=range has actions that the user
* agent must perform to change the element's value to avoid underflow/overflow
* and step mismatch (when possible). We specifically avoid triggering these
* other actions here so that this test only tests the value sanitization
* algorithm for the various input types.
*
* XXXjwatt splitting out testing of the value sanitization algorithm and
* "other things" that affect .value makes it harder to know what we're testing
* and what we've missed, because what's included in the value sanitization
* algorithm and what's not is different from input type to input type. It
* seems to me it would be better to have a test (maybe one per type) focused
* on testing .value for permutations of all other inputs that can affect it.
* The value sanitization algorithm is just an internal spec concept after all.
*/
// We buffer up the results of sets of sub-tests, and avoid outputting log
// entries for them all if they all pass. Otherwise, we have an enormous amount
// of test output.
var delayedTests = [];
var anyFailedDelayedTests = false;
function delayed_is(actual, expected, description)
{
var result = actual == expected;
delayedTests.push({ actual: actual, expected: expected, description: description });
if (!result) {
anyFailedDelayedTests = true;
}
}
function flushDelayedTests(description)
{
if (anyFailedDelayedTests) {
info("Outputting individual results for \"" + description + "\" due to failures in subtests");
for (var test of delayedTests) {
is(test.actual, test.expected, test.description);
}
} else {
ok(true, description + " (" + delayedTests.length + " subtests)");
}
delayedTests = [];
anyFailedDelayedTests = false;
}
// We are excluding "file" because it's too different from the other types.
// And it has no sanitizing algorithm.
var inputTypes =
[
"text", "password", "search", "tel", "hidden", "checkbox", "radio",
"submit", "image", "reset", "button", "email", "url", "number", "date",
"time", "range", "color"
];
var todoTypes =
[
"month", "week", "datetime", "datetime-local",
];
var valueModeValue =
[
"text", "search", "url", "tel", "email", "password", "date", "datetime",
"month", "week", "time", "datetime-local", "number", "range", "color",
];
function sanitizeValue(aType, aValue)
{
// http://www.whatwg.org/html/#value-sanitization-algorithm
switch (aType) {
case "text":
case "password":
case "search":
case "tel":
return aValue.replace(/[\n\r]/g, "");
case "url":
case "email":
return aValue.replace(/[\n\r]/g, "").replace(/^[\u0020\u0009\t\u000a\u000c\u000d]+|[\u0020\u0009\t\u000a\u000c\u000d]+$/g, "");
case "number":
return isNaN(Number(aValue)) ? "" : aValue;
case "range":
var defaultMinimum = 0;
var defaultMaximum = 100;
var value = Number(aValue);
if (isNaN(value)) {
return ((defaultMaximum - defaultMinimum)/2).toString(); // "50"
}
if (value < defaultMinimum) {
return defaultMinimum.toString();
}
if (value > defaultMaximum) {
return defaultMaximum.toString();
}
return aValue;
case "date":
// http://www.whatwg.org/specs/web-apps/current-work/multipage/common-microsyntaxes.html#valid-date-string
function getNumbersOfDaysInMonth(aMonth, aYear) {
if (aMonth === 2) {
return (aYear % 400 === 0 || (aYear % 100 != 0 && aYear % 4 === 0)) ? 29 : 28;
}
return (aMonth === 1 || aMonth === 3 || aMonth === 5 || aMonth === 7 ||
aMonth === 8 || aMonth === 10 || aMonth === 12) ? 31 : 30;
}
var match = /^([0-9]{4,})-([0-9]{2})-([0-9]{2})$/.exec(aValue);
if (!match) {
return "";
}
var year = Number(match[1]);
if (year === 0) {
return "";
}
var month = Number(match[2]);
if (month > 12 || month < 1) {
return "";
}
var day = Number(match[3]);
return 1 <= day && day <= getNumbersOfDaysInMonth(month, year) ? aValue : "";
case "time":
// http://www.whatwg.org/specs/web-apps/current-work/multipage/common-microsyntaxes.html#valid-time-string
var match = /^([0-9]{2}):([0-9]{2})(.*)$/.exec(aValue);
if (!match) {
return "";
}
var hours = match[1];
if (hours < 0 || hours > 23) {
return "";
}
var minutes = match[2];
if (minutes < 0 || minutes > 59) {
return "";
}
var other = match[3];
if (other == "") {
return aValue;
}
match = /^:([0-9]{2})(.*)$/.exec(other);
if (!match) {
return "";
}
var seconds = match[1];
if (seconds < 0 || seconds > 59) {
return "";
}
var other = match[2];
if (other == "") {
return aValue;
}
match = /^.([0-9]{1,3})$/.exec(other);
if (!match) {
return "";
}
return aValue;
case "month":
case "week":
case "datetime":
case "datetime-local":
// TODO: write the sanitize algorithm.
ok(false);
return "";
case "color":
return /^#[0-9A-Fa-f]{6}$/.exec(aValue) ? aValue.toLowerCase() : "#000000";
default:
return aValue;
}
}
function checkSanitizing(element, inputTypeDescription)
{
var testData =
[
// For text, password, search, tel, email:
"\n\rfoo\n\r",
"foo\n\rbar",
" foo ",
" foo\n\r bar ",
// For url:
"\r\n foobar \n\r",
"\u000B foo \u000B",
"\u000A foo \u000A",
"\u000C foo \u000C",
"\u000d foo \u000d",
"\u0020 foo \u0020",
" \u0009 foo \u0009 ",
// For number and range:
"42",
"13.37",
"1.234567898765432",
"12foo",
"1e2",
"3E42",
// For date:
"1970-01-01",
"1234-12-12",
"1234567890-01-02",
"2012-12-31",
"2012-02-29",
"2000-02-29",
"1234",
"1234-",
"12345",
"1234-01",
"1234-012",
"1234-01-",
"12-12",
"999-01-01",
"1234-56-78-91",
"1234-567-78",
"1234--7-78",
"abcd-12-12",
"thisinotadate",
"2012-13-01",
"1234-12-42",
" 2012-13-01",
" 123-01-01",
"2012- 3-01",
"12- 10- 01",
" 12-0-1",
"2012-3-001",
"2012-12-00",
"2012-12-1r",
"2012-11-31",
"2011-02-29",
"2100-02-29",
"a2000-01-01",
"2000a-01-0'",
"20aa00-01-01",
"2000a2000-01-01",
"2000-1-1",
"2000-1-01",
"2000-01-1",
"2000-01-01 ",
"2000- 01-01",
"-1970-01-01",
"0000-00-00",
"0001-00-00",
"0000-01-01",
"1234-12 12",
"1234 12-12",
"1234 12 12",
// For time:
"1",
"10",
"10:",
"10:1",
"21:21",
":21:21",
"-21:21",
" 21:21",
"21-21",
"21:21:",
"21:211",
"121:211",
"21:21 ",
"00:00",
"-1:00",
"24:00",
"00:60",
"01:01",
"23:59",
"99:99",
"8:30",
"19:2",
"19:a2",
"4c:19",
"10:.1",
"1.:10",
"13:37:42",
"13:37.42",
"13:37:42 ",
"13:37:42.",
"13:37:61.",
"13:37:00",
"13:37:99",
"13:37:b5",
"13:37:-1",
"13:37:.1",
"13:37:1.",
"13:37:42.001",
"13:37:42.001",
"13:37:42.abc",
"13:37:42.00c",
"13:37:42.a23",
"13:37:42.12e",
"13:37:42.1e1",
"13:37:42.e11",
"13:37:42.1",
"13:37:42.99",
"13:37:42.0",
"13:37:42.00",
"13:37:42.000",
"13:37:42.-1",
"13:37:42.1.1",
"13:37:42.1,1",
"13:37:42.",
"foo12:12",
"13:37:42.100000000000",
// For color
"#00ff00",
"#000000",
"red",
"#0f0",
"#FFFFAA",
"FFAABB",
"fFAaBb",
"FFAAZZ",
"ABCDEF",
"#7654321",
];
for (value of testData) {
element.setAttribute('value', value);
delayed_is(element.value, sanitizeValue(type, value),
"The value has not been correctly sanitized for type=" + type);
delayed_is(element.getAttribute('value'), value,
"The content value should not have been sanitized");
if (type in valueModeValue) {
element.setAttribute('value', 'tulip');
element.value = value;
delayed_is(element.value, sanitizeValue(type, value),
"The value has not been correctly sanitized for type=" + type);
delayed_is(element.getAttribute('value'), 'tulip',
"The content value should not have been sanitized");
}
element.setAttribute('value', '');
form.reset();
element.type = 'checkbox'; // We know this type has no sanitizing algorithm.
element.setAttribute('value', value);
delayed_is(element.value, value, "The value should not have been sanitized");
element.type = type;
delayed_is(element.value, sanitizeValue(type, value),
"The value has not been correctly sanitized for type=" + type);
delayed_is(element.getAttribute('value'), value,
"The content value should not have been sanitized");
element.setAttribute('value', '');
form.reset();
element.setAttribute('value', value);
form.reset();
delayed_is(element.value, sanitizeValue(type, value),
"The value has not been correctly sanitized for type=" + type);
delayed_is(element.getAttribute('value'), value,
"The content value should not have been sanitized");
// Cleaning-up.
element.setAttribute('value', '');
form.reset();
}
flushDelayedTests(inputTypeDescription);
}
for (type of inputTypes) {
var form = document.forms[0];
var element = document.createElement("input");
element.style.display = "none";
element.type = type;
form.appendChild(element);
checkSanitizing(element, "type=" + type + ", no frame, no editor");
element.style.display = "";
checkSanitizing(element, "type=" + type + ", frame, no editor");
element.focus();
element.blur();
checkSanitizing(element, "type=" + type + ", frame, editor");
element.style.display = "none";
checkSanitizing(element, "type=" + type + ", no frame, editor");
form.removeChild(element);
}
for (type of todoTypes) {
// The only meaning of this is to have a failure when new types are introduced
// so we will know we have to write the tests here.
var form = document.forms[0];
var element = document.createElement("input");
element.type = type;
form.appendChild(element);
todo_is(element.type, type, "");
form.removeChild(element);
}
</script>
</pre>
</body>
</html>