Bug 1314493 simplify xhr webrequest tests for uploads, fix xhr blob send, r=kmag
MozReview-Commit-ID: 4sQGgwD6HMC
--- a/toolkit/components/extensions/test/mochitest/file_WebRequest_page1.html
+++ b/toolkit/components/extensions/test/mochitest/file_WebRequest_page1.html
@@ -24,110 +24,20 @@
<script src="nonexistent_script_url.js"></script>
<iframe src="file_WebRequest_page2.html" width="200" height="200"></iframe>
<iframe src="redirection.sjs" width="200" height="200"></iframe>
<iframe src="data:text/plain,webRequestTest" width="200" height="200"></iframe>
<iframe src="data:text/plain,webRequestTest_bad" width="200" height="200"></iframe>
<iframe src="https://invalid.localhost/" width="200" height="200"></iframe>
<a href="file_WebRequest_page3.html?trigger=a" target="webrequest_link">link</a>
-<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 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>
+<form method="post" action="file_WebRequest_page3.html?trigger=form" target="webrequest_form"></form>
<script>
"use strict";
for (let a of document.links) {
a.click();
}
-
-SpecialPowers.createFiles([{name: "testFile.pdf", data: "Not really a PDF file :)", "type": "application/x-pdf"}], (files) => {
- let testFile = files[0];
- let blob = {
- name: "blobAsFile",
- content: new Blob(["A blob sent as a file"], {type: "text/csv"}),
- fileName: "blobAsFile.csv",
- };
- let file = {
- name: "testFile",
- fileName: testFile.name,
- };
- let uploads = {
- [blob.name]: blob,
- [file.name]: file,
- };
-
- 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();
-
- if (form.enctype === "multipart/form-data") {
- let post = (data) => {
- let xhr = new XMLHttpRequest();
- action.searchParams.set("xhr", "1");
- xhr.open("POST", action.href);
- xhr.send(data);
- action.searchParams.delete("xhr");
- };
-
- formData.append(blob.name, blob.content, blob.fileName);
- formData.append("formDataField", "some value");
- updateActionURL(true);
- post(formData);
-
- action.searchParams.set("upload", JSON.stringify([{file: "<file>"}]));
- post(testFile);
-
- let blobReader = new FileReader();
- blobReader.readAsArrayBuffer(blob.content);
- blobReader.onload = () => {
- action.searchParams.set("upload", `${blobReader.result.byteLength} bytes`);
- post(blob.content);
- };
- let byteLength = 16;
- action.searchParams.set("upload", `${byteLength} bytes`);
- post(new ArrayBuffer(byteLength));
- }
- }
-});
+for (let f of document.forms) {
+ f.submit();
+}
</script>
</body>
</html>
--- a/toolkit/components/extensions/test/mochitest/mochitest.ini
+++ b/toolkit/components/extensions/test/mochitest/mochitest.ini
@@ -86,15 +86,17 @@ skip-if = (os == 'android' || buildapp =
skip-if = (os == 'android') # Android does not support tabs API. Bug 1260250
[test_ext_unload_frame.html]
[test_ext_i18n.html]
skip-if = (os == 'android') # Bug 1258975 on android.
[test_ext_web_accessible_resources.html]
skip-if = (os == 'android') # Bug 1258975 on android.
[test_ext_webrequest.html]
skip-if = os == 'android' # webrequest api unsupported (bug 1258975).
+[test_ext_webrequest_upload.html]
+skip-if = os == 'android' # webrequest api unsupported (bug 1258975).
[test_ext_webnavigation.html]
skip-if = os == 'android' # port.sender.tab is undefined on Android (bug 1258975).
[test_ext_webnavigation_filters.html]
skip-if = os == 'android' # port.sender.tab is undefined on Android (bug 1258975).
[test_ext_subframes_privileges.html]
skip-if = os == 'android' # port.sender.tab is undefined on Android (bug 1258975).
[test_ext_xhr_capabilities.html]
--- a/toolkit/components/extensions/test/mochitest/test_ext_webrequest.html
+++ b/toolkit/components/extensions/test/mochitest/test_ext_webrequest.html
@@ -323,41 +323,16 @@ function backgroundScript() {
}
}
if (details.url.includes("_bad")) {
return {cancel: true};
}
return {};
}
- 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(`onUpload ${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.`);
- }
- }
-
function onBeforeSendHeaders(details) {
browser.test.log(`onBeforeSendHeaders ${details.url}`);
checkRequestId(details);
checkOrigin(details);
checkResourceType(details.type);
processHeaders("request", details);
if (shouldRecord(details.url)) {
recorded.beforeSendHeaders.push(details.url);
@@ -464,24 +439,16 @@ function backgroundScript() {
}
function onCompleted(details) {
checkFromCache("completed", details);
checkHeaders("response", details);
}
browser.webRequest.onBeforeRequest.addListener(onBeforeRequest, {urls: ["<all_urls>"]}, ["blocking"]);
- try {
- browser.webRequest.onBeforeRequest.addListener(onUpload, {urls: ["http://*/*"]}, ["blocking", "requestBody"]);
- } catch (e) {
- // requestBody is disabled in release builds
- if (!/\brequestBody\b/.test(e.message)) {
- throw e;
- }
- }
browser.webRequest.onBeforeSendHeaders.addListener(onBeforeSendHeaders, {urls: ["<all_urls>"]}, ["blocking", "requestHeaders"]);
browser.webRequest.onSendHeaders.addListener(onSendHeaders, {urls: ["<all_urls>"]}, ["requestHeaders"]);
browser.webRequest.onBeforeRedirect.addListener(onBeforeRedirect, {urls: ["<all_urls>"]});
browser.webRequest.onHeadersReceived.addListener(onHeadersReceived, {urls: ["<all_urls>"]}, ["blocking", "responseHeaders"]);
browser.webRequest.onResponseStarted.addListener(checkFromCache.bind(null, "responseStarted"), {urls: ["<all_urls>"]});
browser.webRequest.onResponseStarted.addListener(checkFromCache.bind(null, "responseStarted2"), {urls: ["<all_urls>"]});
browser.webRequest.onErrorOccurred.addListener(onErrorOccurred, {urls: ["<all_urls>"]});
browser.webRequest.onCompleted.addListener(onCompleted, {urls: ["<all_urls>"]}, ["responseHeaders"]);
new file mode 100644
--- /dev/null
+++ b/toolkit/components/extensions/test/mochitest/test_ext_webrequest_upload.html
@@ -0,0 +1,195 @@
+<!DOCTYPE HTML>
+
+<html>
+<head>
+<meta charset="utf-8">
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
+ <script type="text/javascript" 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(function* test_setup() {
+ files = yield new Promise(resolve => {
+ SpecialPowers.createFiles([{name: "testFile.pdf", data: "Not really a PDF file :)", "type": "application/x-pdf"}], (files) => {
+ resolve(files);
+ });
+ });
+ 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,
+ };
+});
+
+function background() {
+ let events = {
+ "onBeforeRequest": [{urls: ["<all_urls>"]}, ["blocking", "requestBody"]],
+ "onCompleted": [{urls: ["<all_urls>"]}, ["responseHeaders"]],
+ };
+
+ 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(`onUpload ${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.`);
+ }
+ }
+
+ function listener(name, details) {
+ browser.test.log(`${name} ${details.requestId} ${details.url}`);
+
+ if (name == "onBeforeRequest") {
+ onUpload(details);
+ } else if (name == "onCompleted") {
+ browser.test.sendMessage("done");
+ }
+ }
+
+ for (let [name, args] of Object.entries(events)) {
+ try {
+ browser.test.log(`adding listener for ${name}`);
+ browser.webRequest[name].addListener(
+ listener.bind(null, name), ...args);
+ } catch (e) {
+ // requestBody is disabled in release builds
+ if (!/\brequestBody\b/.test(e.message)) {
+ args.pop();
+ browser.webRequest[name].addListener(
+ listener.bind(null, name), ...args);
+ }
+ }
+ }
+}
+
+add_task(function* test_xhr_forms() {
+ let extension = ExtensionTestUtils.loadExtension({
+ manifest: {
+ permissions: [
+ "webRequest",
+ "webRequestBlocking",
+ "<all_urls>",
+ ],
+ },
+ background,
+ });
+
+ yield extension.startup();
+
+ 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();
+ yield extension.awaitMessage("done");
+
+ 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 extension.awaitMessage("done");
+ };
+
+ formData.append(blob.name, blob.content, blob.fileName);
+ formData.append("formDataField", "some value");
+ updateActionURL();
+ yield post(formData);
+
+ action.searchParams.set("upload", JSON.stringify([{file: "<file>"}]));
+ yield post(testFile);
+
+ action.searchParams.set("upload", `${blob.content.size} bytes`);
+ yield post(blob.content);
+
+ let byteLength = 16;
+ action.searchParams.set("upload", `${byteLength} bytes`);
+ yield post(new ArrayBuffer(byteLength));
+ }
+
+ yield extension.unload();
+});
+</script>
+</body>
+</html>
--- a/toolkit/modules/addons/WebRequestUpload.jsm
+++ b/toolkit/modules/addons/WebRequestUpload.jsm
@@ -14,17 +14,19 @@ const Cu = Components.utils;
const Cr = Components.results;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
var WebRequestUpload;
function rewind(stream) {
try {
- stream.seek(0, 0);
+ if (stream instanceof Ci.nsISeekableStream) {
+ stream.seek(0, 0);
+ }
} catch (e) {
// It might be already closed, e.g. because of a previous error.
}
}
function parseFormData(stream, channel, lenient = false) {
const BUFFER_SIZE = 8192; // Empirically it seemed a good compromise.