diff options
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.html | 265 |
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=""special" 
 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> |