diff --git a/dom/ipc/manifestMessages.js b/dom/ipc/manifestMessages.js index 4c5255b412c9..ea8cebf249ad 100644 --- a/dom/ipc/manifestMessages.js +++ b/dom/ipc/manifestMessages.js @@ -11,82 +11,112 @@ * * BUG: https://bugzilla.mozilla.org/show_bug.cgi?id=1083410 */ -/*globals Task, ManifestObtainer, ManifestFinder, content, sendAsyncMessage, addMessageListener, Components*/ +/*globals content, sendAsyncMessage, addMessageListener, Components*/ 'use strict'; const { utils: Cu, + classes: Cc, + interfaces: Ci } = Components; -Cu.import('resource://gre/modules/ManifestObtainer.jsm'); -Cu.import('resource://gre/modules/ManifestFinder.jsm'); -Cu.import('resource://gre/modules/Task.jsm'); +const { + ManifestProcessor +} = Cu.import('resource://gre/modules/WebManifest.jsm', {}); +const { + Task: { + spawn, async + } +} = Components.utils.import('resource://gre/modules/Task.jsm', {}); -const finder = new ManifestFinder(); +addMessageListener('DOM:ManifestObtainer:Obtain', async(function* (aMsg) { + const response = { + msgId: aMsg.data.msgId, + success: true, + result: undefined + }; + try { + response.result = yield fetchManifest(); + } catch (err) { + response.success = false; + response.result = cloneError(err); + } + sendAsyncMessage('DOM:ManifestObtainer:Obtain', response); +})); -const MessageHandler = { - registerListeners() { - addMessageListener( - 'DOM:WebManifest:hasManifestLink', - this.hasManifestLink.bind(this) - ); - addMessageListener( - 'DOM:ManifestObtainer:Obtain', - this.obtainManifest.bind(this) - ); - }, +function cloneError(aError) { + const clone = { + 'fileName': String(aError.fileName), + 'lineNumber': String(aError.lineNumber), + 'columnNumber': String(aError.columnNumber), + 'stack': String(aError.stack), + 'message': String(aError.message), + 'name': String(aError.name) + }; + return clone; +} - /** - * Check if the content document includes a link to a web manifest. - * @param {Object} aMsg The IPC message. - */ - hasManifestLink: Task.async(function* ({data: {id}}) { - const response = this.makeMsgResponse(id); - response.result = yield finder.hasManifestLink(content); - response.success = true; - sendAsyncMessage('DOM:WebManifest:hasManifestLink', response); - }), - - /** - * Obtains a web manifest from content by using the ManifestObtainer - * and messages back the result. - * @param {Object} aMsg The IPC message. - */ - obtainManifest: Task.async(function* ({data: {id}}) { - const obtainer = new ManifestObtainer(); - const response = this.makeMsgResponse(id); - try { - response.result = yield obtainer.obtainManifest(content); - response.success = true; - } catch (err) { - response.result = this.serializeError(err); +function fetchManifest() { + return spawn(function* () { + if (!content || content.top !== content) { + let msg = 'Content window must be a top-level browsing context.'; + throw new Error(msg); } - sendAsyncMessage('DOM:ManifestObtainer:Obtain', response); - }), - - makeMsgResponse(aId) { - return { - id: aId, - success: false, - result: undefined + const elem = content.document.querySelector('link[rel~="manifest"]'); + if (!elem || !elem.getAttribute('href')) { + let msg = 'No manifest to fetch.'; + throw new Error(msg); + } + // Throws on malformed URLs + const manifestURL = new content.URL(elem.href, elem.baseURI); + if (!canLoadManifest(elem)) { + let msg = `Content Security Policy: The page's settings blocked the `; + msg += `loading of a resource at ${elem.href}`; + throw new Error(msg); + } + const reqInit = { + mode: 'cors' }; - }, + if (elem.crossOrigin === 'use-credentials') { + reqInit.credentials = 'include'; + } + const req = new content.Request(manifestURL, reqInit); + req.setContentPolicyType(Ci.nsIContentPolicy.TYPE_WEB_MANIFEST); + const response = yield content.fetch(req); + const manifest = yield processResponse(response, content); + return manifest; + }); +} - /** - * Utility function to Serializes an JS Error, so it can be transferred over - * the message channel. - * FIX ME: https://bugzilla.mozilla.org/show_bug.cgi?id=1172586 - * @param {Error} aError The error to serialize. - * @return {Object} The serialized object. - */ - serializeError(aError) { - const clone = { - 'fileName': aError.fileName, - 'lineNumber': aError.lineNumber, - 'columnNumber': aError.columnNumber, - 'stack': aError.stack, - 'message': aError.message, - 'name': aError.name +function canLoadManifest(aElem) { + const contentPolicy = Cc['@mozilla.org/layout/content-policy;1'] + .getService(Ci.nsIContentPolicy); + const mimeType = aElem.type || 'application/manifest+json'; + const elemURI = BrowserUtils.makeURI( + aElem.href, aElem.ownerDocument.characterSet + ); + const shouldLoad = contentPolicy.shouldLoad( + Ci.nsIContentPolicy.TYPE_WEB_MANIFEST, elemURI, + aElem.ownerDocument.documentURIObject, + aElem, mimeType, null + ); + return shouldLoad === Ci.nsIContentPolicy.ACCEPT; +} + +function processResponse(aResp, aContentWindow) { + return spawn(function* () { + const badStatus = aResp.status < 200 || aResp.status >= 300; + if (aResp.type === 'error' || badStatus) { + let msg = + `Fetch error: ${aResp.status} - ${aResp.statusText} at ${aResp.url}`; + throw new Error(msg); + } + const text = yield aResp.text(); + const args = { + jsonText: text, + manifestURL: aResp.url, + docURL: aContentWindow.location.href }; - return clone; - }, -}; -MessageHandler.registerListeners(); + const processor = new ManifestProcessor(); + const manifest = processor.process(args); + return Cu.cloneInto(manifest, content); + }); +} diff --git a/dom/manifest/ImageObjectProcessor.jsm b/dom/manifest/ImageObjectProcessor.js similarity index 100% rename from dom/manifest/ImageObjectProcessor.jsm rename to dom/manifest/ImageObjectProcessor.js diff --git a/dom/manifest/ManifestFinder.jsm b/dom/manifest/ManifestFinder.jsm deleted file mode 100644 index 66a28a82d023..000000000000 --- a/dom/manifest/ManifestFinder.jsm +++ /dev/null @@ -1,58 +0,0 @@ -/* 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 https://mozilla.org/MPL/2.0/. */ -/* globals Components, Task, PromiseMessage */ -'use strict'; -const { - utils: Cu -} = Components; -Cu.import('resource://gre/modules/PromiseMessage.jsm'); -Cu.import('resource://gre/modules/Task.jsm'); - -/** - * @constructor - */ -function ManifestFinder() {} - -/** - * checks if a browser window's document has a conforming - * manifest link relationship. - * @param aWindowOrBrowser the XUL browser or window to check. - * @return {Promise} - */ -ManifestFinder.prototype.hasManifestLink = Task.async( - function* (aWindowOrBrowser) { - const msgKey = 'DOM:WebManifest:hasManifestLink'; - if (!(aWindowOrBrowser && (aWindowOrBrowser.namespaceURI || aWindowOrBrowser.location))) { - throw new TypeError('Invalid input.'); - } - if (isXULBrowser(aWindowOrBrowser)) { - const mm = aWindowOrBrowser.messageManager; - const reply = yield PromiseMessage.send(mm, msgKey); - return reply.data.result; - } - return checkForManifest(aWindowOrBrowser); - } -); - -function isXULBrowser(aBrowser) { - const XUL = 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul'; - return (aBrowser.namespaceURI && aBrowser.namespaceURI === XUL); -} - -function checkForManifest(aWindow) { - // Only top-level browsing contexts are valid. - if (!aWindow || aWindow.top !== aWindow) { - return false; - } - const elem = aWindow.document.querySelector('link[rel~="manifest"]'); - // Only if we have an element and a non-empty href attribute. - if (!elem || !elem.getAttribute('href')) { - return false; - } - return true; -} - -this.EXPORTED_SYMBOLS = [ // jshint ignore:line - 'ManifestFinder' -]; diff --git a/dom/manifest/ManifestObtainer.js b/dom/manifest/ManifestObtainer.js new file mode 100644 index 000000000000..999d89829597 --- /dev/null +++ b/dom/manifest/ManifestObtainer.js @@ -0,0 +1,92 @@ +/* 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/. + * + * ManifestObtainer is an implementation of: + * http://w3c.github.io/manifest/#obtaining + * + * Exposes public method `.obtainManifest(browserWindow)`, which returns + * a promise. If successful, you get back a manifest (string). + * + * For e10s compat, this JSM relies on the following to do + * the nessesary IPC: + * dom/ipc/manifestMessages.js + * + * whose internal URL is: + * 'chrome://global/content/manifestMessages.js' + * + * Which is injected into every browser instance via browser.js. + * + * BUG: https://bugzilla.mozilla.org/show_bug.cgi?id=1083410 + * exported ManifestObtainer + */ +'use strict'; +const MSG_KEY = 'DOM:ManifestObtainer:Obtain'; +let messageCounter = 0; +// FIXME: Ideally, we would store a reference to the +// message manager in a weakmap instead of needing a +// browserMap. However, trying to store a messageManager +// results in a TypeError because of: +// https://bugzilla.mozilla.org/show_bug.cgi?id=888600 +const browsersMap = new WeakMap(); + +function ManifestObtainer() {} + +ManifestObtainer.prototype = { + obtainManifest(aBrowserWindow) { + if (!aBrowserWindow) { + const err = new TypeError('Invalid input. Expected xul browser.'); + return Promise.reject(err); + } + const mm = aBrowserWindow.messageManager; + const onMessage = function(aMsg) { + const msgId = aMsg.data.msgId; + const { + resolve, reject + } = browsersMap.get(aBrowserWindow).get(msgId); + browsersMap.get(aBrowserWindow).delete(msgId); + // If we we've processed all messages, + // stop listening. + if (!browsersMap.get(aBrowserWindow).size) { + browsersMap.delete(aBrowserWindow); + mm.removeMessageListener(MSG_KEY, onMessage); + } + if (aMsg.data.success) { + return resolve(aMsg.data.result); + } + reject(toError(aMsg.data.result)); + }; + // If we are not already listening for messages + // start listening. + if (!browsersMap.has(aBrowserWindow)) { + browsersMap.set(aBrowserWindow, new Map()); + mm.addMessageListener(MSG_KEY, onMessage); + } + return new Promise((resolve, reject) => { + const msgId = messageCounter++; + browsersMap.get(aBrowserWindow).set(msgId, { + resolve: resolve, + reject: reject + }); + mm.sendAsyncMessage(MSG_KEY, { + msgId: msgId + }); + }); + + function toError(aErrorClone) { + let error; + switch (aErrorClone.name) { + case 'TypeError': + error = new TypeError(); + break; + default: + error = new Error(); + } + Object.getOwnPropertyNames(aErrorClone) + .forEach(name => error[name] = aErrorClone[name]); + return error; + } + } +}; +this.ManifestObtainer = ManifestObtainer; // jshint ignore:line +this.EXPORTED_SYMBOLS = ['ManifestObtainer']; // jshint ignore:line diff --git a/dom/manifest/ManifestObtainer.jsm b/dom/manifest/ManifestObtainer.jsm deleted file mode 100644 index f791f00bec52..000000000000 --- a/dom/manifest/ManifestObtainer.jsm +++ /dev/null @@ -1,170 +0,0 @@ -/* 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/. - */ - /* - * ManifestObtainer is an implementation of: - * http://w3c.github.io/manifest/#obtaining - * - * Exposes public method `.obtainManifest(Window)`, which returns - * a promise. If successful, you get back a manifest object. - * - * Import it with URL: - * 'chrome://global/content/manifestMessages.js' - * - * e10s IPC messaage from this components are handled by: - * dom/ipc/manifestMessages.js - * - * Which is injected into every browser instance via browser.js. - * - * exported ManifestObtainer - */ -/*globals Components, Task, PromiseMessage, XPCOMUtils, ManifestProcessor, BrowserUtils*/ -'use strict'; -const { - utils: Cu, - classes: Cc, - interfaces: Ci -} = Components; -Cu.import('resource://gre/modules/Task.jsm'); -Cu.import('resource://gre/modules/PromiseMessage.jsm'); -Cu.import('resource://gre/modules/XPCOMUtils.jsm'); -Cu.import('resource://gre/modules/ManifestProcessor.jsm'); -XPCOMUtils.defineLazyModuleGetter(this, 'BrowserUtils', // jshint ignore:line - 'resource://gre/modules/BrowserUtils.jsm'); - -const processor = new ManifestProcessor(); - -/** - * Asynchronously processes the result of response after having fetched - * a manifest. - * @param {Response} aResp Response from fetch(). - * @param {Window} aContentWindow The content window. - * @return {Promise} The processed manifest. - */ -const processResponse = Task.async(function* (aResp, aContentWindow) { - const badStatus = aResp.status < 200 || aResp.status >= 300; - if (aResp.type === 'error' || badStatus) { - const msg = - `Fetch error: ${aResp.status} - ${aResp.statusText} at ${aResp.url}`; - throw new Error(msg); - } - const text = yield aResp.text(); - const args = { - jsonText: text, - manifestURL: aResp.url, - docURL: aContentWindow.location.href - }; - const manifest = processor.process(args); - return manifest; -}); - -/** - * Asynchronously fetches a web manifest. - * @param {Window} a The content Window from where to extract the manifest. - * @return {Promise} - */ -const fetchManifest = Task.async(function* (aWindow) { - if (!aWindow || aWindow.top !== aWindow) { - let msg = 'Window must be a top-level browsing context.'; - throw new Error(msg); - } - const elem = aWindow.document.querySelector('link[rel~="manifest"]'); - if (!elem || !elem.getAttribute('href')) { - let msg = `No manifest to fetch at ${aWindow.location}`; - throw new Error(msg); - } - // Throws on malformed URLs - const manifestURL = new aWindow.URL(elem.href, elem.baseURI); - if (!canLoadManifest(elem)) { - let msg = `Content Security Policy: The page's settings blocked the `; - msg += `loading of a resource at ${elem.href}`; - throw new Error(msg); - } - const reqInit = { - mode: 'cors' - }; - if (elem.crossOrigin === 'use-credentials') { - reqInit.credentials = 'include'; - } - const req = new aWindow.Request(manifestURL, reqInit); - req.setContentPolicyType(Ci.nsIContentPolicy.TYPE_WEB_MANIFEST); - const response = yield aWindow.fetch(req); - const manifest = yield processResponse(response, aWindow); - return manifest; -}); - -/** - * Checks against security manager if we can load the web manifest. - * @param {HTMLLinkElement} aElem The HTML element to security check. - * @return {Boolean} True if it can, false if it can't. - */ -function canLoadManifest(aElem) { - const contentPolicy = Cc['@mozilla.org/layout/content-policy;1'] - .getService(Ci.nsIContentPolicy); - const mimeType = aElem.type || 'application/manifest+json'; - const elemURI = BrowserUtils.makeURI( - aElem.href, aElem.ownerDocument.characterSet - ); - const shouldLoad = contentPolicy.shouldLoad( - Ci.nsIContentPolicy.TYPE_WEB_MANIFEST, elemURI, - aElem.ownerDocument.documentURIObject, - aElem, mimeType, null - ); - return shouldLoad === Ci.nsIContentPolicy.ACCEPT; -} - -/** - * ManifestObtainer - * @constructor - */ -function ManifestObtainer() { -} - -/** - * Public interface for obtaining a web manifest. - * @param {XULWindow or DOMWindow} aWindow The Window from which to fetch - * the manifest. - * @return {Promise} The processed manifest. - */ -ManifestObtainer.prototype.obtainManifest = Task.async( - function* (aWindowOrBrowser) { - const msgKey = 'DOM:ManifestObtainer:Obtain'; - if (!(aWindowOrBrowser && (aWindowOrBrowser.namespaceURI || aWindowOrBrowser.location))) { - throw new TypeError('Invalid input.'); - } - if (isXULBrowser(aWindowOrBrowser)) { - const mm = aWindowOrBrowser.messageManager; - const {data: {success, result}} = yield PromiseMessage.send(mm, msgKey); - if (!success) { - const error = toError(result); - throw error; - } - return result; - } - const manifest = yield fetchManifest(aWindowOrBrowser); - return manifest; - } -); - -function toError(aErrorClone) { - let error; - switch (aErrorClone.name) { - case 'TypeError': - error = new TypeError(); - break; - default: - error = new Error(); - } - Object.getOwnPropertyNames(aErrorClone) - .forEach(name => error[name] = aErrorClone[name]); - return error; -} - -function isXULBrowser(aBrowser) { - const XUL = 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul'; - return (aBrowser.namespaceURI && aBrowser.namespaceURI === XUL); -} - -this.ManifestObtainer = ManifestObtainer; // jshint ignore:line -this.EXPORTED_SYMBOLS = ['ManifestObtainer']; // jshint ignore:line diff --git a/dom/manifest/ManifestProcessor.jsm b/dom/manifest/ManifestProcessor.js similarity index 95% rename from dom/manifest/ManifestProcessor.jsm rename to dom/manifest/ManifestProcessor.js index 50a0508030b1..b727d62d517e 100644 --- a/dom/manifest/ManifestProcessor.jsm +++ b/dom/manifest/ManifestProcessor.js @@ -19,10 +19,12 @@ * TODO: The constructor should accept the UA's supported display modes. * TODO: hook up developer tools to console. (1086997). */ -/*globals Components, ValueExtractor, ImageObjectProcessor, ConsoleAPI*/ +/*globals Components*/ 'use strict'; const { - utils: Cu + utils: Cu, + interfaces: Ci, + classes: Cc } = Components; Cu.importGlobalProperties(['URL']); const displayModes = new Set(['fullscreen', 'standalone', 'minimal-ui', @@ -32,12 +34,18 @@ const orientationTypes = new Set(['any', 'natural', 'landscape', 'portrait', 'portrait-primary', 'portrait-secondary', 'landscape-primary', 'landscape-secondary' ]); -Cu.import('resource://gre/modules/devtools/Console.jsm'); +const { + ConsoleAPI +} = Cu.import('resource://gre/modules/devtools/Console.jsm', {}); // ValueExtractor is used by the various processors to get values // from the manifest and to report errors. -Cu.import('resource://gre/modules/ValueExtractor.jsm'); +const { + ValueExtractor +} = Cu.import('resource://gre/modules/ValueExtractor.js', {}); // ImageObjectProcessor is used to process things like icons and images -Cu.import('resource://gre/modules/ImageObjectProcessor.jsm'); +const { + ImageObjectProcessor +} = Cu.import('resource://gre/modules/ImageObjectProcessor.js', {}); function ManifestProcessor() {} diff --git a/dom/manifest/ValueExtractor.jsm b/dom/manifest/ValueExtractor.js similarity index 96% rename from dom/manifest/ValueExtractor.jsm rename to dom/manifest/ValueExtractor.js index 69f924e3bfce..bc6bd1da16d3 100644 --- a/dom/manifest/ValueExtractor.jsm +++ b/dom/manifest/ValueExtractor.js @@ -25,7 +25,9 @@ ValueExtractor.prototype = { // objectName: string used to construct the developer warning. // property: the name of the property being extracted. // trim: boolean, if the value should be trimmed (used by string type). - extractValue({expectedType, object, objectName, property, trim}) { + extractValue({ + expectedType, object, objectName, property, trim + }) { const value = object[property]; const isArray = Array.isArray(value); // We need to special-case "array", as it's not a JS primitive. diff --git a/dom/manifest/WebManifest.jsm b/dom/manifest/WebManifest.jsm new file mode 100644 index 000000000000..a473cca3dd4b --- /dev/null +++ b/dom/manifest/WebManifest.jsm @@ -0,0 +1,19 @@ +/* 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 https://mozilla.org/MPL/2.0/. */ +/*exported EXPORTED_SYMBOLS, ManifestProcessor, ManifestObtainer*/ +/*globals Components */ +'use strict'; +const { + utils: Cu +} = Components; + +this.EXPORTED_SYMBOLS = [ + 'ManifestObtainer', + 'ManifestProcessor' +]; + +// Export public interfaces +for (let symbl of EXPORTED_SYMBOLS) { + Cu.import(`resource://gre/modules/${symbl}.js`); +} diff --git a/dom/manifest/moz.build b/dom/manifest/moz.build index 181ea32a3240..f4ac96bd7925 100644 --- a/dom/manifest/moz.build +++ b/dom/manifest/moz.build @@ -5,11 +5,11 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. EXTRA_JS_MODULES += [ - 'ImageObjectProcessor.jsm', - 'ManifestFinder.jsm', - 'ManifestObtainer.jsm', - 'ManifestProcessor.jsm', - 'ValueExtractor.jsm', + 'ImageObjectProcessor.js', + 'ManifestObtainer.js', + 'ManifestProcessor.js', + 'ValueExtractor.js', + 'WebManifest.jsm' ] MOCHITEST_MANIFESTS += ['test/mochitest.ini'] diff --git a/dom/manifest/test/browser.ini b/dom/manifest/test/browser.ini index 5b112d788b6e..3fa909b08c96 100644 --- a/dom/manifest/test/browser.ini +++ b/dom/manifest/test/browser.ini @@ -1,3 +1,2 @@ [DEFAULT] -[browser_hasManifestLink.js] -[browser_ManifestObtainer_obtain.js] +[browser_ManifestObtainer_obtain.js] \ No newline at end of file diff --git a/dom/manifest/test/browser_ManifestObtainer_obtain.js b/dom/manifest/test/browser_ManifestObtainer_obtain.js index ba2337a7c726..527d7f3cb692 100644 --- a/dom/manifest/test/browser_ManifestObtainer_obtain.js +++ b/dom/manifest/test/browser_ManifestObtainer_obtain.js @@ -3,7 +3,7 @@ 'use strict'; const { ManifestObtainer -} = Cu.import('resource://gre/modules/ManifestObtainer.jsm', {}); +} = Cu.import('resource://gre/modules/WebManifest.jsm', {}); requestLongerTimeout(4); // e10s tests take time. const defaultURL = diff --git a/dom/manifest/test/browser_hasManifestLink.js b/dom/manifest/test/browser_hasManifestLink.js deleted file mode 100644 index 4c9969cadc8b..000000000000 --- a/dom/manifest/test/browser_hasManifestLink.js +++ /dev/null @@ -1,109 +0,0 @@ -//Used by JSHint: -/*global Cu, BrowserTestUtils, is, ok, add_task, gBrowser, ManifestFinder */ -'use strict'; -Cu.import('resource://gre/modules/ManifestFinder.jsm', this); // jshint ignore:line - -const finder = new ManifestFinder(); -const defaultURL = - 'http://example.org/tests/dom/manifest/test/resource.sjs'; -const tests = [{ - expected: 'Document has a web manifest.', - get tabURL() { - let query = [ - `body=

${this.expected}

`, - 'Content-Type=text/html; charset=utf-8', - ]; - const URL = `${defaultURL}?${query.join('&')}`; - return URL; - }, - run(result) { - is(result, true, this.expected); - }, - testData: ` - - - ` -}, { - expected: 'Document does not have a web manifest.', - get tabURL() { - let query = [ - `body=

${this.expected}

`, - 'Content-Type=text/html; charset=utf-8', - ]; - const URL = `${defaultURL}?${query.join('&')}`; - return URL; - }, - run(result) { - is(result, false, this.expected); - }, - testData: ` - - - ` -}, { - expected: 'Manifest link is has empty href.', - get tabURL() { - let query = [ - `body=

${this.expected}

`, - 'Content-Type=text/html; charset=utf-8', - ]; - const URL = `${defaultURL}?${query.join('&')}`; - return URL; - }, - run(result) { - is(result, false, this.expected); - }, - testData: ` - - ` -}, { - expected: 'Manifest link is missing.', - get tabURL() { - let query = [ - `body=

${this.expected}

`, - 'Content-Type=text/html; charset=utf-8', - ]; - const URL = `${defaultURL}?${query.join('&')}`; - return URL; - }, - run(result) { - is(result, false, this.expected); - }, - testData: ` - - ` -}]; - -/** - * Test basic API error conditions - */ -add_task(function* () { - let expected = 'Invalid types should throw a TypeError.'; - for (let invalidValue of [undefined, null, 1, {}, 'test']) { - try { - yield finder.hasManifestLink(invalidValue); - ok(false, expected); - } catch (e) { - is(e.name, 'TypeError', expected); - } - } -}); - -add_task(function* () { - for (let test of tests) { - let tabOptions = { - gBrowser: gBrowser, - url: test.tabURL, - }; - yield BrowserTestUtils.withNewTab( - tabOptions, - browser => testHasManifest(browser, test) - ); - } - - function* testHasManifest(aBrowser, aTest) { - aBrowser.contentWindowAsCPOW.document.head.innerHTML = aTest.testData; - const result = yield finder.hasManifestLink(aBrowser); - aTest.run(result); - } -}); diff --git a/dom/manifest/test/common.js b/dom/manifest/test/common.js index 5b4d38d03bd1..d3aba06d0cb3 100644 --- a/dom/manifest/test/common.js +++ b/dom/manifest/test/common.js @@ -1,11 +1,11 @@ /** * Common infrastructure for manifest tests. **/ -/*globals SpecialPowers, ManifestProcessor*/ + 'use strict'; const { ManifestProcessor -} = SpecialPowers.Cu.import('resource://gre/modules/ManifestProcessor.jsm'); +} = SpecialPowers.Cu.import('resource://gre/modules/WebManifest.jsm'); const processor = new ManifestProcessor(); const manifestURL = new URL(document.location.origin + '/manifest.json'); const docURL = document.location; diff --git a/dom/security/test/csp/browser_test_web_manifest.js b/dom/security/test/csp/browser_test_web_manifest.js index 1f1e025767da..118f6fa28fc6 100644 --- a/dom/security/test/csp/browser_test_web_manifest.js +++ b/dom/security/test/csp/browser_test_web_manifest.js @@ -5,15 +5,21 @@ * In particular, the tests check that default-src and manifest-src directives are * are respected by the ManifestObtainer. */ -/*globals SpecialPowers, requestLongerTimeout, ok, Cu, is, add_task, gBrowser, BrowserTestUtils, ManifestObtainer*/ +/*globals Components*/ 'use strict'; requestLongerTimeout(10); // e10s tests take time. -Cu.import('resource://gre/modules/ManifestObtainer.jsm', this); // jshint ignore:line +const { + ManifestObtainer +} = Components.utils.import('resource://gre/modules/WebManifest.jsm', {}); const path = '/tests/dom/security/test/csp/'; const testFile = `file=${path}file_web_manifest.html`; const remoteFile = `file=${path}file_web_manifest_remote.html`; +const httpsManifest = `file=${path}file_web_manifest_https.html`; +const mixedContent = `file=${path}file_web_manifest_mixed_content.html`; const server = 'file_testserver.sjs'; const defaultURL = `http://example.org${path}${server}`; +const remoteURL = `http://mochi.test:8888`; +const secureURL = `https://example.com${path}${server}`; const tests = [ // CSP block everything, so trying to load a manifest // will result in a policy violation. @@ -242,7 +248,7 @@ function NetworkObserver(test) { let success = false; this.finished = new Promise((resolver) => { finishedTest = resolver; - }); + }) this.observe = function observer(subject, topic) { SpecialPowers.removeObserver(this, 'csp-on-violate-policy'); test.run(topic); diff --git a/dom/security/test/csp/browser_test_web_manifest_mixed_content.js b/dom/security/test/csp/browser_test_web_manifest_mixed_content.js index d1d739926a0b..b7d1b7b68807 100644 --- a/dom/security/test/csp/browser_test_web_manifest_mixed_content.js +++ b/dom/security/test/csp/browser_test_web_manifest_mixed_content.js @@ -3,12 +3,10 @@ * Check that mixed content blocker works prevents fetches of * mixed content manifests. */ -/*globals Cu, add_task, ok, gBrowser, BrowserTestUtils, ManifestObtainer*/ 'use strict'; const { ManifestObtainer -} = Cu.import('resource://gre/modules/ManifestObtainer.jsm', this); // jshint ignore:line -const obtainer = new ManifestObtainer(); +} = Components.utils.import('resource://gre/modules/WebManifest.jsm', {}); const path = '/tests/dom/security/test/csp/'; const mixedContent = `file=${path}file_web_manifest_mixed_content.html`; const server = 'file_testserver.sjs'; @@ -33,7 +31,7 @@ const tests = [ ]; //jscs:disable -add_task(function* () { +add_task(function*() { //jscs:enable for (let test of tests) { let tabOptions = { @@ -47,11 +45,11 @@ add_task(function* () { } function* testObtainingManifest(aBrowser, aTest) { - let manifest; + const obtainer = new ManifestObtainer(); try { yield obtainer.obtainManifest(aBrowser); } catch (e) { - return aTest.run(e); + aTest.run(e) } } }); diff --git a/toolkit/modules/PromiseMessage.jsm b/toolkit/modules/PromiseMessage.jsm deleted file mode 100644 index 53105139a9c4..000000000000 --- a/toolkit/modules/PromiseMessage.jsm +++ /dev/null @@ -1,36 +0,0 @@ -/* 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'; - -this.EXPORTED_SYMBOLS = ['PromiseMessage']; - -let msgId = 0; - -let PromiseMessage = { - send(messageManager, name, data = {}) { - let id = msgId++; - - // Make a copy of data so that the caller doesn't see us setting 'id'. - let dataCopy = {}; - for (let prop in data) { - dataCopy[prop] = data[prop]; - } - dataCopy.id = id; - - // Send the message. - messageManager.sendAsyncMessage(name, dataCopy); - - // Return a promise that resolves when we get a reply (a message of the same name). - return new Promise(resolve => { - messageManager.addMessageListener(name, function listener(reply) { - if (reply.data.id !== id) { - return; - } - messageManager.removeMessageListener(name, listener); - resolve(reply); - }); - }); - } -}; diff --git a/toolkit/modules/moz.build b/toolkit/modules/moz.build index 2a0cfb3f3f5b..b61e0a3bf613 100644 --- a/toolkit/modules/moz.build +++ b/toolkit/modules/moz.build @@ -48,7 +48,6 @@ EXTRA_JS_MODULES += [ 'ProfileAge.jsm', 'Promise-backend.js', 'Promise.jsm', - 'PromiseMessage.jsm', 'PromiseUtils.jsm', 'PropertyListUtils.jsm', 'RemoteController.jsm',