summaryrefslogtreecommitdiffstats
path: root/netwerk/test/browser
diff options
context:
space:
mode:
Diffstat (limited to 'netwerk/test/browser')
-rw-r--r--netwerk/test/browser/browser.ini31
-rw-r--r--netwerk/test/browser/browser_NetUtil.js112
-rw-r--r--netwerk/test/browser/browser_about_cache.js126
-rw-r--r--netwerk/test/browser/browser_bug1535877.js15
-rw-r--r--netwerk/test/browser/browser_child_resource.js247
-rw-r--r--netwerk/test/browser/browser_cookie_sync_across_tabs.js79
-rw-r--r--netwerk/test/browser/browser_fetch_lnk.js27
-rw-r--r--netwerk/test/browser/browser_nsIFormPOSTActionChannel.js292
-rw-r--r--netwerk/test/browser/browser_post_file.js78
-rw-r--r--netwerk/test/browser/browser_resource_navigation.js76
-rw-r--r--netwerk/test/browser/browser_test_favicon.js26
-rw-r--r--netwerk/test/browser/browser_test_io_activity.js50
-rw-r--r--netwerk/test/browser/damonbowling.jpgbin0 -> 44008 bytes
-rw-r--r--netwerk/test/browser/damonbowling.jpg^headers^2
-rw-r--r--netwerk/test/browser/dummy.html11
-rw-r--r--netwerk/test/browser/file_favicon.html7
-rw-r--r--netwerk/test/browser/file_lnk.lnkbin0 -> 1531 bytes
-rw-r--r--netwerk/test/browser/ioactivity.html11
-rw-r--r--netwerk/test/browser/redirect.sjs7
19 files changed, 1197 insertions, 0 deletions
diff --git a/netwerk/test/browser/browser.ini b/netwerk/test/browser/browser.ini
new file mode 100644
index 0000000000..dbe43345f2
--- /dev/null
+++ b/netwerk/test/browser/browser.ini
@@ -0,0 +1,31 @@
+[DEFAULT]
+support-files =
+ dummy.html
+ ioactivity.html
+ redirect.sjs
+
+[browser_about_cache.js]
+[browser_bug1535877.js]
+[browser_NetUtil.js]
+[browser_child_resource.js]
+skip-if = !crashreporter
+ (e10s && debug && os == "linux" && bits == 64)
+ debug # Bug 1370783
+ fission # Bug 1670867
+[browser_post_file.js]
+[browser_nsIFormPOSTActionChannel.js]
+skip-if = e10s # protocol handler and channel does not work in content process
+[browser_resource_navigation.js]
+[browser_test_io_activity.js]
+skip-if = socketprocess_networking
+[browser_cookie_sync_across_tabs.js]
+[browser_test_favicon.js]
+skip-if = (verify && (os == 'linux' || os == 'mac'))
+support-files =
+ damonbowling.jpg
+ damonbowling.jpg^headers^
+ file_favicon.html
+[browser_fetch_lnk.js]
+run-if = os == "win"
+support-files =
+ file_lnk.lnk
diff --git a/netwerk/test/browser/browser_NetUtil.js b/netwerk/test/browser/browser_NetUtil.js
new file mode 100644
index 0000000000..f8578fa4f8
--- /dev/null
+++ b/netwerk/test/browser/browser_NetUtil.js
@@ -0,0 +1,112 @@
+/*
+Any copyright is dedicated to the Public Domain.
+http://creativecommons.org/publicdomain/zero/1.0/
+*/
+"use strict";
+
+function test() {
+ waitForExplicitFinish();
+
+ // We overload this test to include verifying that httpd.js is
+ // importable as a testing-only JS module.
+ ChromeUtils.import("resource://testing-common/httpd.js", {});
+
+ nextTest();
+}
+
+function nextTest() {
+ if (tests.length) {
+ executeSoon(tests.shift());
+ } else {
+ executeSoon(finish);
+ }
+}
+
+var tests = [test_asyncFetchBadCert];
+
+function test_asyncFetchBadCert() {
+ // Try a load from an untrusted cert, with errors supressed
+ NetUtil.asyncFetch(
+ {
+ uri: "https://untrusted.example.com",
+ loadUsingSystemPrincipal: true,
+ },
+ function(aInputStream, aStatusCode, aRequest) {
+ ok(!Components.isSuccessCode(aStatusCode), "request failed");
+ ok(aRequest instanceof Ci.nsIHttpChannel, "request is an nsIHttpChannel");
+
+ // Now try again with a channel whose notificationCallbacks doesn't suprress errors
+ let channel = NetUtil.newChannel({
+ uri: "https://untrusted.example.com",
+ loadUsingSystemPrincipal: true,
+ });
+ channel.notificationCallbacks = {
+ QueryInterface: ChromeUtils.generateQI([
+ "nsIProgressEventSink",
+ "nsIInterfaceRequestor",
+ ]),
+ getInterface(aIID) {
+ return this.QueryInterface(aIID);
+ },
+ onProgress() {},
+ onStatus() {},
+ };
+ NetUtil.asyncFetch(channel, function(
+ aInputStream,
+ aStatusCode,
+ aRequest
+ ) {
+ ok(!Components.isSuccessCode(aStatusCode), "request failed");
+ ok(
+ aRequest instanceof Ci.nsIHttpChannel,
+ "request is an nsIHttpChannel"
+ );
+
+ // Now try a valid request
+ NetUtil.asyncFetch(
+ {
+ uri: "https://example.com",
+ loadUsingSystemPrincipal: true,
+ },
+ function(aInputStream, aStatusCode, aRequest) {
+ info("aStatusCode for valid request: " + aStatusCode);
+ ok(Components.isSuccessCode(aStatusCode), "request succeeded");
+ ok(
+ aRequest instanceof Ci.nsIHttpChannel,
+ "request is an nsIHttpChannel"
+ );
+ ok(aRequest.requestSucceeded, "HTTP request succeeded");
+
+ nextTest();
+ }
+ );
+ });
+ }
+ );
+}
+
+function WindowListener(aURL, aCallback) {
+ this.callback = aCallback;
+ this.url = aURL;
+}
+WindowListener.prototype = {
+ onOpenWindow(aXULWindow) {
+ var domwindow = aXULWindow.docShell.domWindow;
+ var self = this;
+ domwindow.addEventListener(
+ "load",
+ function() {
+ if (domwindow.document.location.href != self.url) {
+ return;
+ }
+
+ // Allow other window load listeners to execute before passing to callback
+ executeSoon(function() {
+ self.callback(domwindow);
+ });
+ },
+ { once: true }
+ );
+ },
+ onCloseWindow(aXULWindow) {},
+};
diff --git a/netwerk/test/browser/browser_about_cache.js b/netwerk/test/browser/browser_about_cache.js
new file mode 100644
index 0000000000..dba4204129
--- /dev/null
+++ b/netwerk/test/browser/browser_about_cache.js
@@ -0,0 +1,126 @@
+"use strict";
+
+/**
+ * Open a dummy page, then open about:cache and verify the opened page shows up in the cache.
+ */
+add_task(async function() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["privacy.partition.network_state", false]],
+ });
+
+ const kRoot = getRootDirectory(gTestPath).replace(
+ "chrome://mochitests/content/",
+ "https://example.com/"
+ );
+ const kTestPage = kRoot + "dummy.html";
+ // Open the dummy page to get it cached.
+ let tab = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ kTestPage,
+ true
+ );
+ BrowserTestUtils.removeTab(tab);
+
+ tab = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ "about:cache",
+ true
+ );
+ let expectedPageCheck = function(uri) {
+ info("Saw load for " + uri);
+ // Can't easily use searchParms and new URL() because it's an about: URI...
+ return uri.startsWith("about:cache?") && uri.includes("storage=disk");
+ };
+ let diskPageLoaded = BrowserTestUtils.browserLoaded(
+ tab.linkedBrowser,
+ false,
+ expectedPageCheck
+ );
+ await SpecialPowers.spawn(tab.linkedBrowser, [], function() {
+ ok(
+ !content.document.nodePrincipal.isSystemPrincipal,
+ "about:cache should not have system principal"
+ );
+ let principal = content.document.nodePrincipal;
+ let channel = content.docShell.currentDocumentChannel;
+ ok(!channel.loadInfo.loadingPrincipal, "Loading principal should be null.");
+ is(
+ principal.spec,
+ content.document.location.href,
+ "Principal matches location"
+ );
+ let links = [...content.document.querySelectorAll("a[href*=disk]")];
+ is(links.length, 1, "Should have 1 link to the disk entries");
+ links[0].click();
+ });
+ await diskPageLoaded;
+ info("about:cache disk subpage loaded");
+
+ expectedPageCheck = function(uri) {
+ info("Saw load for " + uri);
+ return uri.startsWith("about:cache-entry") && uri.includes("dummy.html");
+ };
+ let triggeringURISpec = tab.linkedBrowser.currentURI.spec;
+ let entryLoaded = BrowserTestUtils.browserLoaded(
+ tab.linkedBrowser,
+ false,
+ expectedPageCheck
+ );
+ await SpecialPowers.spawn(tab.linkedBrowser, [kTestPage], function(
+ kTestPage
+ ) {
+ ok(
+ !content.document.nodePrincipal.isSystemPrincipal,
+ "about:cache with query params should still not have system principal"
+ );
+ let principal = content.document.nodePrincipal;
+ is(
+ principal.spec,
+ content.document.location.href,
+ "Principal matches location"
+ );
+ let channel = content.docShell.currentDocumentChannel;
+ principal = channel.loadInfo.triggeringPrincipal;
+ is(
+ principal.spec,
+ "about:cache",
+ "Triggering principal matches previous location"
+ );
+ ok(!channel.loadInfo.loadingPrincipal, "Loading principal should be null.");
+ let links = [
+ ...content.document.querySelectorAll("a[href*='" + kTestPage + "']"),
+ ];
+ is(links.length, 1, "Should have 1 link to the entry for " + kTestPage);
+ links[0].click();
+ });
+ await entryLoaded;
+ info("about:cache entry loaded");
+
+ await SpecialPowers.spawn(tab.linkedBrowser, [triggeringURISpec], function(
+ triggeringURISpec
+ ) {
+ ok(
+ !content.document.nodePrincipal.isSystemPrincipal,
+ "about:cache-entry should also not have system principal"
+ );
+ let principal = content.document.nodePrincipal;
+ is(
+ principal.spec,
+ content.document.location.href,
+ "Principal matches location"
+ );
+ let channel = content.docShell.currentDocumentChannel;
+ principal = channel.loadInfo.triggeringPrincipal;
+ is(
+ principal.spec,
+ triggeringURISpec,
+ "Triggering principal matches previous location"
+ );
+ ok(!channel.loadInfo.loadingPrincipal, "Loading principal should be null.");
+ ok(
+ content.document.querySelectorAll("th").length,
+ "Should have several table headers with data."
+ );
+ });
+ BrowserTestUtils.removeTab(tab);
+});
diff --git a/netwerk/test/browser/browser_bug1535877.js b/netwerk/test/browser/browser_bug1535877.js
new file mode 100644
index 0000000000..0bd0a98d11
--- /dev/null
+++ b/netwerk/test/browser/browser_bug1535877.js
@@ -0,0 +1,15 @@
+"use strict";
+
+add_task(_ => {
+ try {
+ Cc["@mozilla.org/network/effective-tld-service;1"].createInstance(
+ Ci.nsISupports
+ );
+ } catch (e) {
+ is(
+ e.result,
+ Cr.NS_ERROR_XPC_CI_RETURNED_FAILURE,
+ "Component creation as an instance fails with expected code"
+ );
+ }
+});
diff --git a/netwerk/test/browser/browser_child_resource.js b/netwerk/test/browser/browser_child_resource.js
new file mode 100644
index 0000000000..7535120f44
--- /dev/null
+++ b/netwerk/test/browser/browser_child_resource.js
@@ -0,0 +1,247 @@
+/*
+Any copyright is dedicated to the Public Domain.
+http://creativecommons.org/publicdomain/zero/1.0/
+*/
+"use strict";
+
+// This must be loaded in the remote process for this test to be useful
+const TEST_URL = "http://example.com/browser/netwerk/test/browser/dummy.html";
+
+const expectedRemote = gMultiProcessBrowser ? "true" : "";
+
+const resProtocol = Cc[
+ "@mozilla.org/network/protocol;1?name=resource"
+].getService(Ci.nsIResProtocolHandler);
+
+function waitForEvent(obj, name, capturing, chromeEvent) {
+ info("Waiting for " + name);
+ return new Promise(resolve => {
+ function listener(event) {
+ info("Saw " + name);
+ obj.removeEventListener(name, listener, capturing, chromeEvent);
+ resolve(event);
+ }
+
+ obj.addEventListener(name, listener, capturing, chromeEvent);
+ });
+}
+
+function resolveURI(uri) {
+ uri = Services.io.newURI(uri);
+ try {
+ return resProtocol.resolveURI(uri);
+ } catch (e) {
+ return null;
+ }
+}
+
+function remoteResolveURI(uri) {
+ return SpecialPowers.spawn(gBrowser.selectedBrowser, [uri], uriToResolve => {
+ const { Services } = ChromeUtils.import(
+ "resource://gre/modules/Services.jsm"
+ );
+ let resProtocol = Cc[
+ "@mozilla.org/network/protocol;1?name=resource"
+ ].getService(Ci.nsIResProtocolHandler);
+
+ uriToResolve = Services.io.newURI(uriToResolve);
+ try {
+ return resProtocol.resolveURI(uriToResolve);
+ } catch (e) {}
+ return null;
+ });
+}
+
+// Restarts the child process by crashing it then reloading the tab
+var restart = async function() {
+ let browser = gBrowser.selectedBrowser;
+ // If the tab isn't remote this would crash the main process so skip it
+ if (browser.getAttribute("remote") != "true") {
+ return browser;
+ }
+
+ await BrowserTestUtils.crashFrame(browser);
+
+ browser.reload();
+
+ await BrowserTestUtils.browserLoaded(browser);
+ is(
+ browser.getAttribute("remote"),
+ expectedRemote,
+ "Browser should be in the right process"
+ );
+ return browser;
+};
+
+// Sanity check that this test is going to be useful
+add_task(async function() {
+ await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
+
+ // This must be loaded in the remote process for this test to be useful
+ is(
+ gBrowser.selectedBrowser.getAttribute("remote"),
+ expectedRemote,
+ "Browser should be in the right process"
+ );
+
+ let local = resolveURI("resource://gre/modules/Services.jsm");
+ let remote = await remoteResolveURI("resource://gre/modules/Services.jsm");
+ is(local, remote, "Services.jsm should resolve in both processes");
+
+ gBrowser.removeCurrentTab();
+});
+
+// Add a mapping, update it then remove it
+add_task(async function() {
+ await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
+
+ info("Set");
+ resProtocol.setSubstitution(
+ "testing",
+ Services.io.newURI("chrome://global/content")
+ );
+ let local = resolveURI("resource://testing/test.js");
+ let remote = await remoteResolveURI("resource://testing/test.js");
+ is(
+ local,
+ "chrome://global/content/test.js",
+ "Should resolve in main process"
+ );
+ is(
+ remote,
+ "chrome://global/content/test.js",
+ "Should resolve in child process"
+ );
+
+ info("Change");
+ resProtocol.setSubstitution(
+ "testing",
+ Services.io.newURI("chrome://global/skin")
+ );
+ local = resolveURI("resource://testing/test.js");
+ remote = await remoteResolveURI("resource://testing/test.js");
+ is(local, "chrome://global/skin/test.js", "Should resolve in main process");
+ is(remote, "chrome://global/skin/test.js", "Should resolve in child process");
+
+ info("Clear");
+ resProtocol.setSubstitution("testing", null);
+ local = resolveURI("resource://testing/test.js");
+ remote = await remoteResolveURI("resource://testing/test.js");
+ is(local, null, "Shouldn't resolve in main process");
+ is(remote, null, "Shouldn't resolve in child process");
+
+ gBrowser.removeCurrentTab();
+});
+
+// Add a mapping, restart the child process then check it is still there
+add_task(async function() {
+ await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
+
+ info("Set");
+ resProtocol.setSubstitution(
+ "testing",
+ Services.io.newURI("chrome://global/content")
+ );
+ let local = resolveURI("resource://testing/test.js");
+ let remote = await remoteResolveURI("resource://testing/test.js");
+ is(
+ local,
+ "chrome://global/content/test.js",
+ "Should resolve in main process"
+ );
+ is(
+ remote,
+ "chrome://global/content/test.js",
+ "Should resolve in child process"
+ );
+
+ await restart();
+
+ local = resolveURI("resource://testing/test.js");
+ remote = await remoteResolveURI("resource://testing/test.js");
+ is(
+ local,
+ "chrome://global/content/test.js",
+ "Should resolve in main process"
+ );
+ is(
+ remote,
+ "chrome://global/content/test.js",
+ "Should resolve in child process"
+ );
+
+ info("Change");
+ resProtocol.setSubstitution(
+ "testing",
+ Services.io.newURI("chrome://global/skin")
+ );
+
+ await restart();
+
+ local = resolveURI("resource://testing/test.js");
+ remote = await remoteResolveURI("resource://testing/test.js");
+ is(local, "chrome://global/skin/test.js", "Should resolve in main process");
+ is(remote, "chrome://global/skin/test.js", "Should resolve in child process");
+
+ info("Clear");
+ resProtocol.setSubstitution("testing", null);
+
+ await restart();
+
+ local = resolveURI("resource://testing/test.js");
+ remote = await remoteResolveURI("resource://testing/test.js");
+ is(local, null, "Shouldn't resolve in main process");
+ is(remote, null, "Shouldn't resolve in child process");
+
+ gBrowser.removeCurrentTab();
+});
+
+// Adding a mapping to a resource URI should work
+add_task(async function() {
+ await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
+
+ info("Set");
+ resProtocol.setSubstitution(
+ "testing",
+ Services.io.newURI("chrome://global/content")
+ );
+ resProtocol.setSubstitution(
+ "testing2",
+ Services.io.newURI("resource://testing")
+ );
+ let local = resolveURI("resource://testing2/test.js");
+ let remote = await remoteResolveURI("resource://testing2/test.js");
+ is(
+ local,
+ "chrome://global/content/test.js",
+ "Should resolve in main process"
+ );
+ is(
+ remote,
+ "chrome://global/content/test.js",
+ "Should resolve in child process"
+ );
+
+ info("Clear");
+ resProtocol.setSubstitution("testing", null);
+ local = resolveURI("resource://testing2/test.js");
+ remote = await remoteResolveURI("resource://testing2/test.js");
+ is(
+ local,
+ "chrome://global/content/test.js",
+ "Should resolve in main process"
+ );
+ is(
+ remote,
+ "chrome://global/content/test.js",
+ "Should resolve in child process"
+ );
+
+ resProtocol.setSubstitution("testing2", null);
+ local = resolveURI("resource://testing2/test.js");
+ remote = await remoteResolveURI("resource://testing2/test.js");
+ is(local, null, "Shouldn't resolve in main process");
+ is(remote, null, "Shouldn't resolve in child process");
+
+ gBrowser.removeCurrentTab();
+});
diff --git a/netwerk/test/browser/browser_cookie_sync_across_tabs.js b/netwerk/test/browser/browser_cookie_sync_across_tabs.js
new file mode 100644
index 0000000000..872e3cc4f5
--- /dev/null
+++ b/netwerk/test/browser/browser_cookie_sync_across_tabs.js
@@ -0,0 +1,79 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+"use strict";
+
+add_task(async function() {
+ info("Make sure cookie changes in one process are visible in the other");
+
+ const kRoot = getRootDirectory(gTestPath).replace(
+ "chrome://mochitests/content/",
+ "https://example.com/"
+ );
+ const kTestPage = kRoot + "dummy.html";
+
+ Services.cookies.removeAll();
+
+ let tab1 = await BrowserTestUtils.openNewForegroundTab({
+ gBrowser,
+ url: kTestPage,
+ forceNewProcess: true,
+ });
+ let tab2 = await BrowserTestUtils.openNewForegroundTab({
+ gBrowser,
+ url: kTestPage,
+ forceNewProcess: true,
+ });
+
+ let browser1 = gBrowser.getBrowserForTab(tab1);
+ let browser2 = gBrowser.getBrowserForTab(tab2);
+
+ let pid1 = browser1.frameLoader.remoteTab.osPid;
+ let pid2 = browser2.frameLoader.remoteTab.osPid;
+
+ // Note, this might not be true once fission is implemented (Bug 1451850)
+ ok(pid1 != pid2, "We should have different processes here.");
+
+ await SpecialPowers.spawn(browser1, [], async function() {
+ is(content.document.cookie, "", "Expecting no cookies");
+ });
+
+ await SpecialPowers.spawn(browser2, [], async function() {
+ is(content.document.cookie, "", "Expecting no cookies");
+ });
+
+ await SpecialPowers.spawn(browser1, [], async function() {
+ content.document.cookie = "a1=test";
+ });
+
+ await SpecialPowers.spawn(browser2, [], async function() {
+ is(content.document.cookie, "a1=test", "Cookie should be set");
+ content.document.cookie = "a1=other_test";
+ });
+
+ await SpecialPowers.spawn(browser1, [], async function() {
+ is(content.document.cookie, "a1=other_test", "Cookie should be set");
+ content.document.cookie = "a2=again";
+ });
+
+ await SpecialPowers.spawn(browser2, [], async function() {
+ is(
+ content.document.cookie,
+ "a1=other_test; a2=again",
+ "Cookie should be set"
+ );
+ content.document.cookie = "a1=; expires=Thu, 01-Jan-1970 00:00:01 GMT;";
+ content.document.cookie = "a2=; expires=Thu, 01-Jan-1970 00:00:01 GMT;";
+ });
+
+ await SpecialPowers.spawn(browser1, [], async function() {
+ is(content.document.cookie, "", "Cookies should be cleared");
+ });
+
+ BrowserTestUtils.removeTab(tab1);
+ BrowserTestUtils.removeTab(tab2);
+
+ ok(true, "Got to the end of the test!");
+});
diff --git a/netwerk/test/browser/browser_fetch_lnk.js b/netwerk/test/browser/browser_fetch_lnk.js
new file mode 100644
index 0000000000..cbfc6a4c4b
--- /dev/null
+++ b/netwerk/test/browser/browser_fetch_lnk.js
@@ -0,0 +1,27 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+add_task(async () => {
+ await SpecialPowers.pushPrefEnv({
+ set: [["privacy.file_unique_origin", false]],
+ });
+
+ const FILE_PAGE = Services.io.newFileURI(
+ new FileUtils.File(getTestFilePath("dummy.html"))
+ ).spec;
+ await BrowserTestUtils.withNewTab(FILE_PAGE, async browser => {
+ try {
+ await SpecialPowers.spawn(browser, [], () =>
+ content.fetch("./file_lnk.lnk")
+ );
+ ok(
+ false,
+ "Loading lnk must fail if it links to a file from other directory"
+ );
+ } catch (err) {
+ is(err.constructor.name, "TypeError", "Should fail on Windows");
+ }
+ });
+});
diff --git a/netwerk/test/browser/browser_nsIFormPOSTActionChannel.js b/netwerk/test/browser/browser_nsIFormPOSTActionChannel.js
new file mode 100644
index 0000000000..07387f8c09
--- /dev/null
+++ b/netwerk/test/browser/browser_nsIFormPOSTActionChannel.js
@@ -0,0 +1,292 @@
+/*
+ * Tests for bug 1241377: A channel with nsIFormPOSTActionChannel interface
+ * should be able to accept form POST.
+ */
+
+/* eslint-env mozilla/frame-script */
+
+"use strict";
+
+const SCHEME = "x-bug1241377";
+
+const FORM_BASE = SCHEME + "://dummy/form/";
+const NORMAL_FORM_URI = FORM_BASE + "normal.html";
+const UPLOAD_FORM_URI = FORM_BASE + "upload.html";
+const POST_FORM_URI = FORM_BASE + "post.html";
+
+const ACTION_BASE = SCHEME + "://dummy/action/";
+const NORMAL_ACTION_URI = ACTION_BASE + "normal.html";
+const UPLOAD_ACTION_URI = ACTION_BASE + "upload.html";
+const POST_ACTION_URI = ACTION_BASE + "post.html";
+
+function CustomProtocolHandler() {}
+CustomProtocolHandler.prototype = {
+ /** nsIProtocolHandler */
+ get scheme() {
+ return SCHEME;
+ },
+ get defaultPort() {
+ return -1;
+ },
+ get protocolFlags() {
+ return (
+ Ci.nsIProtocolHandler.URI_NORELATIVE |
+ Ci.nsIProtocolHandler.URI_IS_LOCAL_RESOURCE
+ );
+ },
+ newChannel(aURI, aLoadInfo) {
+ return new CustomChannel(aURI, aLoadInfo);
+ },
+ allowPort(port, scheme) {
+ return port != -1;
+ },
+
+ /** nsIFactory */
+ createInstance(aOuter, aIID) {
+ if (aOuter) {
+ throw Components.Exception("", Cr.NS_ERROR_NO_AGGREGATION);
+ }
+ return this.QueryInterface(aIID);
+ },
+ lockFactory() {},
+
+ /** nsISupports */
+ QueryInterface: ChromeUtils.generateQI(["nsIProtocolHandler", "nsIFactory"]),
+ classID: Components.ID("{16d594bc-d9d8-47ae-a139-ea714dc0c35c}"),
+};
+
+function CustomChannel(aURI, aLoadInfo) {
+ this.uri = aURI;
+ this.loadInfo = aLoadInfo;
+
+ this._uploadStream = null;
+
+ var interfaces = [Ci.nsIRequest, Ci.nsIChannel];
+ if (this.uri.spec == POST_ACTION_URI) {
+ interfaces.push(Ci.nsIFormPOSTActionChannel);
+ } else if (this.uri.spec == UPLOAD_ACTION_URI) {
+ interfaces.push(Ci.nsIUploadChannel);
+ }
+ this.QueryInterface = ChromeUtils.generateQI(interfaces);
+}
+CustomChannel.prototype = {
+ /** nsIUploadChannel */
+ get uploadStream() {
+ return this._uploadStream;
+ },
+ set uploadStream(val) {
+ throw Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED);
+ },
+ setUploadStream(aStream, aContentType, aContentLength) {
+ this._uploadStream = aStream;
+ },
+
+ /** nsIChannel */
+ get originalURI() {
+ return this.uri;
+ },
+ get URI() {
+ return this.uri;
+ },
+ owner: null,
+ notificationCallbacks: null,
+ get securityInfo() {
+ return null;
+ },
+ get contentType() {
+ return "text/html";
+ },
+ set contentType(val) {},
+ contentCharset: "UTF-8",
+ get contentLength() {
+ return -1;
+ },
+ set contentLength(val) {
+ throw Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED);
+ },
+ open() {
+ throw Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED);
+ },
+ asyncOpen(aListener) {
+ var data = `
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>test bug 1241377</title>
+</head>
+<body>
+`;
+
+ if (this.uri.spec.startsWith(FORM_BASE)) {
+ data += `
+<form id="form" action="${this.uri.spec.replace(FORM_BASE, ACTION_BASE)}"
+ method="post" enctype="text/plain" target="frame">
+<input type="hidden" name="foo" value="bar">
+<input type="submit">
+</form>
+
+<iframe id="frame" name="frame" width="200" height="200"></iframe>
+
+<script type="text/javascript">
+<!--
+document.getElementById('form').submit();
+//-->
+</script>
+`;
+ } else if (this.uri.spec.startsWith(ACTION_BASE)) {
+ var postData = "";
+ var headers = {};
+ if (this._uploadStream) {
+ var bstream = Cc["@mozilla.org/binaryinputstream;1"].createInstance(
+ Ci.nsIBinaryInputStream
+ );
+ bstream.setInputStream(this._uploadStream);
+ postData = bstream.readBytes(bstream.available());
+
+ if (this._uploadStream instanceof Ci.nsIMIMEInputStream) {
+ this._uploadStream.visitHeaders((name, value) => {
+ headers[name] = value;
+ });
+ }
+ }
+ data += `
+<input id="upload_stream" value="${this._uploadStream ? "yes" : "no"}">
+<input id="post_data" value="${btoa(postData)}">
+<input id="upload_headers" value='${JSON.stringify(headers)}'>
+`;
+ }
+
+ data += `
+</body>
+</html>
+`;
+
+ var stream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(
+ Ci.nsIStringInputStream
+ );
+ stream.setData(data, data.length);
+
+ var runnable = {
+ run: () => {
+ try {
+ aListener.onStartRequest(this, null);
+ } catch (e) {}
+ try {
+ aListener.onDataAvailable(this, stream, 0, stream.available());
+ } catch (e) {}
+ try {
+ aListener.onStopRequest(this, null, Cr.NS_OK);
+ } catch (e) {}
+ },
+ };
+ Services.tm.dispatchToMainThread(runnable);
+ },
+
+ /** nsIRequest */
+ get name() {
+ return this.uri.spec;
+ },
+ isPending() {
+ return false;
+ },
+ get status() {
+ return Cr.NS_OK;
+ },
+ cancel(status) {},
+ loadGroup: null,
+ loadFlags:
+ Ci.nsIRequest.LOAD_NORMAL |
+ Ci.nsIRequest.INHIBIT_CACHING |
+ Ci.nsIRequest.LOAD_BYPASS_CACHE,
+};
+
+function frameScript() {
+ addMessageListener("Test:WaitForIFrame", function() {
+ var check = function() {
+ if (content) {
+ var frame = content.document.getElementById("frame");
+ if (frame) {
+ var upload_stream = frame.contentDocument.getElementById(
+ "upload_stream"
+ );
+ var post_data = frame.contentDocument.getElementById("post_data");
+ var headers = frame.contentDocument.getElementById("upload_headers");
+ if (upload_stream && post_data && headers) {
+ sendAsyncMessage("Test:IFrameLoaded", [
+ upload_stream.value,
+ post_data.value,
+ headers.value,
+ ]);
+ return;
+ }
+ }
+ }
+
+ setTimeout(check, 100);
+ };
+
+ check();
+ });
+}
+
+function loadTestTab(uri) {
+ gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, uri);
+ var browser = gBrowser.selectedBrowser;
+
+ let manager = browser.messageManager;
+ browser.messageManager.loadFrameScript(
+ "data:,(" + frameScript.toString() + ")();",
+ true
+ );
+
+ return new Promise(resolve => {
+ function listener({ data: [hasUploadStream, postData, headers] }) {
+ manager.removeMessageListener("Test:IFrameLoaded", listener);
+ resolve([hasUploadStream, atob(postData), JSON.parse(headers)]);
+ }
+
+ manager.addMessageListener("Test:IFrameLoaded", listener);
+ manager.sendAsyncMessage("Test:WaitForIFrame");
+ });
+}
+
+add_task(async function() {
+ var handler = new CustomProtocolHandler();
+ var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
+ registrar.registerFactory(
+ handler.classID,
+ "",
+ "@mozilla.org/network/protocol;1?name=" + handler.scheme,
+ handler
+ );
+ registerCleanupFunction(function() {
+ registrar.unregisterFactory(handler.classID, handler);
+ });
+});
+
+add_task(async function() {
+ var [hasUploadStream] = await loadTestTab(NORMAL_FORM_URI);
+ is(hasUploadStream, "no", "normal action should not have uploadStream");
+
+ gBrowser.removeCurrentTab();
+});
+
+add_task(async function() {
+ var [hasUploadStream] = await loadTestTab(UPLOAD_FORM_URI);
+ is(hasUploadStream, "no", "upload action should not have uploadStream");
+
+ gBrowser.removeCurrentTab();
+});
+
+add_task(async function() {
+ var [hasUploadStream, postData, headers] = await loadTestTab(POST_FORM_URI);
+
+ is(hasUploadStream, "yes", "post action should have uploadStream");
+ is(postData, "foo=bar\r\n", "POST data is received correctly");
+
+ is(headers["Content-Type"], "text/plain", "Content-Type header is correct");
+ is(headers["Content-Length"], undefined, "Content-Length header is correct");
+
+ gBrowser.removeCurrentTab();
+});
diff --git a/netwerk/test/browser/browser_post_file.js b/netwerk/test/browser/browser_post_file.js
new file mode 100644
index 0000000000..f8dc859cc0
--- /dev/null
+++ b/netwerk/test/browser/browser_post_file.js
@@ -0,0 +1,78 @@
+/*
+ * Tests for bug 1241100: Post to local file should not overwrite the file.
+ */
+"use strict";
+const { OS } = ChromeUtils.import("resource://gre/modules/osfile.jsm");
+
+async function createTestFile(filename, content) {
+ let path = OS.Path.join(OS.Constants.Path.tmpDir, filename);
+ await OS.File.writeAtomic(path, content);
+ return path;
+}
+
+async function readFile(path) {
+ var array = await OS.File.read(path);
+ var decoder = new TextDecoder();
+ return decoder.decode(array);
+}
+
+add_task(async function() {
+ var postFilename = "post_file.html";
+ var actionFilename = "action_file.html";
+
+ var postFileContent = `
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>post file</title>
+</head>
+<body onload="document.getElementById('form').submit();">
+<form id="form" action="${actionFilename}" method="post" enctype="text/plain" target="frame">
+<input type="hidden" name="foo" value="bar">
+<input type="submit">
+</form>
+<iframe id="frame" name="frame"></iframe>
+</body>
+</html>
+`;
+
+ var actionFileContent = `
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>action file</title>
+</head>
+<body>
+<div id="action_file_ok">ok</div>
+</body>
+</html>
+`;
+
+ var postPath = await createTestFile(postFilename, postFileContent);
+ var actionPath = await createTestFile(actionFilename, actionFileContent);
+
+ var postURI = OS.Path.toFileURI(postPath);
+ var actionURI = OS.Path.toFileURI(actionPath);
+
+ let tab = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ "about:blank"
+ );
+ let browserLoadedPromise = BrowserTestUtils.browserLoaded(
+ tab.linkedBrowser,
+ true,
+ actionURI
+ );
+ BrowserTestUtils.loadURI(tab.linkedBrowser, postURI);
+ await browserLoadedPromise;
+
+ var actionFileContentAfter = await readFile(actionPath);
+ is(actionFileContentAfter, actionFileContent, "action file is not modified");
+
+ await OS.File.remove(postPath);
+ await OS.File.remove(actionPath);
+
+ gBrowser.removeCurrentTab();
+});
diff --git a/netwerk/test/browser/browser_resource_navigation.js b/netwerk/test/browser/browser_resource_navigation.js
new file mode 100644
index 0000000000..abcac2b554
--- /dev/null
+++ b/netwerk/test/browser/browser_resource_navigation.js
@@ -0,0 +1,76 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+"use strict";
+
+add_task(async function() {
+ info("Make sure navigation through links in resource:// pages work");
+
+ await BrowserTestUtils.withNewTab(
+ { gBrowser, url: "resource://gre/" },
+ async function(browser) {
+ // Following a directory link shall properly open the directory (bug 1224046)
+ await SpecialPowers.spawn(browser, [], function() {
+ let link = Array.prototype.filter.call(
+ content.document.getElementsByClassName("dir"),
+ function(element) {
+ let name = element.textContent;
+ // Depending whether resource:// is backed by jar: or file://,
+ // directories either have a trailing slash or they don't.
+ if (name.endsWith("/")) {
+ name = name.slice(0, -1);
+ }
+ return name == "components";
+ }
+ )[0];
+ // First ensure the link is in the viewport
+ link.scrollIntoView();
+ // Then click on it.
+ link.click();
+ });
+
+ await BrowserTestUtils.browserLoaded(
+ browser,
+ undefined,
+ "resource://gre/components/"
+ );
+
+ // Following the parent link shall properly open the parent (bug 1366180)
+ await SpecialPowers.spawn(browser, [], function() {
+ let link = content.document
+ .getElementById("UI_goUp")
+ .getElementsByTagName("a")[0];
+ // The link should always be high enough in the page to be in the viewport.
+ link.click();
+ });
+
+ await BrowserTestUtils.browserLoaded(
+ browser,
+ undefined,
+ "resource://gre/"
+ );
+
+ // Following a link to a given file shall properly open the file.
+ await SpecialPowers.spawn(browser, [], function() {
+ let link = Array.prototype.filter.call(
+ content.document.getElementsByClassName("file"),
+ function(element) {
+ return element.textContent == "greprefs.js";
+ }
+ )[0];
+ link.scrollIntoView();
+ link.click();
+ });
+
+ await BrowserTestUtils.browserLoaded(
+ browser,
+ undefined,
+ "resource://gre/greprefs.js"
+ );
+
+ ok(true, "Got to the end of the test!");
+ }
+ );
+});
diff --git a/netwerk/test/browser/browser_test_favicon.js b/netwerk/test/browser/browser_test_favicon.js
new file mode 100644
index 0000000000..2817385d20
--- /dev/null
+++ b/netwerk/test/browser/browser_test_favicon.js
@@ -0,0 +1,26 @@
+// Tests third party cookie blocking using a favicon loaded from a different
+// domain. The cookie should be considered third party.
+"use strict";
+add_task(async function() {
+ const iconUrl =
+ "http://example.org/browser/netwerk/test/browser/damonbowling.jpg";
+ const pageUrl =
+ "http://example.com/browser/netwerk/test/browser/file_favicon.html";
+ await SpecialPowers.pushPrefEnv({
+ set: [["network.cookie.cookieBehavior", 1]],
+ });
+
+ let promise = TestUtils.topicObserved("cookie-rejected", subject => {
+ let uri = subject.QueryInterface(Ci.nsIURI);
+ return uri.spec == iconUrl;
+ });
+
+ // Kick off a page load that will load the favicon.
+ let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, pageUrl);
+ registerCleanupFunction(async function() {
+ BrowserTestUtils.removeTab(tab);
+ });
+
+ await promise;
+ ok(true, "foreign favicon cookie was blocked");
+});
diff --git a/netwerk/test/browser/browser_test_io_activity.js b/netwerk/test/browser/browser_test_io_activity.js
new file mode 100644
index 0000000000..f847701888
--- /dev/null
+++ b/netwerk/test/browser/browser_test_io_activity.js
@@ -0,0 +1,50 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+const ROOT_URL = getRootDirectory(gTestPath).replace(
+ "chrome://mochitests/content/",
+ "https://example.com/"
+);
+const TEST_URL = "about:license";
+const TEST_URL2 = ROOT_URL + "ioactivity.html";
+
+var gotSocket = false;
+var gotFile = false;
+var gotSqlite = false;
+var gotEmptyData = false;
+
+function processResults(results) {
+ for (let data of results) {
+ console.log(data.location);
+ gotEmptyData = data.rx == 0 && data.tx == 0 && !gotEmptyData;
+ gotSocket = data.location.startsWith("socket://127.0.0.1:") || gotSocket;
+ gotFile = data.location.endsWith("aboutLicense.css") || gotFile;
+ gotSqlite = data.location.endsWith("places.sqlite") || gotSqlite;
+ // check for the write-ahead file as well
+ gotSqlite = data.location.endsWith("places.sqlite-wal") || gotSqlite;
+ }
+}
+
+add_task(async function testRequestIOActivity() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["io.activity.enabled", true]],
+ });
+ waitForExplicitFinish();
+ Services.obs.notifyObservers(null, "profile-initial-state");
+
+ await BrowserTestUtils.withNewTab(TEST_URL, async function(browser) {
+ await BrowserTestUtils.withNewTab(TEST_URL2, async function(browser) {
+ let results = await ChromeUtils.requestIOActivity();
+ processResults(results);
+
+ ok(gotSocket, "A socket was used");
+ // test deactivated for now
+ // ok(gotFile, "A file was used");
+ ok(gotSqlite, "A sqlite DB was used");
+ ok(!gotEmptyData, "Every I/O event had data");
+ });
+ });
+});
diff --git a/netwerk/test/browser/damonbowling.jpg b/netwerk/test/browser/damonbowling.jpg
new file mode 100644
index 0000000000..8bdb2b6042
--- /dev/null
+++ b/netwerk/test/browser/damonbowling.jpg
Binary files differ
diff --git a/netwerk/test/browser/damonbowling.jpg^headers^ b/netwerk/test/browser/damonbowling.jpg^headers^
new file mode 100644
index 0000000000..77f4f49089
--- /dev/null
+++ b/netwerk/test/browser/damonbowling.jpg^headers^
@@ -0,0 +1,2 @@
+Cache-Control: no-store
+Set-Cookie: damon=bowling
diff --git a/netwerk/test/browser/dummy.html b/netwerk/test/browser/dummy.html
new file mode 100644
index 0000000000..8025fcdb20
--- /dev/null
+++ b/netwerk/test/browser/dummy.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+
+<head>
+<meta http-equiv="content-type" content="text/html; charset=utf-8">
+</head>
+
+<html>
+<body>
+ <p>Dummy Page</p>
+</body>
+</html>
diff --git a/netwerk/test/browser/file_favicon.html b/netwerk/test/browser/file_favicon.html
new file mode 100644
index 0000000000..77532a3a53
--- /dev/null
+++ b/netwerk/test/browser/file_favicon.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+
+<html>
+ <head>
+ <link rel="shortcut icon" href="http://example.org/browser/netwerk/test/browser/damonbowling.jpg">
+ </head>
+</html>
diff --git a/netwerk/test/browser/file_lnk.lnk b/netwerk/test/browser/file_lnk.lnk
new file mode 100644
index 0000000000..abce7587d2
--- /dev/null
+++ b/netwerk/test/browser/file_lnk.lnk
Binary files differ
diff --git a/netwerk/test/browser/ioactivity.html b/netwerk/test/browser/ioactivity.html
new file mode 100644
index 0000000000..5e23f6f117
--- /dev/null
+++ b/netwerk/test/browser/ioactivity.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+
+<head>
+<meta http-equiv="content-type" content="text/html; charset=utf-8">
+</head>
+
+<html>
+<body>
+ <p>IOActivity Test Page</p>
+</body>
+</html>
diff --git a/netwerk/test/browser/redirect.sjs b/netwerk/test/browser/redirect.sjs
new file mode 100644
index 0000000000..7599fe33fb
--- /dev/null
+++ b/netwerk/test/browser/redirect.sjs
@@ -0,0 +1,7 @@
+function handleRequest(request, response)
+{
+ response.setStatusLine(request.httpVersion, 301, "Moved Permanently");
+ let location = request.queryString;
+ response.setHeader("Location", location, false);
+ response.write("Hello world!");
+}