Bug 1169633 - [Browser API] getWebManifest(). r=kanru, r=bholley

This commit is contained in:
Marcos Caceres 2015-09-16 06:55:00 +02:00
parent fb2b8869b7
commit 1819dd4f55
15 changed files with 253 additions and 4 deletions

View File

@ -12,10 +12,15 @@ var { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/BrowserElementPromptService.jsm");
Cu.import("resource://gre/modules/Task.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "acs",
"@mozilla.org/audiochannel/service;1",
"nsIAudioChannelService");
XPCOMUtils.defineLazyModuleGetter(this, "ManifestFinder",
"resource://gre/modules/ManifestFinder.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ManifestObtainer",
"resource://gre/modules/ManifestObtainer.jsm");
var kLongestReturnedString = 128;
@ -251,7 +256,8 @@ BrowserElementChild.prototype = {
"set-audio-channel-volume": this._recvSetAudioChannelVolume,
"get-audio-channel-muted": this._recvGetAudioChannelMuted,
"set-audio-channel-muted": this._recvSetAudioChannelMuted,
"get-is-audio-channel-active": this._recvIsAudioChannelActive
"get-is-audio-channel-active": this._recvIsAudioChannelActive,
"get-web-manifest": this._recvGetWebManifest,
}
addMessageListener("browser-element-api:call", function(aMessage) {
@ -1478,6 +1484,27 @@ BrowserElementChild.prototype = {
});
},
_recvGetWebManifest: Task.async(function* (data) {
debug(`Received GetWebManifest message: (${data.json.id})`);
let manifest = null;
let hasManifest = ManifestFinder.contentHasManifestLink(content);
if (hasManifest) {
try {
manifest = yield ManifestObtainer.contentObtainManifest(content);
} catch (e) {
sendAsyncMsg('got-web-manifest', {
id: data.json.id,
errorMsg: `Error fetching web manifest: ${e}.`,
});
return;
}
}
sendAsyncMsg('got-web-manifest', {
id: data.json.id,
successRv: manifest
});
}),
_initFinder: function() {
if (!this._finder) {
try {

View File

@ -210,7 +210,8 @@ BrowserElementParent.prototype = {
"got-set-audio-channel-volume": this._gotDOMRequestResult,
"got-audio-channel-muted": this._gotDOMRequestResult,
"got-set-audio-channel-muted": this._gotDOMRequestResult,
"got-is-audio-channel-active": this._gotDOMRequestResult
"got-is-audio-channel-active": this._gotDOMRequestResult,
"got-web-manifest": this._gotDOMRequestResult,
};
let mmSecuritySensitiveCalls = {
@ -1033,6 +1034,8 @@ BrowserElementParent.prototype = {
{audioChannel: aAudioChannel});
},
getWebManifest: defineDOMRequestMethod('get-web-manifest'),
/**
* Called when the visibility of the window which owns this iframe changes.
*/

View File

@ -0,0 +1,78 @@
/* 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/. */
/*
* This is an approximate implementation of ES7's async-await pattern.
* see: https://github.com/tc39/ecmascript-asyncawait
*
* It allows for simple creation of async function and "tasks".
*
* For example:
*
* var myThinger = {
* doAsynThing: async(function*(url){
* var result = yield fetch(url);
* return process(result);
* });
* }
*
* And Task-like things can be created as follows:
*
* var myTask = async(function*{
* var result = yield fetch(url);
* return result;
* });
* //returns a promise
*
* myTask().then(doSomethingElse);
*
*/
(function(exports) {
"use strict";
function async(func, self) {
return function asyncFunction() {
const functionArgs = Array.from(arguments);
return new Promise(function(resolve, reject) {
var gen;
if (typeof func !== "function") {
reject(new TypeError("Expected a Function."));
}
//not a generator, wrap it.
if (func.constructor.name !== "GeneratorFunction") {
gen = (function*() {
return func.apply(self, functionArgs);
}());
} else {
gen = func.apply(self, functionArgs);
}
try {
step(gen.next(undefined));
} catch (err) {
reject(err);
}
function step({value, done}) {
if (done) {
return resolve(value);
}
if (value instanceof Promise) {
return value.then(
result => step(gen.next(result)),
error => {
try {
step(gen.throw(error));
} catch (err) {
throw err;
}
}
).catch(err => reject(err));
}
step(gen.next(value));
}
});
};
}
exports.async = async;
}(this || self));

View File

@ -0,0 +1,63 @@
/* Any copyright is dedicated to the public domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/*globals async, ok, is, SimpleTest, browserElementTestHelpers*/
// Bug 1169633 - getWebManifest tests
'use strict';
SimpleTest.waitForExplicitFinish();
browserElementTestHelpers.setEnabledPref(true);
browserElementTestHelpers.addPermission();
// request to load a manifest from a page that doesn't have a manifest.
// The expected result to be null.
var test1 = async(function* () {
var manifest = yield requestManifest('file_empty.html');
is(manifest, null, 'it should be null.');
});
// request to load a manifest from a page that has a manifest.
// The expected manifest to have a property name whose value is 'pass'.
var test2 = async(function* () {
var manifest = yield requestManifest('file_web_manifest.html');
is(manifest && manifest.name, 'pass', 'it should return a manifest with name pass.');
});
// Cause an exception by attempting to fetch a file URL,
// expect onerror to be called.
var test3 = async(function* () {
var gotError = false;
try {
yield requestManifest('file_illegal_web_manifest.html');
} catch (err) {
gotError = true;
}
ok(gotError, 'onerror was called on the DOMRequest.');
});
// Run the tests
Promise
.all([test1(), test2(), test3()])
.then(SimpleTest.finish);
function requestManifest(url) {
var iframe = document.createElement('iframe');
iframe.setAttribute('mozbrowser', 'true');
iframe.src = url;
document.body.appendChild(iframe);
return new Promise((resolve, reject) => {
iframe.addEventListener('mozbrowserloadend', function loadend() {
iframe.removeEventListener('mozbrowserloadend', loadend);
SimpleTest.executeSoon(() => {
var req = iframe.getWebManifest();
req.onsuccess = () => {
document.body.removeChild(iframe);
resolve(req.result);
};
req.onerror = () => {
document.body.removeChild(iframe);
reject(new Error(req.error));
};
});
});
});
}

View File

@ -0,0 +1,6 @@
<!doctype html>
<meta charset=utf-8>
<head>
<link rel="manifest" href="file://this_is_not_allowed!">
</head>
<h1>Support Page for Web Manifest Tests</h1>

View File

@ -0,0 +1,6 @@
<!doctype html>
<meta charset=utf-8>
<head>
<link rel="manifest" href="file_web_manifest.json">
</head>
<h1>Support Page for Web Manifest Tests</h1>

View File

@ -0,0 +1 @@
{"name": "pass"}

View File

@ -114,3 +114,4 @@ disabled = bug 924771
[test_browserElement_oop_GetContentDimensions.html]
[test_browserElement_oop_AudioChannel.html]
[test_browserElement_oop_SetNFCFocus.html]
[test_browserElement_oop_getWebManifest.html]

View File

@ -3,6 +3,7 @@ skip-if = buildapp == 'mulet' || (buildapp == 'b2g' && (toolkit != 'gonk' || deb
support-files =
../../../browser/base/content/test/general/audio.ogg
../../../dom/media/test/short-video.ogv
async.js
browserElementTestHelpers.js
browserElement_Alert.js
browserElement_AlertInFrame.js
@ -37,6 +38,7 @@ support-files =
browserElement_FrameWrongURI.js
browserElement_GetScreenshot.js
browserElement_GetScreenshotDppx.js
browserElement_getWebManifest.js
browserElement_Iconchange.js
browserElement_LoadEvents.js
browserElement_Manifestchange.js
@ -128,10 +130,14 @@ support-files =
file_wyciwyg.html
file_audio.html
iframe_file_audio.html
file_web_manifest.html
file_web_manifest.json
file_illegal_web_manifest.html
# Note: browserElementTestHelpers.js looks at the test's filename to determine
# whether the test should be OOP. "_oop_" signals OOP, "_inproc_" signals in
# process. Default is OOP.
[test_browserElement_inproc_getWebManifest.html]
[test_browserElement_NoAttr.html]
[test_browserElement_NoPref.html]
[test_browserElement_NoPermission.html]

View File

@ -0,0 +1,17 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for Bug 1169633</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="browserElementTestHelpers.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<script type="application/javascript;version=1.8"
src="async.js">
</script>
<script type="application/javascript;version=1.8"
src="browserElement_getWebManifest.js">
</script>
</body>
</html>

View File

@ -0,0 +1,16 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for Bug 1169633</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="browserElementTestHelpers.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<script type="application/javascript;version=1.8"
src="async.js"></script>
<script type="application/javascript;version=1.8"
src="browserElement_getWebManifest.js">
</script>
</body>
</html>

View File

@ -9,7 +9,7 @@
interface nsIDOMDOMRequest;
interface nsIFrameLoader;
[scriptable, function, uuid(c0c2dd9b-41ef-42dd-a4c1-e456619c1941)]
[scriptable, function, uuid(00d0e19d-bd67-491f-8e85-b9905224d3bb)]
interface nsIBrowserElementNextPaintListener : nsISupports
{
void recvNextPaint();
@ -26,7 +26,7 @@ interface nsIBrowserElementNextPaintListener : nsISupports
* Interface to the BrowserElementParent implementation. All methods
* but setFrameLoader throw when the remote process is dead.
*/
[scriptable, uuid(56bd3e12-4a8b-422a-89fc-6dc25aa30aa2)]
[scriptable, uuid(1e098c3a-7d65-452d-a2b2-9ffd1b6e04bb)]
interface nsIBrowserElementAPI : nsISupports
{
const long FIND_CASE_SENSITIVE = 0;
@ -100,4 +100,6 @@ interface nsIBrowserElementAPI : nsISupports
void setNFCFocus(in boolean isFocus);
nsIDOMDOMRequest executeScript(in DOMString script, in jsval options);
nsIDOMDOMRequest getWebManifest();
};

View File

@ -747,4 +747,21 @@ nsBrowserElement::ExecuteScript(const nsAString& aScript,
return req.forget().downcast<DOMRequest>();
}
already_AddRefed<DOMRequest>
nsBrowserElement::GetWebManifest(ErrorResult& aRv)
{
NS_ENSURE_TRUE(IsBrowserElementOrThrow(aRv), nullptr);
nsCOMPtr<nsIDOMDOMRequest> req;
nsresult rv = mBrowserElementAPI->GetWebManifest(getter_AddRefs(req));
if (NS_WARN_IF(NS_FAILED(rv))) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return nullptr;
}
return req.forget().downcast<DOMRequest>();
}
} // namespace mozilla

View File

@ -112,6 +112,8 @@ public:
const dom::BrowserElementExecuteScriptOptions& aOptions,
ErrorResult& aRv);
already_AddRefed<dom::DOMRequest> GetWebManifest(ErrorResult& aRv);
void SetNFCFocus(bool isFocus,
ErrorResult& aRv);

View File

@ -174,5 +174,9 @@ interface BrowserElementPrivileged {
CheckAllPermissions="browser browser:universalxss"]
DOMRequest executeScript(DOMString script,
optional BrowserElementExecuteScriptOptions options);
[Throws,
Pref="dom.mozBrowserFramesEnabled",
CheckAllPermissions="browser"]
DOMRequest getWebManifest();
};