diff options
Diffstat (limited to 'toolkit/components/remotebrowserutils')
7 files changed, 329 insertions, 0 deletions
diff --git a/toolkit/components/remotebrowserutils/RemoteWebNavigation.js b/toolkit/components/remotebrowserutils/RemoteWebNavigation.js new file mode 100644 index 000000000..5790c0004 --- /dev/null +++ b/toolkit/components/remotebrowserutils/RemoteWebNavigation.js @@ -0,0 +1,139 @@ +// -*- indent-tabs-mode: nil; js-indent-level: 2 -*- +// 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/. + +const { interfaces: Ci, classes: Cc, utils: Cu, results: Cr } = Components; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); + +XPCOMUtils.defineLazyModuleGetter(this, "Services", + "resource://gre/modules/Services.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", + "resource://gre/modules/NetUtil.jsm"); + +function makeURI(url) +{ + return Services.io.newURI(url, null, null); +} + +function readInputStreamToString(aStream) +{ + return NetUtil.readInputStreamToString(aStream, aStream.available()); +} + +function RemoteWebNavigation() +{ + this.wrappedJSObject = this; +} + +RemoteWebNavigation.prototype = { + classDescription: "nsIWebNavigation for remote browsers", + classID: Components.ID("{4b56964e-cdf3-4bb8-830c-0e2dad3f4ebd}"), + contractID: "@mozilla.org/remote-web-navigation;1", + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebNavigation, Ci.nsISupports]), + + swapBrowser: function(aBrowser) { + this._browser = aBrowser; + }, + + LOAD_FLAGS_MASK: 65535, + LOAD_FLAGS_NONE: 0, + LOAD_FLAGS_IS_REFRESH: 16, + LOAD_FLAGS_IS_LINK: 32, + LOAD_FLAGS_BYPASS_HISTORY: 64, + LOAD_FLAGS_REPLACE_HISTORY: 128, + LOAD_FLAGS_BYPASS_CACHE: 256, + LOAD_FLAGS_BYPASS_PROXY: 512, + LOAD_FLAGS_CHARSET_CHANGE: 1024, + LOAD_FLAGS_STOP_CONTENT: 2048, + LOAD_FLAGS_FROM_EXTERNAL: 4096, + LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP: 8192, + LOAD_FLAGS_FIRST_LOAD: 16384, + LOAD_FLAGS_ALLOW_POPUPS: 32768, + LOAD_FLAGS_BYPASS_CLASSIFIER: 65536, + LOAD_FLAGS_FORCE_ALLOW_COOKIES: 131072, + + STOP_NETWORK: 1, + STOP_CONTENT: 2, + STOP_ALL: 3, + + canGoBack: false, + canGoForward: false, + goBack: function() { + this._sendMessage("WebNavigation:GoBack", {}); + }, + goForward: function() { + this._sendMessage("WebNavigation:GoForward", {}); + }, + gotoIndex: function(aIndex) { + this._sendMessage("WebNavigation:GotoIndex", {index: aIndex}); + }, + loadURI: function(aURI, aLoadFlags, aReferrer, aPostData, aHeaders) { + this.loadURIWithOptions(aURI, aLoadFlags, aReferrer, + Ci.nsIHttpChannel.REFERRER_POLICY_DEFAULT, + aPostData, aHeaders, null); + }, + loadURIWithOptions: function(aURI, aLoadFlags, aReferrer, aReferrerPolicy, + aPostData, aHeaders, aBaseURI) { + this._sendMessage("WebNavigation:LoadURI", { + uri: aURI, + flags: aLoadFlags, + referrer: aReferrer ? aReferrer.spec : null, + referrerPolicy: aReferrerPolicy, + postData: aPostData ? readInputStreamToString(aPostData) : null, + headers: aHeaders ? readInputStreamToString(aHeaders) : null, + baseURI: aBaseURI ? aBaseURI.spec : null, + }); + }, + setOriginAttributesBeforeLoading: function(aOriginAttributes) { + this._sendMessage("WebNavigation:SetOriginAttributes", { + originAttributes: aOriginAttributes, + }); + }, + reload: function(aReloadFlags) { + this._sendMessage("WebNavigation:Reload", {flags: aReloadFlags}); + }, + stop: function(aStopFlags) { + this._sendMessage("WebNavigation:Stop", {flags: aStopFlags}); + }, + + get document() { + return this._browser.contentDocument; + }, + + _currentURI: null, + get currentURI() { + if (!this._currentURI) { + this._currentURI = makeURI("about:blank"); + } + + return this._currentURI; + }, + set currentURI(aURI) { + this.loadURI(aURI.spec, null, null, null); + }, + + referringURI: null, + + // Bug 1233803 - accessing the sessionHistory of remote browsers should be + // done in content scripts. + get sessionHistory() { + throw Cr.NS_ERROR_NOT_IMPLEMENTED; + }, + set sessionHistory(aValue) { + throw Cr.NS_ERROR_NOT_IMPLEMENTED; + }, + + _sendMessage: function(aMessage, aData) { + try { + this._browser.messageManager.sendAsyncMessage(aMessage, aData); + } + catch (e) { + Cu.reportError(e); + } + }, +}; + +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([RemoteWebNavigation]); diff --git a/toolkit/components/remotebrowserutils/moz.build b/toolkit/components/remotebrowserutils/moz.build new file mode 100644 index 000000000..9cfc4a976 --- /dev/null +++ b/toolkit/components/remotebrowserutils/moz.build @@ -0,0 +1,12 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +EXTRA_COMPONENTS += [ + 'remotebrowserutils.manifest', + 'RemoteWebNavigation.js', +] + +BROWSER_CHROME_MANIFESTS += ['tests/browser/browser.ini'] diff --git a/toolkit/components/remotebrowserutils/remotebrowserutils.manifest b/toolkit/components/remotebrowserutils/remotebrowserutils.manifest new file mode 100644 index 000000000..d762d65a0 --- /dev/null +++ b/toolkit/components/remotebrowserutils/remotebrowserutils.manifest @@ -0,0 +1,2 @@ +component {4b56964e-cdf3-4bb8-830c-0e2dad3f4ebd} RemoteWebNavigation.js process=main +contract @mozilla.org/remote-web-navigation;1 {4b56964e-cdf3-4bb8-830c-0e2dad3f4ebd} process=main
\ No newline at end of file diff --git a/toolkit/components/remotebrowserutils/tests/browser/.eslintrc.js b/toolkit/components/remotebrowserutils/tests/browser/.eslintrc.js new file mode 100644 index 000000000..7c8021192 --- /dev/null +++ b/toolkit/components/remotebrowserutils/tests/browser/.eslintrc.js @@ -0,0 +1,7 @@ +"use strict"; + +module.exports = { + "extends": [ + "../../../../../testing/mochitest/browser.eslintrc.js" + ] +}; diff --git a/toolkit/components/remotebrowserutils/tests/browser/browser.ini b/toolkit/components/remotebrowserutils/tests/browser/browser.ini new file mode 100644 index 000000000..916d0f9cb --- /dev/null +++ b/toolkit/components/remotebrowserutils/tests/browser/browser.ini @@ -0,0 +1,6 @@ +[DEFAULT] +run-if = e10s +support-files = + dummy_page.html + +[browser_RemoteWebNavigation.js] diff --git a/toolkit/components/remotebrowserutils/tests/browser/browser_RemoteWebNavigation.js b/toolkit/components/remotebrowserutils/tests/browser/browser_RemoteWebNavigation.js new file mode 100644 index 000000000..106758e81 --- /dev/null +++ b/toolkit/components/remotebrowserutils/tests/browser/browser_RemoteWebNavigation.js @@ -0,0 +1,156 @@ +/* eslint-env mozilla/frame-script */ + +const DUMMY1 = "http://example.com/browser/toolkit/modules/tests/browser/dummy_page.html"; +const DUMMY2 = "http://example.org/browser/toolkit/modules/tests/browser/dummy_page.html" + +function waitForLoad(uri) { + return BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser, false, uri); +} + +function waitForPageShow(browser = gBrowser.selectedBrowser) { + return BrowserTestUtils.waitForContentEvent(browser, "pageshow", true); +} + +function makeURI(url) { + return Cc["@mozilla.org/network/io-service;1"]. + getService(Ci.nsIIOService). + newURI(url, null, null); +} + +// Tests that loadURI accepts a referrer and it is included in the load. +add_task(function* test_referrer() { + gBrowser.selectedTab = gBrowser.addTab(); + let browser = gBrowser.selectedBrowser; + + browser.webNavigation.loadURI(DUMMY1, + Ci.nsIWebNavigation.LOAD_FLAGS_NONE, + makeURI(DUMMY2), + null, null); + yield waitForLoad(DUMMY1); + + yield ContentTask.spawn(browser, [ DUMMY1, DUMMY2 ], function([dummy1, dummy2]) { + is(content.location.href, dummy1, "Should have loaded the right URL"); + is(content.document.referrer, dummy2, "Should have the right referrer"); + }); + + gBrowser.removeCurrentTab(); +}); + +// Tests that remote access to webnavigation.sessionHistory works. +add_task(function* test_history() { + function checkHistoryIndex(browser, n) { + return ContentTask.spawn(browser, n, function(n) { + let history = docShell.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsISHistory); + is(history.index, n, "Should be at the right place in history"); + }); + } + gBrowser.selectedTab = gBrowser.addTab(); + let browser = gBrowser.selectedBrowser; + + browser.webNavigation.loadURI(DUMMY1, + Ci.nsIWebNavigation.LOAD_FLAGS_NONE, + null, null, null); + yield waitForLoad(DUMMY1); + + browser.webNavigation.loadURI(DUMMY2, + Ci.nsIWebNavigation.LOAD_FLAGS_NONE, + null, null, null); + yield waitForLoad(DUMMY2); + + yield ContentTask.spawn(browser, [DUMMY1, DUMMY2], function([dummy1, dummy2]) { + let history = docShell.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsISHistory); + is(history.count, 2, "Should be two history items"); + is(history.index, 1, "Should be at the right place in history"); + let entry = history.getEntryAtIndex(0, false); + is(entry.URI.spec, dummy1, "Should have the right history entry"); + entry = history.getEntryAtIndex(1, false); + is(entry.URI.spec, dummy2, "Should have the right history entry"); + }); + + let promise = waitForPageShow(); + browser.webNavigation.goBack(); + yield promise; + yield checkHistoryIndex(browser, 0); + + promise = waitForPageShow(); + browser.webNavigation.goForward(); + yield promise; + yield checkHistoryIndex(browser, 1); + + promise = waitForPageShow(); + browser.webNavigation.gotoIndex(0); + yield promise; + yield checkHistoryIndex(browser, 0); + + gBrowser.removeCurrentTab(); +}); + +// Tests that load flags are passed through to the content process. +add_task(function* test_flags() { + function checkHistory(browser, { count, index }) { + return ContentTask.spawn(browser, [ DUMMY2, count, index ], + function([ dummy2, count, index ]) { + let history = docShell.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsISHistory); + is(history.count, count, "Should be one history item"); + is(history.index, index, "Should be at the right place in history"); + let entry = history.getEntryAtIndex(index, false); + is(entry.URI.spec, dummy2, "Should have the right history entry"); + }); + } + + gBrowser.selectedTab = gBrowser.addTab(); + let browser = gBrowser.selectedBrowser; + + browser.webNavigation.loadURI(DUMMY1, + Ci.nsIWebNavigation.LOAD_FLAGS_NONE, + null, null, null); + yield waitForLoad(DUMMY1); + + browser.webNavigation.loadURI(DUMMY2, + Ci.nsIWebNavigation.LOAD_FLAGS_REPLACE_HISTORY, + null, null, null); + yield waitForLoad(DUMMY2); + yield checkHistory(browser, { count: 1, index: 0 }); + + browser.webNavigation.loadURI(DUMMY1, + Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_HISTORY, + null, null, null); + yield waitForLoad(DUMMY1); + yield checkHistory(browser, { count: 1, index: 0 }); + + gBrowser.removeCurrentTab(); +}); + +// Tests that attempts to use unsupported arguments throw an exception. +add_task(function* test_badarguments() { + if (!gMultiProcessBrowser) + return; + + gBrowser.selectedTab = gBrowser.addTab(); + let browser = gBrowser.selectedBrowser; + + try { + browser.webNavigation.loadURI(DUMMY1, + Ci.nsIWebNavigation.LOAD_FLAGS_NONE, + null, {}, null); + ok(false, "Should have seen an exception from trying to pass some postdata"); + } + catch (e) { + ok(true, "Should have seen an exception from trying to pass some postdata"); + } + + try { + browser.webNavigation.loadURI(DUMMY1, + Ci.nsIWebNavigation.LOAD_FLAGS_NONE, + null, null, {}); + ok(false, "Should have seen an exception from trying to pass some headers"); + } + catch (e) { + ok(true, "Should have seen an exception from trying to pass some headers"); + } + + gBrowser.removeCurrentTab(); +}); diff --git a/toolkit/components/remotebrowserutils/tests/browser/dummy_page.html b/toolkit/components/remotebrowserutils/tests/browser/dummy_page.html new file mode 100644 index 000000000..c1c9a4e04 --- /dev/null +++ b/toolkit/components/remotebrowserutils/tests/browser/dummy_page.html @@ -0,0 +1,7 @@ +<!DOCTYPE html> + +<html> +<body> +<p>Page</p> +</body> +</html> |