зеркало из https://github.com/mozilla/gecko-dev.git
Backed out changeset 01d03b6be047 (bug 1171200)
--HG-- rename : dom/manifest/ImageObjectProcessor.jsm => dom/manifest/ImageObjectProcessor.js rename : dom/manifest/ManifestProcessor.jsm => dom/manifest/ManifestProcessor.js rename : dom/manifest/ValueExtractor.jsm => dom/manifest/ValueExtractor.js
This commit is contained in:
Родитель
2b9faf4b60
Коммит
fa8ccba8c3
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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'
|
||||
];
|
|
@ -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
|
|
@ -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<Object>} 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<Object>}
|
||||
*/
|
||||
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<Object>} 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
|
|
@ -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() {}
|
||||
|
|
@ -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.
|
|
@ -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`);
|
||||
}
|
|
@ -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']
|
||||
|
|
|
@ -1,3 +1,2 @@
|
|||
[DEFAULT]
|
||||
[browser_hasManifestLink.js]
|
||||
[browser_ManifestObtainer_obtain.js]
|
||||
[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 =
|
||||
|
|
|
@ -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=<h1>${this.expected}</h1>`,
|
||||
'Content-Type=text/html; charset=utf-8',
|
||||
];
|
||||
const URL = `${defaultURL}?${query.join('&')}`;
|
||||
return URL;
|
||||
},
|
||||
run(result) {
|
||||
is(result, true, this.expected);
|
||||
},
|
||||
testData: `
|
||||
<link rel="manifesto" href='${defaultURL}?body={"name":"fail"}'>
|
||||
<link rel="foo bar manifest bar test" href='${defaultURL}?body={"name":"value"}'>
|
||||
<link rel="manifest" href='${defaultURL}?body={"name":"fail"}'>`
|
||||
}, {
|
||||
expected: 'Document does not have a web manifest.',
|
||||
get tabURL() {
|
||||
let query = [
|
||||
`body=<h1>${this.expected}</h1>`,
|
||||
'Content-Type=text/html; charset=utf-8',
|
||||
];
|
||||
const URL = `${defaultURL}?${query.join('&')}`;
|
||||
return URL;
|
||||
},
|
||||
run(result) {
|
||||
is(result, false, this.expected);
|
||||
},
|
||||
testData: `
|
||||
<link rel="amanifista" href='${defaultURL}?body={"name":"fail"}'>
|
||||
<link rel="foo bar manifesto bar test" href='${defaultURL}?body={"name":"pass-1"}'>
|
||||
<link rel="manifesto" href='${defaultURL}?body={"name":"fail"}'>`
|
||||
}, {
|
||||
expected: 'Manifest link is has empty href.',
|
||||
get tabURL() {
|
||||
let query = [
|
||||
`body=<h1>${this.expected}</h1>`,
|
||||
'Content-Type=text/html; charset=utf-8',
|
||||
];
|
||||
const URL = `${defaultURL}?${query.join('&')}`;
|
||||
return URL;
|
||||
},
|
||||
run(result) {
|
||||
is(result, false, this.expected);
|
||||
},
|
||||
testData: `
|
||||
<link rel="manifest" href="">
|
||||
<link rel="manifest" href='${defaultURL}?body={"name":"fail"}'>`
|
||||
}, {
|
||||
expected: 'Manifest link is missing.',
|
||||
get tabURL() {
|
||||
let query = [
|
||||
`body=<h1>${this.expected}</h1>`,
|
||||
'Content-Type=text/html; charset=utf-8',
|
||||
];
|
||||
const URL = `${defaultURL}?${query.join('&')}`;
|
||||
return URL;
|
||||
},
|
||||
run(result) {
|
||||
is(result, false, this.expected);
|
||||
},
|
||||
testData: `
|
||||
<link rel="manifest">
|
||||
<link rel="manifest" href='${defaultURL}?body={"name":"fail"}'>`
|
||||
}];
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
});
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
|
@ -48,7 +48,6 @@ EXTRA_JS_MODULES += [
|
|||
'ProfileAge.jsm',
|
||||
'Promise-backend.js',
|
||||
'Promise.jsm',
|
||||
'PromiseMessage.jsm',
|
||||
'PromiseUtils.jsm',
|
||||
'PropertyListUtils.jsm',
|
||||
'RemoteController.jsm',
|
||||
|
|
Загрузка…
Ссылка в новой задаче