summaryrefslogtreecommitdiffstats
path: root/toolkit/components/extensions/test/mochitest/test_ext_webrequest_upload.html
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/extensions/test/mochitest/test_ext_webrequest_upload.html')
-rw-r--r--toolkit/components/extensions/test/mochitest/test_ext_webrequest_upload.html265
1 files changed, 265 insertions, 0 deletions
diff --git a/toolkit/components/extensions/test/mochitest/test_ext_webrequest_upload.html b/toolkit/components/extensions/test/mochitest/test_ext_webrequest_upload.html
new file mode 100644
index 0000000000..30ecb0aa78
--- /dev/null
+++ b/toolkit/components/extensions/test/mochitest/test_ext_webrequest_upload.html
@@ -0,0 +1,265 @@
+<!DOCTYPE HTML>
+
+<html>
+<head>
+<meta charset="utf-8">
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
+ <script type="text/javascript" src="head.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+<form method="post"
+ action="file_WebRequest_page3.html?trigger=form"
+ target="_blank"
+ enctype="multipart/form-data"
+ >
+<input type="text" name="&quot;special&quot; &#x0D;&#x0A; ch�rs" value="sp�cial">
+<input type="file" name="testFile">
+<input type="file" name="emptyFile">
+<input type="text" name="textInput1" value="value1">
+</form>
+
+<form method="post"
+ action="file_WebRequest_page3.html?trigger=form"
+ target="_blank"
+ enctype="multipart/form-data"
+ >
+<input type="text" name="textInput2" value="value2">
+<input type="file" name="testFile">
+<input type="file" name="emptyFile">
+</form>
+
+</form>
+<form method="post"
+ action="file_WebRequest_page3.html?trigger=form"
+ target="_blank"
+ >
+<input type="text" name="textInput" value="value1">
+<input type="text" name="textInput" value="value2">
+</form>
+<script>
+"use strict";
+
+let files, testFile, blob, file, uploads;
+add_task(async function test_setup() {
+ files = await new Promise(resolve => {
+ SpecialPowers.createFiles([{name: "testFile.pdf", data: "Not really a PDF file :)", "type": "application/x-pdf"}], (result) => {
+ resolve(result);
+ });
+ });
+ testFile = files[0];
+ blob = {
+ name: "blobAsFile",
+ content: new Blob(["A blob sent as a file"], {type: "text/csv"}),
+ fileName: "blobAsFile.csv",
+ };
+ file = {
+ name: "testFile",
+ fileName: testFile.name,
+ };
+ uploads = {
+ [blob.name]: blob,
+ [file.name]: file,
+ "emptyFile": {fileName: ""}
+ };
+});
+
+function background() {
+ const FILTERS = {urls: ["<all_urls>"]};
+
+ function onUpload(details) {
+ let url = new URL(details.url);
+ let upload = url.searchParams.get("upload");
+ if (!upload) {
+ return;
+ }
+
+ let requestBody = details.requestBody;
+ browser.test.log(`onBeforeRequest upload: ${details.url} ${JSON.stringify(details.requestBody)}`);
+ browser.test.assertTrue(!!requestBody, `Intercepted upload ${details.url} #${details.requestId} ${upload} have a requestBody`);
+ if (!requestBody) {
+ return;
+ }
+ let byteLength = parseInt(upload, 10);
+ if (byteLength) {
+ browser.test.assertTrue(!!requestBody.raw, `Binary upload ${details.url} #${details.requestId} ${upload} have a raw attribute`);
+ browser.test.assertEq(byteLength, requestBody.raw && requestBody.raw.map(r => r.bytes ? r.bytes.byteLength : 0).reduce((a, b) => a + b), `Binary upload size matches`);
+ return;
+ }
+ if ("raw" in requestBody) {
+ browser.test.assertEq(upload, JSON.stringify(requestBody.raw).replace(/(\bfile: ")[^"]+/, "$1<file>"), `Upload ${details.url} #${details.requestId} matches raw data`);
+ } else {
+ browser.test.assertEq(upload, JSON.stringify(requestBody.formData), `Upload ${details.url} #${details.requestId} matches form data.`);
+ }
+ }
+
+ browser.webRequest.onCompleted.addListener(
+ details => {
+ browser.test.log(`onCompleted ${details.requestId} ${details.url}`);
+ // See bug 1471387
+ if (details.url.endsWith("/favicon.ico") || details.originUrl == "about:newtab") {
+ return;
+ }
+
+ browser.test.sendMessage("done");
+ },
+ FILTERS);
+
+ let onBeforeRequest = details => {
+ browser.test.log(`${name} ${details.requestId} ${details.url}`);
+ // See bug 1471387
+ if (details.url.endsWith("/favicon.ico") || details.originUrl == "about:newtab") {
+ return;
+ }
+
+ onUpload(details);
+ };
+
+ browser.webRequest.onBeforeRequest.addListener(
+ onBeforeRequest, FILTERS, ["requestBody"]);
+
+ let tab;
+ browser.tabs.onCreated.addListener(newTab => {
+ tab = newTab;
+ });
+
+ browser.test.onMessage.addListener(msg => {
+ if (msg === "close-tab") {
+ browser.tabs.remove(tab.id);
+ browser.test.sendMessage("tab-closed");
+ }
+ });
+}
+
+add_task(async function test_xhr_forms() {
+ let extension = ExtensionTestUtils.loadExtension({
+ manifest: {
+ permissions: [
+ "tabs",
+ "webRequest",
+ "webRequestBlocking",
+ "<all_urls>",
+ ],
+ },
+ background,
+ });
+
+ await extension.startup();
+
+ async function doneAndTabClosed() {
+ await extension.awaitMessage("done");
+ let closed = extension.awaitMessage("tab-closed");
+ extension.sendMessage("close-tab");
+ await closed;
+ }
+
+ for (let form of document.forms) {
+ if (file.name in form.elements) {
+ SpecialPowers.wrap(form.elements[file.name]).mozSetFileArray(files);
+ }
+ let action = new URL(form.action);
+ let formData = new FormData(form);
+ let webRequestFD = {};
+
+ let updateActionURL = () => {
+ for (let name of formData.keys()) {
+ webRequestFD[name] = name in uploads ? [uploads[name].fileName] : formData.getAll(name);
+ }
+ action.searchParams.set("upload", JSON.stringify(webRequestFD));
+ action.searchParams.set("enctype", form.enctype);
+ };
+
+ updateActionURL();
+
+ form.action = action;
+ form.submit();
+ await doneAndTabClosed();
+
+ if (form.enctype !== "multipart/form-data") {
+ continue;
+ }
+
+ let post = (data) => {
+ let xhr = new XMLHttpRequest();
+ action.searchParams.set("xhr", "1");
+ xhr.open("POST", action.href);
+ xhr.send(data);
+ action.searchParams.delete("xhr");
+ return doneAndTabClosed();
+ };
+
+ formData.append(blob.name, blob.content, blob.fileName);
+ formData.append("formDataField", "some value");
+ updateActionURL();
+ await post(formData);
+
+ action.searchParams.set("upload", JSON.stringify([{file: "<file>"}]));
+ await post(testFile);
+
+ action.searchParams.set("upload", `${blob.content.size} bytes`);
+ await post(blob.content);
+
+ let byteLength = 16;
+ action.searchParams.set("upload", `${byteLength} bytes`);
+ await post(new ArrayBuffer(byteLength));
+ }
+
+ // Testing the decoding of percent escapes even in cases where the
+ // multipart/form-data serializer won't emit them.
+ {
+ let boundary = "-".repeat(27);
+ for (let i = 0; i < 3; i++) {
+ const randomNumber = Math.floor(Math.random() * (2 ** 32));
+ boundary += String(randomNumber);
+ }
+
+ const formPayload = [
+ `--${boundary}`,
+ 'Content-Disposition: form-data; name="percent escapes other than%20quotes and newlines"',
+ "",
+ "",
+ `--${boundary}`,
+ 'Content-Disposition: form-data; name="valid UTF-8: %F0%9F%92%A9"',
+ "",
+ "",
+ `--${boundary}`,
+ 'Content-Disposition: form-data; name="broken UTF-8: %F0%9F %92%A9"',
+ "",
+ "",
+ `--${boundary}`,
+ 'Content-Disposition: form-data; name="percent escapes aren\'t decoded in filenames"; filename="%0D%0A%22"',
+ "Content-Type: application/octet-stream",
+ "",
+ "",
+ `--${boundary}--`,
+ ""
+ ].join("\r\n");
+
+ const action = new URL("file_WebRequest_page3.html?trigger=form", document.location.href);
+ action.searchParams.set("xhr", "1");
+ action.searchParams.set("upload", JSON.stringify({
+ "percent escapes other than quotes and newlines": [""],
+ "valid UTF-8: 💩": [""],
+ "broken UTF-8: � ��": [""],
+ "percent escapes aren't decoded in filenames": ["%0D%0A%22"]
+ }));
+ action.searchParams.set("enctype", "multipart/form-data");
+
+ await fetch(
+ action.href,
+ {
+ method: "POST",
+ headers: {"Content-Type": `multipart/form-data; boundary=${boundary}`},
+ body: formPayload
+ },
+ );
+ await doneAndTabClosed();
+ }
+
+ await extension.unload();
+});
+</script>
+</body>
+</html>