Bug 1680478 [wpt PR 26740] - Add test cases for newline handling in form payloads, a=testonly

Automatic update from web-platform-tests
Add test cases for newline handling in form payloads

--

wpt-commits: 9353d550f0d49f5fd090dc276b60528c642b80d0
wpt-pr: 26740
This commit is contained in:
Andreu Botella 2021-04-13 10:23:49 +00:00 коммит произвёл moz-wptsync-bot
Родитель c4de0fa719
Коммит 3aae1c3908
10 изменённых файлов: 1290 добавлений и 76 удалений

Просмотреть файл

@ -1,10 +1,6 @@
<!DOCTYPE html>
<meta charset="utf-8" />
<title>FormData: Upload files named using controls (tentative)</title>
<!--
NOTE: This test is tentative because encoding for filename
control characters is not yet standardized.
-->
<title>FormData: Upload files named using controls</title>
<link
rel="help"
href="https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#multipart-form-data"

Просмотреть файл

@ -1,10 +1,6 @@
<!DOCTYPE html>
<meta charset="utf-8" />
<title>FormData: Upload files named using punctuation (tentative)</title>
<!--
NOTE: This test is tentative because encoding for filename
punctuation characters is not yet standardized.
-->
<title>FormData: Upload files named using punctuation</title>
<link
rel="help"
href="https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#multipart-form-data"

Просмотреть файл

@ -70,19 +70,21 @@ const formDataPostFileUploadTest = ({
}`,
);
const asName = fileBaseName.replace(/[\r\n"]/g, encodeURIComponent);
const asValue = fileBaseName.replace(/\r\n?|\n/g, "\r\n");
const asName = asValue.replace(/[\r\n"]/g, encodeURIComponent);
const asFilename = fileBaseName.replace(/[\r\n"]/g, encodeURIComponent);
const expectedText = [
boundary,
'Content-Disposition: form-data; name="filename"',
"",
fileBaseName,
asValue,
boundary,
`Content-Disposition: form-data; name="${asName}"`,
"",
"filename",
boundary,
`Content-Disposition: form-data; name="file"; ` +
`filename="${asName}"`,
`filename="${asFilename}"`,
"Content-Type: text/plain",
"",
kTestChars,

Просмотреть файл

@ -1,4 +1,5 @@
<!DOCTYPE html>
<meta charset="utf-8">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="container"></div>
@ -30,32 +31,85 @@ class MyControl extends HTMLElement {
customElements.define('my-control', MyControl);
const $ = document.querySelector.bind(document);
function submitPromise(t) {
function submitPromise(t, extractFromIframe) {
if (!extractFromIframe) {
extractFromIframe = (iframe) => iframe.contentWindow.location.search;
}
return new Promise((resolve, reject) => {
const iframe = $('iframe');
iframe.onload = () => resolve(iframe.contentWindow.location.search);
iframe.onload = () => resolve(extractFromIframe(iframe));
iframe.onerror = () => reject(new Error('iframe onerror fired'));
$('form').submit();
});
}
function testSerializedEntry({name, expectedName, value, expectedValue, description}) {
promise_test(async t => {
$('#container').innerHTML = '<form action="/common/blank.html" target="if1">' +
'<my-control></my-control>' +
'</form>' +
'<iframe name="if1"></iframe>';
if (name !== undefined) {
$('my-control').setAttribute("name", name);
}
if (Array.isArray(value)) {
$('my-control').setValues(value);
} else {
$('my-control').value = value;
}
const query = await submitPromise(t);
assert_equals(query, `?${expectedName}=${expectedValue}`);
}, description);
function testSerializedEntry({name, value, expected, description}) {
// urlencoded
{
const {name: expectedName, value: expectedValue} = expected.urlencoded;
promise_test(async t => {
$('#container').innerHTML = '<form action="/common/blank.html" target="if1">' +
'<my-control></my-control>' +
'</form>' +
'<iframe name="if1"></iframe>';
if (name !== undefined) {
$('my-control').setAttribute("name", name);
}
if (Array.isArray(value)) {
$('my-control').setValues(value);
} else {
$('my-control').value = value;
}
const query = await submitPromise(t);
assert_equals(query, `?${expectedName}=${expectedValue}`);
}, `${description} (urlencoded)`);
}
// formdata
{
const {name: expectedName, filename: expectedFilename, value: expectedValue} = expected.formdata;
promise_test(async t => {
$('#container').innerHTML =
'<form action="/FileAPI/file/resources/echo-content-escaped.py" method="post" enctype="multipart/form-data" target="if1">' +
'<my-control></my-control>' +
'</form>' +
'<iframe name="if1"></iframe>';
if (name !== undefined) {
$('my-control').setAttribute("name", name);
}
if (Array.isArray(value)) {
$('my-control').setValues(value);
} else {
$('my-control').value = value;
}
const escaped = await submitPromise(t, iframe => iframe.contentDocument.body.textContent);
const formdata = escaped
.replace(/\r\n?|\n/g, "\r\n")
.replace(
/\\x[0-9A-Fa-f]{2}/g,
escape => String.fromCodePoint(parseInt(escape.substring(2), 16))
);
const boundary = formdata.split("\r\n")[0];
const expected = [
boundary,
...(() => {
if (expectedFilename === undefined) {
return [`Content-Disposition: form-data; name="${expectedName}"`];
} else {
return [
`Content-Disposition: form-data; name="${expectedName}"; filename="${expectedFilename}"`,
"Content-Type: text/plain"
];
}
})(),
"",
expectedValue,
boundary + "--",
""
].join("\r\n");
assert_equals(formdata, expected);
}, `${description} (formdata)`);
}
}
promise_test(t => {
@ -145,152 +199,380 @@ promise_test(t => {
testSerializedEntry({
name: 'a\nb',
value: 'c',
expectedName: 'a%0D%0Ab',
expectedValue: 'c',
expected: {
urlencoded: {
name: 'a%0D%0Ab',
value: 'c'
},
formdata: {
name: 'a%0D%0Ab',
value: 'c'
}
},
description: 'Newline normalization - \\n in name'
});
testSerializedEntry({
name: 'a\rb',
value: 'c',
expectedName: 'a%0D%0Ab',
expectedValue: 'c',
expected: {
urlencoded: {
name: 'a%0D%0Ab',
value: 'c'
},
formdata: {
name: 'a%0D%0Ab',
value: 'c'
}
},
description: 'Newline normalization - \\r in name'
});
testSerializedEntry({
name: 'a\r\nb',
value: 'c',
expectedName: 'a%0D%0Ab',
expectedValue: 'c',
expected: {
urlencoded: {
name: 'a%0D%0Ab',
value: 'c'
},
formdata: {
name: 'a%0D%0Ab',
value: 'c'
}
},
description: 'Newline normalization - \\r\\n in name'
});
testSerializedEntry({
name: 'a\n\rb',
value: 'c',
expectedName: 'a%0D%0A%0D%0Ab',
expectedValue: 'c',
expected: {
urlencoded: {
name: 'a%0D%0A%0D%0Ab',
value: 'c'
},
formdata: {
name: 'a%0D%0A%0D%0Ab',
value: 'c'
}
},
description: 'Newline normalization - \\n\\r in name'
});
testSerializedEntry({
name: 'a',
value: 'b\nc',
expectedName: 'a',
expectedValue: 'b%0D%0Ac',
expected: {
urlencoded: {
name: 'a',
value: 'b%0D%0Ac'
},
formdata: {
name: 'a',
value: 'b\r\nc'
}
},
description: 'Newline normalization - \\n in value'
});
testSerializedEntry({
name: 'a',
value: 'b\rc',
expectedName: 'a',
expectedValue: 'b%0D%0Ac',
expected: {
urlencoded: {
name: 'a',
value: 'b%0D%0Ac'
},
formdata: {
name: 'a',
value: 'b\r\nc'
}
},
description: 'Newline normalization - \\r in value'
});
testSerializedEntry({
name: 'a',
value: 'b\r\nc',
expectedName: 'a',
expectedValue: 'b%0D%0Ac',
expected: {
urlencoded: {
name: 'a',
value: 'b%0D%0Ac'
},
formdata: {
name: 'a',
value: 'b\r\nc'
}
},
description: 'Newline normalization - \\r\\n in value'
});
testSerializedEntry({
name: 'a',
value: 'b\n\rc',
expectedName: 'a',
expectedValue: 'b%0D%0A%0D%0Ac',
expected: {
urlencoded: {
name: 'a',
value: 'b%0D%0A%0D%0Ac'
},
formdata: {
name: 'a',
value: 'b\r\n\r\nc'
}
},
description: 'Newline normalization - \\n\\r in value'
});
testSerializedEntry({
name: 'a',
value: new File([], "b\nc"),
expectedName: 'a',
expectedValue: 'b%0D%0Ac',
value: new File([], "b\nc", {type: "text/plain"}),
expected: {
urlencoded: {
name: 'a',
value: 'b%0D%0Ac'
},
formdata: {
name: 'a',
filename: 'b%0Ac',
value: ''
}
},
description: 'Newline normalization - \\n in filename'
});
testSerializedEntry({
name: 'a',
value: new File([], "b\rc"),
expectedName: 'a',
expectedValue: 'b%0D%0Ac',
value: new File([], "b\rc", {type: "text/plain"}),
expected: {
urlencoded: {
name: 'a',
value: 'b%0D%0Ac'
},
formdata: {
name: 'a',
filename: 'b%0Dc',
value: ''
}
},
description: 'Newline normalization - \\r in filename'
});
testSerializedEntry({
name: 'a',
value: new File([], "b\r\nc"),
expectedName: 'a',
expectedValue: 'b%0D%0Ac',
value: new File([], "b\r\nc", {type: "text/plain"}),
expected: {
urlencoded: {
name: 'a',
value: 'b%0D%0Ac'
},
formdata: {
name: 'a',
filename: 'b%0D%0Ac',
value: ''
}
},
description: 'Newline normalization - \\r\\n in filename'
});
testSerializedEntry({
name: 'a',
value: new File([], "b\n\rc"),
expectedName: 'a',
expectedValue: 'b%0D%0A%0D%0Ac',
value: new File([], "b\n\rc", {type: "text/plain"}),
expected: {
urlencoded: {
name: 'a',
value: 'b%0D%0A%0D%0Ac'
},
formdata: {
name: 'a',
filename: 'b%0A%0Dc',
value: ''
}
},
description: 'Newline normalization - \\n\\r in filename'
});
testSerializedEntry({
value: [['a\nb', 'c']],
expectedName: 'a%0Ab',
expectedValue: 'c',
expected: {
urlencoded: {
name: 'a%0D%0Ab',
value: 'c'
},
formdata: {
name: 'a%0D%0Ab',
value: 'c'
}
},
description: 'Newline normalization - \\n in FormData name'
});
testSerializedEntry({
value: [['a\rb', 'c']],
expectedName: 'a%0Db',
expectedValue: 'c',
expected: {
urlencoded: {
name: 'a%0D%0Ab',
value: 'c'
},
formdata: {
name: 'a%0D%0Ab',
value: 'c'
}
},
description: 'Newline normalization - \\r in FormData name'
});
testSerializedEntry({
value: [['a\r\nb', 'c']],
expectedName: 'a%0D%0Ab',
expectedValue: 'c',
expected: {
urlencoded: {
name: 'a%0D%0Ab',
value: 'c'
},
formdata: {
name: 'a%0D%0Ab',
value: 'c'
}
},
description: 'Newline normalization - \\r\\n in FormData name'
});
testSerializedEntry({
value: [['a\n\rb', 'c']],
expectedName: 'a%0A%0Db',
expectedValue: 'c',
expected: {
urlencoded: {
name: 'a%0D%0A%0D%0Ab',
value: 'c'
},
formdata: {
name: 'a%0D%0A%0D%0Ab',
value: 'c'
}
},
description: 'Newline normalization - \\n\\r in FormData name'
});
testSerializedEntry({
value: [['a', 'b\nc']],
expectedName: 'a',
expectedValue: 'b%0Ac',
expected: {
urlencoded: {
name: 'a',
value: 'b%0D%0Ac'
},
formdata: {
name: 'a',
value: 'b\r\nc'
}
},
description: 'Newline normalization - \\n in FormData value'
});
testSerializedEntry({
value: [['a', 'b\rc']],
expectedName: 'a',
expectedValue: 'b%0Dc',
expected: {
urlencoded: {
name: 'a',
value: 'b%0D%0Ac'
},
formdata: {
name: 'a',
value: 'b\r\nc'
}
},
description: 'Newline normalization - \\r in FormData value'
});
testSerializedEntry({
value: [['a', 'b\r\nc']],
expectedName: 'a',
expectedValue: 'b%0D%0Ac',
expected: {
urlencoded: {
name: 'a',
value: 'b%0D%0Ac'
},
formdata: {
name: 'a',
value: 'b\r\nc'
}
},
description: 'Newline normalization - \\r\\n in FormData value'
});
testSerializedEntry({
value: [['a', 'b\n\rc']],
expectedName: 'a',
expectedValue: 'b%0A%0Dc',
expected: {
urlencoded: {
name: 'a',
value: 'b%0D%0A%0D%0Ac'
},
formdata: {
name: 'a',
value: 'b\r\n\r\nc'
}
},
description: 'Newline normalization - \\n\\r in FormData value'
});
testSerializedEntry({
value: [['a', new File([], 'b\nc', {type: "text/plain"})]],
expected: {
urlencoded: {
name: 'a',
value: 'b%0D%0Ac'
},
formdata: {
name: 'a',
filename: 'b%0Ac',
value: ''
}
},
description: 'Newline normalization - \\n in FormData filename'
});
testSerializedEntry({
value: [['a', new File([], 'b\rc', {type: "text/plain"})]],
expected: {
urlencoded: {
name: 'a',
value: 'b%0D%0Ac'
},
formdata: {
name: 'a',
filename: 'b%0Dc',
value: ''
}
},
description: 'Newline normalization - \\r in FormData filename'
});
testSerializedEntry({
value: [['a', new File([], 'b\r\nc', {type: "text/plain"})]],
expected: {
urlencoded: {
name: 'a',
value: 'b%0D%0Ac'
},
formdata: {
name: 'a',
filename: 'b%0D%0Ac',
value: ''
}
},
description: 'Newline normalization - \\r\\n in FormData filename'
});
testSerializedEntry({
value: [['a', new File([], 'b\n\rc', {type: "text/plain"})]],
expected: {
urlencoded: {
name: 'a',
value: 'b%0D%0A%0D%0Ac'
},
formdata: {
name: 'a',
filename: 'b%0A%0Dc',
value: ''
}
},
description: 'Newline normalization - \\n\\r in FormData filename'
});
</script>

Просмотреть файл

@ -114,6 +114,17 @@ t1.step(() => {
form.submit();
});
test(() => {
const form = populateForm('');
form.addEventListener('formdata', e => {
e.formData.append('a\nb', 'c\rd');
});
const formData = new FormData(form);
const [name, value] = [...formData][0];
assert_equals(name, 'a\nb');
assert_equals(value, 'c\rd');
}, 'Entries added to the "formdata" IDL attribute shouldn\'t be newline normalized in the resulting FormData');
test(() => {
let form = populateForm('<input name=n1 value=v1><button type=submit name=n2 value=v2></button>');
let formDataInEvent = null;

Просмотреть файл

@ -0,0 +1,138 @@
(() => {
// Using echo-content-escaped.py rather than
// /fetch/api/resources/echo-content.py to work around WebKit not
// percent-encoding \x00, which causes the response to be detected as
// a binary file and served as a download.
const ACTION_URL = "/FileAPI/file/resources/echo-content-escaped.py";
const IFRAME_NAME = "formtargetframe";
// Undoes the escapes from /fetch/api/resources/echo-content.py
function unescape(str) {
return str
.replace(/\r\n?|\n/g, "\r\n")
.replace(
/\\x[0-9A-Fa-f]{2}/g,
(escape) => String.fromCodePoint(parseInt(escape.substring(2), 16)),
)
.replace(/\\\\/g, "\\");
}
// `expectedBuilder` is a function that takes in the actual form body
// (necessary to get the multipart/form-data payload) and returns the form
// body that should be expected.
// If `testFormData` is false, the form entry will be submitted in for
// controls. If it is true, it will submitted by modifying the entry list
// during the `formdata` event.
async function formSubmissionTest({
name,
value,
expectedBuilder,
enctype,
formEncoding,
testFormData = false,
testCase,
}) {
if (document.readyState !== "complete") {
await new Promise((resolve) => addEventListener("load", resolve));
}
const formTargetFrame = Object.assign(document.createElement("iframe"), {
name: IFRAME_NAME,
});
document.body.append(formTargetFrame);
testCase.add_cleanup(() => {
document.body.removeChild(formTargetFrame);
});
const form = Object.assign(document.createElement("form"), {
acceptCharset: formEncoding,
action: ACTION_URL,
method: "POST",
enctype,
target: IFRAME_NAME,
});
document.body.append(form);
testCase.add_cleanup(() => {
document.body.removeChild(form);
});
if (!testFormData) {
const input = document.createElement("input");
input.name = name;
if (value instanceof File) {
input.type = "file";
const dataTransfer = new DataTransfer();
dataTransfer.items.add(value);
input.files = dataTransfer.files;
} else {
input.type = "hidden";
input.value = value;
}
form.append(input);
} else {
form.addEventListener("formdata", (evt) => {
evt.formData.append(name, value);
});
}
await new Promise((resolve) => {
form.submit();
formTargetFrame.onload = resolve;
});
const serialized = unescape(
formTargetFrame.contentDocument.body.textContent,
);
const expected = expectedBuilder(serialized);
assert_equals(serialized, expected);
}
// This function returns a function to add individual form tests corresponding
// to some enctype.
// `expectedBuilder` is a function that takes two parameters: `expected` (the
// `expected` value of a test) and `serialized` (the actual form body
// submitted by the browser), and returns the correct form body that should
// have been submitted. This is necessary in order to account for th
// multipart/form-data boundary.
window.formSubmissionTemplate = (enctype, expectedBuilder) => {
function form({
name,
value,
expected,
formEncoding = "utf-8",
description,
}) {
const commonParams = {
name,
value,
expectedBuilder: expectedBuilder.bind(null, expected),
enctype,
formEncoding,
};
// Normal form
promise_test(
(testCase) =>
formSubmissionTest({
...commonParams,
testCase,
}),
`${enctype}: ${description} (normal form)`,
);
// formdata event
promise_test(
(testCase) =>
formSubmissionTest({
...commonParams,
testFormData: true,
testCase,
}),
`${enctype}: ${description} (formdata event)`,
);
}
return form;
};
})();

Просмотреть файл

@ -0,0 +1,343 @@
// META: script=enctypes-helper.js
// Form submissions in multipart/form-data are also tested in
// /FileAPI/file/send-file*
const form = formSubmissionTemplate(
"multipart/form-data",
({ name, filename, value }, serialized) => {
let headers;
if (filename === undefined) {
headers = [`Content-Disposition: form-data; name="${name}"`];
} else {
headers = [
`Content-Disposition: form-data; name="${name}"; filename="${filename}"`,
"Content-Type: text/plain",
];
}
const boundary = serialized.split("\r\n")[0];
return [
boundary,
...headers,
"",
value,
boundary + "--",
"",
].join("\r\n");
},
);
form({
name: "basic",
value: "test",
expected: {
name: "basic",
value: "test",
},
description: "Basic test",
});
form({
name: "basic",
value: new File([], "file-test.txt", { type: "text/plain" }),
expected: {
name: "basic",
filename: "file-test.txt",
value: "",
},
description: "Basic File test",
});
form({
name: "a\0b",
value: "c",
expected: {
name: "a\0b",
value: "c",
},
description: "0x00 in name",
});
form({
name: "a",
value: "b\0c",
expected: {
name: "a",
value: "b\0c",
},
description: "0x00 in value",
});
form({
name: "a",
value: new File([], "b\0c", { type: "text/plain" }),
expected: {
name: "a",
filename: "b\0c",
value: "",
},
description: "0x00 in filename",
});
form({
name: "a\nb",
value: "c",
expected: {
name: "a%0D%0Ab",
value: "c",
},
description: "\\n in name",
});
form({
name: "a\rb",
value: "c",
expected: {
name: "a%0D%0Ab",
value: "c",
},
description: "\\r in name",
});
form({
name: "a\r\nb",
value: "c",
expected: {
name: "a%0D%0Ab",
value: "c",
},
description: "\\r\\n in name",
});
form({
name: "a\n\rb",
value: "c",
expected: {
name: "a%0D%0A%0D%0Ab",
value: "c",
},
description: "\\n\\r in name",
});
form({
name: "a",
value: "b\nc",
expected: {
name: "a",
value: "b\r\nc",
},
description: "\\n in value",
});
form({
name: "a",
value: "b\rc",
expected: {
name: "a",
value: "b\r\nc",
},
description: "\\r in value",
});
form({
name: "a",
value: "b\r\nc",
expected: {
name: "a",
value: "b\r\nc",
},
description: "\\r\\n in value",
});
form({
name: "a",
value: "b\n\rc",
expected: {
name: "a",
value: "b\r\n\r\nc",
},
description: "\\n\\r in value",
});
form({
name: "a",
value: new File([], "b\nc", { type: "text/plain" }),
expected: {
name: "a",
filename: "b%0Ac",
value: "",
},
description: "\\n in filename",
});
form({
name: "a",
value: new File([], "b\rc", { type: "text/plain" }),
expected: {
name: "a",
filename: "b%0Dc",
value: "",
},
description: "\\r in filename",
});
form({
name: "a",
value: new File([], "b\r\nc", { type: "text/plain" }),
expected: {
name: "a",
filename: "b%0D%0Ac",
value: "",
},
description: "\\r\\n in filename",
});
form({
name: "a",
value: new File([], "b\n\rc", { type: "text/plain" }),
expected: {
name: "a",
filename: "b%0A%0Dc",
value: "",
},
description: "\\n\\r in filename",
});
form({
name: 'a"b',
value: "c",
expected: {
name: "a%22b",
value: "c",
},
description: "double quote in name",
});
form({
name: "a",
value: 'b"c',
expected: {
name: "a",
value: 'b"c',
},
description: "double quote in value",
});
form({
name: "a",
value: new File([], 'b"c', { type: "text/plain" }),
expected: {
name: "a",
filename: "b%22c",
value: "",
},
description: "double quote in filename",
});
form({
name: "a'b",
value: "c",
expected: {
name: "a'b",
value: "c",
},
description: "single quote in name",
});
form({
name: "a",
value: "b'c",
expected: {
name: "a",
value: "b'c",
},
description: "single quote in value",
});
form({
name: "a",
value: new File([], "b'c", { type: "text/plain" }),
expected: {
name: "a",
filename: "b'c",
value: "",
},
description: "single quote in filename",
});
form({
name: "a\\b",
value: "c",
expected: {
name: "a\\b",
value: "c",
},
description: "backslash in name",
});
form({
name: "a",
value: "b\\c",
expected: {
name: "a",
value: "b\\c",
},
description: "backslash in value",
});
form({
name: "a",
value: new File([], "b\\c", { type: "text/plain" }),
expected: {
name: "a",
filename: "b\\c",
value: "",
},
description: "backslash in filename",
});
form({
name: "áb",
value: "ç",
expected: {
name: "\xC3\xA1b",
value: "\xC3\xA7",
},
description: "non-ASCII in name and value",
});
form({
name: "a",
value: new File([], "ə.txt", { type: "text/plain" }),
expected: {
name: "a",
filename: "\xC9\x99.txt",
value: "",
},
description: "non-ASCII in filename",
});
form({
name: "aəb",
value: "c\uFFFDd",
formEncoding: "windows-1252",
expected: {
name: "a&#601;b",
value: "c&#65533;d",
},
description: "characters not in encoding in name and value",
});
form({
name: "á",
value: new File([], "💩", { type: "text/plain" }),
formEncoding: "windows-1252",
expected: {
name: "\xE1",
filename: "&#128169;",
value: "",
},
description: "character not in encoding in filename",
});

Просмотреть файл

@ -0,0 +1,218 @@
// META: script=enctypes-helper.js
const form = formSubmissionTemplate(
"text/plain",
(expected) => expected,
);
form({
name: "basic",
value: "test",
expected: "basic=test\r\n",
description: "Basic test",
});
form({
name: "basic",
value: new File([], "file-test.txt"),
expected: "basic=file-test.txt\r\n",
description: "Basic File test",
});
form({
name: "a\0b",
value: "c",
expected: "a\0b=c\r\n",
description: "0x00 in name",
});
form({
name: "a",
value: "b\0c",
expected: "a=b\0c\r\n",
description: "0x00 in value",
});
form({
name: "a",
value: new File([], "b\0c"),
expected: "a=b\0c\r\n",
description: "0x00 in filename",
});
form({
name: "a\nb",
value: "c",
expected: "a\r\nb=c\r\n",
description: "\\n in name",
});
form({
name: "a\rb",
value: "c",
expected: "a\r\nb=c\r\n",
description: "\\r in name",
});
form({
name: "a\r\nb",
value: "c",
expected: "a\r\nb=c\r\n",
description: "\\r\\n in name",
});
form({
name: "a\n\rb",
value: "c",
expected: "a\r\n\r\nb=c\r\n",
description: "\\n\\r in name",
});
form({
name: "a",
value: "b\nc",
expected: "a=b\r\nc\r\n",
description: "\\n in value",
});
form({
name: "a",
value: "b\rc",
expected: "a=b\r\nc\r\n",
description: "\\r in value",
});
form({
name: "a",
value: "b\r\nc",
expected: "a=b\r\nc\r\n",
description: "\\r\\n in value",
});
form({
name: "a",
value: "b\n\rc",
expected: "a=b\r\n\r\nc\r\n",
description: "\\n\\r in value",
});
form({
name: "a",
value: new File([], "b\nc"),
expected: "a=b\r\nc\r\n",
description: "\\n in filename",
});
form({
name: "a",
value: new File([], "b\rc"),
expected: "a=b\r\nc\r\n",
description: "\\r in filename",
});
form({
name: "a",
value: new File([], "b\r\nc"),
expected: "a=b\r\nc\r\n",
description: "\\r\\n in filename",
});
form({
name: "a",
value: new File([], "b\n\rc"),
expected: "a=b\r\n\r\nc\r\n",
description: "\\n\\r in filename",
});
form({
name: 'a"b',
value: "c",
expected: 'a"b=c\r\n',
description: "double quote in name",
});
form({
name: "a",
value: 'b"c',
expected: 'a=b"c\r\n',
description: "double quote in value",
});
form({
name: "a",
value: new File([], 'b"c'),
expected: 'a=b"c\r\n',
description: "double quote in filename",
});
form({
name: "a'b",
value: "c",
expected: "a'b=c\r\n",
description: "single quote in name",
});
form({
name: "a",
value: "b'c",
expected: "a=b'c\r\n",
description: "single quote in value",
});
form({
name: "a",
value: new File([], "b'c"),
expected: "a=b'c\r\n",
description: "single quote in filename",
});
form({
name: "a\\b",
value: "c",
expected: "a\\b=c\r\n",
description: "backslash in name",
});
form({
name: "a",
value: "b\\c",
expected: "a=b\\c\r\n",
description: "backslash in value",
});
form({
name: "a",
value: new File([], "b\\c"),
expected: "a=b\\c\r\n",
description: "backslash in filename",
});
form({
name: "áb",
value: "ç",
expected: "\xC3\xA1b=\xC3\xA7\r\n",
description: "non-ASCII in name and value",
});
form({
name: "a",
value: new File([], "ə.txt"),
expected: "a=\xC9\x99.txt\r\n",
description: "non-ASCII in filename",
});
form({
name: "aəb",
value: "c\uFFFDd",
formEncoding: "windows-1252",
expected: "a&#601;b=c&#65533;d\r\n",
description: "characters not in encoding in name and value",
});
form({
name: "á",
value: new File([], "💩"),
formEncoding: "windows-1252",
expected: "\xE1=&#128169;\r\n",
description: "character not in encoding in filename",
});

Просмотреть файл

@ -0,0 +1,218 @@
// META: script=enctypes-helper.js
const form = formSubmissionTemplate(
"application/x-www-form-urlencoded",
(expected) => expected,
);
form({
name: "basic",
value: "test",
expected: "basic=test",
description: "Basic test",
});
form({
name: "basic",
value: new File([], "file-test.txt"),
expected: "basic=file-test.txt",
description: "Basic File test",
});
form({
name: "a\0b",
value: "c",
expected: "a%00b=c",
description: "0x00 in name",
});
form({
name: "a",
value: "b\0c",
expected: "a=b%00c",
description: "0x00 in value",
});
form({
name: "a",
value: new File([], "b\0c"),
expected: "a=b%00c",
description: "0x00 in filename",
});
form({
name: "a\nb",
value: "c",
expected: "a%0D%0Ab=c",
description: "\\n in name",
});
form({
name: "a\rb",
value: "c",
expected: "a%0D%0Ab=c",
description: "\\r in name",
});
form({
name: "a\r\nb",
value: "c",
expected: "a%0D%0Ab=c",
description: "\\r\\n in name",
});
form({
name: "a\n\rb",
value: "c",
expected: "a%0D%0A%0D%0Ab=c",
description: "\\n\\r in name",
});
form({
name: "a",
value: "b\nc",
expected: "a=b%0D%0Ac",
description: "\\n in value",
});
form({
name: "a",
value: "b\rc",
expected: "a=b%0D%0Ac",
description: "\\r in value",
});
form({
name: "a",
value: "b\r\nc",
expected: "a=b%0D%0Ac",
description: "\\r\\n in value",
});
form({
name: "a",
value: "b\n\rc",
expected: "a=b%0D%0A%0D%0Ac",
description: "\\n\\r in value",
});
form({
name: "a",
value: new File([], "b\nc"),
expected: "a=b%0D%0Ac",
description: "\\n in filename",
});
form({
name: "a",
value: new File([], "b\rc"),
expected: "a=b%0D%0Ac",
description: "\\r in filename",
});
form({
name: "a",
value: new File([], "b\r\nc"),
expected: "a=b%0D%0Ac",
description: "\\r\\n in filename",
});
form({
name: "a",
value: new File([], "b\n\rc"),
expected: "a=b%0D%0A%0D%0Ac",
description: "\\n\\r in filename",
});
form({
name: 'a"b',
value: "c",
expected: "a%22b=c",
description: "double quote in name",
});
form({
name: "a",
value: 'b"c',
expected: "a=b%22c",
description: "double quote in value",
});
form({
name: "a",
value: new File([], 'b"c'),
expected: "a=b%22c",
description: "double quote in filename",
});
form({
name: "a'b",
value: "c",
expected: "a%27b=c",
description: "single quote in name",
});
form({
name: "a",
value: "b'c",
expected: "a=b%27c",
description: "single quote in value",
});
form({
name: "a",
value: new File([], "b'c"),
expected: "a=b%27c",
description: "single quote in filename",
});
form({
name: "a\\b",
value: "c",
expected: "a%5Cb=c",
description: "backslash in name",
});
form({
name: "a",
value: "b\\c",
expected: "a=b%5Cc",
description: "backslash in value",
});
form({
name: "a",
value: new File([], "b\\c"),
expected: "a=b%5Cc",
description: "backslash in filename",
});
form({
name: "áb",
value: "ç",
expected: "%C3%A1b=%C3%A7",
description: "non-ASCII in name and value",
});
form({
name: "a",
value: new File([], "ə.txt"),
expected: "a=%C9%99.txt",
description: "non-ASCII in filename",
});
form({
name: "aəb",
value: "c\uFFFDd",
formEncoding: "windows-1252",
expected: "a%26%23601%3Bb=c%26%2365533%3Bd",
description: "characters not in encoding in name and value",
});
form({
name: "á",
value: new File([], "💩"),
formEncoding: "windows-1252",
expected: "%E1=%26%23128169%3B",
description: "character not in encoding in filename",
});

Просмотреть файл

@ -133,3 +133,13 @@ test(() => {
assert_equals(url.toString(), 'http://www.example.com/?a=b%2Cc&x=y');
assert_equals(params.toString(), 'a=b%2Cc&x=y');
}, 'URLSearchParams connected to URL');
test(() => {
const url = new URL('http://www.example.com/');
const params = url.searchParams;
params.append('a\nb', 'c\rd');
params.append('e\n\rf', 'g\r\nh');
assert_equals(params.toString(), "a%0Ab=c%0Dd&e%0A%0Df=g%0D%0Ah");
}, 'URLSearchParams must not do newline normalization');