merge mozilla-inbound to mozilla-central a=merge

This commit is contained in:
Carsten "Tomcat" Book 2015-11-23 14:08:50 +01:00
commit 5f1ac1afb3
417 changed files with 11977 additions and 4672 deletions

View File

@ -3,7 +3,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
chrome.jar:
% content branding %content/branding/
% content branding %content/branding/ contentaccessible=yes
content/branding/about.png (about.png)
content/branding/logoWordmark.png (logoWordmark.png)
content/branding/logo.png (logo.png)

View File

@ -3,7 +3,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
chrome.jar:
% content branding %content/branding/
% content branding %content/branding/ contentaccessible=yes
content/branding/about.png (about.png)
content/branding/logoWordmark.png (logoWordmark.png)
content/branding/logo.png (logo.png)

View File

@ -3,7 +3,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
chrome.jar:
% content branding %content/branding/
% content branding %content/branding/ contentaccessible=yes
content/branding/about.png (about.png)
content/branding/logoWordmark.png (logoWordmark.png)
content/branding/logo.png (logo.png)

View File

@ -3,7 +3,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
chrome.jar:
% content branding %content/branding/
% content branding %content/branding/ contentaccessible=yes
content/branding/about.png (about.png)
content/branding/logoWordmark.png (logoWordmark.png)
content/branding/logo.png (logo.png)

View File

@ -5,7 +5,7 @@
chrome.jar:
% content branding %content/branding/
% content branding %content/branding/ contentaccessible=yes
% content b2g %content/
content/arrow.svg (content/arrow.svg)

View File

@ -32,6 +32,7 @@ externalProtocolLaunchBtn=Launch application
malwareBlocked=The site at %S has been reported as an attack site and has been blocked based on your security preferences.
unwantedBlocked=The site at %S has been reported as serving unwanted software and has been blocked based on your security preferences.
phishingBlocked=The website at %S has been reported as a web forgery designed to trick users into sharing personal or financial information.
forbiddenBlocked=The site at %S has been blocked by your browser configuration.
cspBlocked=This page has a content security policy that prevents it from being loaded in this way.
corruptedContentError=The page you are trying to view cannot be shown because an error in the data transmission was detected.
remoteXUL=This page uses an unsupported technology that is no longer available by default in Firefox.

View File

@ -423,6 +423,7 @@
<h1 id="et_nssBadCert">&nssBadCert.title;</h1>
<h1 id="et_malwareBlocked">&malwareBlocked.title;</h1>
<h1 id="et_unwantedBlocked">&unwantedBlocked.title;</h1>
<h1 id="et_forbiddenBlocked">&forbiddenBlocked.title;</h1>
<h1 id="et_cspBlocked">&cspBlocked.title;</h1>
<h1 id="et_remoteXUL">&remoteXUL.title;</h1>
<h1 id="et_corruptedContentError">&corruptedContentError.title;</h1>
@ -452,6 +453,7 @@
<div id="ed_nssBadCert">&nssBadCert.longDesc2;</div>
<div id="ed_malwareBlocked">&malwareBlocked.longDesc;</div>
<div id="ed_unwantedBlocked">&unwantedBlocked.longDesc;</div>
<div id="ed_forbiddenBlocked">&forbiddenBlocked.longDesc;</div>
<div id="ed_cspBlocked">&cspBlocked.longDesc;</div>
<div id="ed_remoteXUL">&remoteXUL.longDesc;</div>
<div id="ed_corruptedContentError">&corruptedContentError.longDesc;</div>

View File

@ -68,111 +68,76 @@
return getURL();
}
}
function initPage()
{
// Handoff to the appropriate initializer, based on error code
var error = "";
switch (getErrorCode()) {
case "malwareBlocked" :
initPage_malware();
error = "malware";
break;
case "phishingBlocked" :
initPage_phishing();
error = "phishing";
break;
case "unwantedBlocked" :
initPage_unwanted();
error = "unwanted";
break;
case "forbiddenBlocked" :
error = "forbidden";
break;
default:
return;
}
}
/**
* Initialize custom strings and functionality for blocked malware case
*/
function initPage_malware()
{
// Remove phishing and unwanted strings
var el = document.getElementById("errorTitleText_phishing");
el.parentNode.removeChild(el);
el = document.getElementById("errorShortDescText_phishing");
el.parentNode.removeChild(el);
var el;
el = document.getElementById("errorLongDescText_phishing");
el.parentNode.removeChild(el);
if (error !== "malware") {
el = document.getElementById("errorTitleText_malware");
el.parentNode.removeChild(el);
el = document.getElementById("errorShortDescText_malware");
el.parentNode.removeChild(el);
el = document.getElementById("errorLongDescText_malware");
el.parentNode.removeChild(el);
}
el = document.getElementById("errorTitleText_unwanted");
el.parentNode.removeChild(el);
if (error !== "phishing") {
el = document.getElementById("errorTitleText_phishing");
el.parentNode.removeChild(el);
el = document.getElementById("errorShortDescText_phishing");
el.parentNode.removeChild(el);
el = document.getElementById("errorLongDescText_phishing");
el.parentNode.removeChild(el);
}
el = document.getElementById("errorShortDescText_unwanted");
el.parentNode.removeChild(el);
if (error !== "unwanted") {
el = document.getElementById("errorTitleText_unwanted");
el.parentNode.removeChild(el);
el = document.getElementById("errorShortDescText_unwanted");
el.parentNode.removeChild(el);
el = document.getElementById("errorLongDescText_unwanted");
el.parentNode.removeChild(el);
}
el = document.getElementById("errorLongDescText_unwanted");
el.parentNode.removeChild(el);
if (error !== "forbidden") {
el = document.getElementById("errorTitleText_forbidden");
el.parentNode.removeChild(el);
el = document.getElementById("errorShortDescText_forbidden");
el.parentNode.removeChild(el);
} else {
el = document.getElementById("ignoreWarningButton");
el.parentNode.removeChild(el);
el = document.getElementById("reportButton");
el.parentNode.removeChild(el);
}
// Set sitename
document.getElementById("malware_sitename").textContent = getHostString();
document.title = document.getElementById("errorTitleText_malware")
document.getElementById(error + "_sitename").textContent = getHostString();
document.title = document.getElementById("errorTitleText_" + error)
.innerHTML;
}
/**
* Initialize custom strings and functionality for blocked malware case
*/
function initPage_unwanted()
{
// Remove phishing and malware strings
var el = document.getElementById("errorTitleText_phishing");
el.parentNode.removeChild(el);
el = document.getElementById("errorShortDescText_phishing");
el.parentNode.removeChild(el);
el = document.getElementById("errorLongDescText_phishing");
el.parentNode.removeChild(el);
el = document.getElementById("errorTitleText_malware");
el.parentNode.removeChild(el);
el = document.getElementById("errorShortDescText_malware");
el.parentNode.removeChild(el);
el = document.getElementById("errorLongDescText_malware");
el.parentNode.removeChild(el);
// Set sitename
document.getElementById("unwanted_sitename").textContent = getHostString();
document.title = document.getElementById("errorTitleText_unwanted")
.innerHTML;
}
/**
* Initialize custom strings and functionality for blocked phishing case
*/
function initPage_phishing()
{
// Remove malware and unwanted strings
var el = document.getElementById("errorTitleText_malware");
el.parentNode.removeChild(el);
el = document.getElementById("errorShortDescText_malware");
el.parentNode.removeChild(el);
el = document.getElementById("errorLongDescText_malware");
el.parentNode.removeChild(el);
el = document.getElementById("errorTitleText_unwanted");
el.parentNode.removeChild(el);
el = document.getElementById("errorShortDescText_unwanted");
el.parentNode.removeChild(el);
el = document.getElementById("errorLongDescText_unwanted");
el.parentNode.removeChild(el);
// Set sitename
document.getElementById("phishing_sitename").textContent = getHostString();
document.title = document.getElementById("errorTitleText_phishing")
.innerHTML;
// Inform the test harness that we're done loading the page
var event = new CustomEvent("AboutBlockedLoaded");
document.dispatchEvent(event);
}
]]></script>
<style type="text/css">
@ -213,6 +178,7 @@
<h1 id="errorTitleText_phishing">&safeb.blocked.phishingPage.title;</h1>
<h1 id="errorTitleText_malware">&safeb.blocked.malwarePage.title;</h1>
<h1 id="errorTitleText_unwanted">&safeb.blocked.unwantedPage.title;</h1>
<h1 id="errorTitleText_forbidden">&safeb.blocked.forbiddenPage.title;</h1>
</div>
<div id="errorLongContent">
@ -222,6 +188,7 @@
<p id="errorShortDescText_phishing">&safeb.blocked.phishingPage.shortDesc;</p>
<p id="errorShortDescText_malware">&safeb.blocked.malwarePage.shortDesc;</p>
<p id="errorShortDescText_unwanted">&safeb.blocked.unwantedPage.shortDesc;</p>
<p id="errorShortDescText_forbidden">&safeb.blocked.forbiddenPage.shortDesc;</p>
</div>
<!-- Long Description -->

View File

@ -2958,10 +2958,16 @@ var BrowserOnClick = {
onAboutBlocked: function (elementId, reason, isTopFrame, location) {
// Depending on what page we are displaying here (malware/phishing/unwanted)
// use the right strings and links for each.
let bucketName = "WARNING_PHISHING_PAGE_";
let bucketName = "";
let sendTelemetry = false;
if (reason === 'malware') {
sendTelemetry = true;
bucketName = "WARNING_MALWARE_PAGE_";
} else if (reason === 'phishing') {
sendTelemetry = true;
bucketName = "WARNING_PHISHING_PAGE_";
} else if (reason === 'unwanted') {
sendTelemetry = true;
bucketName = "WARNING_UNWANTED_PAGE_";
}
let secHistogram = Services.telemetry.getHistogramById("SECURITY_UI");
@ -2969,7 +2975,9 @@ var BrowserOnClick = {
bucketName += isTopFrame ? "TOP_" : "FRAME_";
switch (elementId) {
case "getMeOutButton":
secHistogram.add(nsISecTel[bucketName + "GET_ME_OUT_OF_HERE"]);
if (sendTelemetry) {
secHistogram.add(nsISecTel[bucketName + "GET_ME_OUT_OF_HERE"]);
}
getMeOutOfHere();
break;
@ -2979,13 +2987,16 @@ var BrowserOnClick = {
// We log even if malware/phishing/unwanted info URL couldn't be found:
// the measurement is for how many users clicked the WHY BLOCKED button
secHistogram.add(nsISecTel[bucketName + "WHY_BLOCKED"]);
if (sendTelemetry) {
secHistogram.add(nsISecTel[bucketName + "WHY_BLOCKED"]);
}
openHelpLink("phishing-malware", false, "current");
break;
case "ignoreWarningButton":
secHistogram.add(nsISecTel[bucketName + "IGNORE_WARNING"]);
if (sendTelemetry) {
secHistogram.add(nsISecTel[bucketName + "IGNORE_WARNING"]);
}
this.ignoreWarningButton(reason);
break;
}
@ -3054,6 +3065,8 @@ var BrowserOnClick = {
title = gNavigatorBundle.getString("safebrowsing.reportedUnwantedSite");
// There is no button for reporting errors since Google doesn't currently
// provide a URL endpoint for these reports.
} else {
return; // no notifications for forbidden sites
}
let notificationBox = gBrowser.getNotificationBox();

View File

@ -460,6 +460,8 @@ var ClickEventHandler = {
reason = 'malware';
} else if (/e=unwantedBlocked/.test(ownerDoc.documentURI)) {
reason = 'unwanted';
} else if (/e=forbiddenBlocked/.test(ownerDoc.documentURI)) {
reason = 'forbidden';
}
sendAsyncMessage("Browser:SiteBlockedError", {
location: ownerDoc.location.href,

View File

@ -5,7 +5,7 @@
Components.utils.import("resource:///modules/SitePermissions.jsm");
Components.utils.import("resource://gre/modules/BrowserUtils.jsm");
const nsIQuotaManager = Components.interfaces.nsIQuotaManager;
const nsIQuotaManagerService = Components.interfaces.nsIQuotaManagerService;
var gPermURI;
var gUsageRequest;
@ -186,13 +186,15 @@ function initIndexedDBRow()
row.appendChild(extras);
var quotaManager = Components.classes["@mozilla.org/dom/quota/manager;1"]
.getService(nsIQuotaManager);
var quotaManagerService =
Components.classes["@mozilla.org/dom/quota-manager-service;1"]
.getService(nsIQuotaManagerService);
let principal = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
.getService(Components.interfaces.nsIScriptSecurityManager)
.createCodebasePrincipal(gPermURI, {});
gUsageRequest =
quotaManager.getUsageForPrincipal(principal, onIndexedDBUsageCallback);
quotaManagerService.getUsageForPrincipal(principal,
onIndexedDBUsageCallback);
var status = document.getElementById("indexedDBStatus");
var button = document.getElementById("indexedDBClear");
@ -208,8 +210,8 @@ function onIndexedDBClear()
.getService(Components.interfaces.nsIScriptSecurityManager)
.createCodebasePrincipal(gPermURI, {});
Components.classes["@mozilla.org/dom/quota/manager;1"]
.getService(nsIQuotaManager)
Components.classes["@mozilla.org/dom/quota-manager-service;1"]
.getService(nsIQuotaManagerService)
.clearStoragesForPrincipal(principal);
Components.classes["@mozilla.org/serviceworkers/manager;1"]
@ -220,14 +222,14 @@ function onIndexedDBClear()
initIndexedDBRow();
}
function onIndexedDBUsageCallback(principal, usage, fileUsage)
function onIndexedDBUsageCallback(request)
{
let uri = principal.URI;
let uri = request.principal.URI;
if (!uri.equals(gPermURI)) {
throw new Error("Callback received for bad URI: " + uri);
}
if (usage) {
if (request.usage) {
if (!("DownloadUtils" in window)) {
Components.utils.import("resource://gre/modules/DownloadUtils.jsm");
}
@ -237,7 +239,7 @@ function onIndexedDBUsageCallback(principal, usage, fileUsage)
status.value =
gBundle.getFormattedString("indexedDBUsage",
DownloadUtils.convertByteUnits(usage));
DownloadUtils.convertByteUnits(request.usage));
status.removeAttribute("hidden");
button.removeAttribute("hidden");
}

View File

@ -360,6 +360,10 @@ var gTests = [
EventUtils.synthesizeKey("a", { accelKey: true });
EventUtils.synthesizeKey("VK_DELETE", {});
ok(table.hidden, "Search suggestion table hidden");
try {
Services.search.removeEngine(engine);
} catch (ex) { }
});
}
},
@ -369,6 +373,12 @@ var gTests = [
run: function()
{
return Task.spawn(function* () {
// Add a test engine that provides suggestions and switch to it.
let engine = yield promiseNewEngine("searchSuggestionEngine.xml");
let p = promiseContentSearchChange(engine.name);
Services.search.currentEngine = engine;
yield p;
// Start composition and type "x"
let input = gBrowser.contentDocument.getElementById("searchText");
input.focus();

View File

@ -0,0 +1,5 @@
<!DOCTYPE html [
<!ENTITY % passwordManagerDTD SYSTEM "chrome://passwordmgr/locale/passwordManager.dtd">
%passwordManagerDTD;
]>
<window>&savedLogins.title;</window>

View File

@ -25,6 +25,7 @@ support-files =
offlineEvent.html
subtst_contextmenu.html
video.ogg
bug_1182546.xml
[test_bug364677.html]
[test_bug395533.html]
@ -38,3 +39,4 @@ skip-if = e10s
skip-if = buildapp == 'mulet' || e10s # Bug 1066070 - I don't think either popup notifications nor addon install stuff works?
[test_offline_gzip.html]
skip-if = buildapp == 'mulet' || e10s # Bug 1066070 - I don't think either popup notifications nor addon install stuff works?
[test_bug1182546.html]

View File

@ -0,0 +1,35 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1182546
-->
<head>
<title>Bug 1182546 - Test block loading DTD from random page</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<iframe id="testframe" src="bug_1182546.xml"></iframe>
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
// make sure the DTD loader (nsExpatDriver) prevents accessing chrome: from random pages
var childNodes = testframe.contentDocument.documentElement.childNodes;
// make sure '&savedLogins.title;' from bug_1182546.xml does not translate into 'Saved Logins'
// the URL 'chrome://passwordmgr/locale/passwordManager.dtd' should not be accessible from content
var nodeValue = childNodes[0].nodeValue;
isnot(nodeValue, "Saved Logins",
"expatDriver should prevent accessing &savedLogins.title;");
ok(nodeValue.startsWith("XML Parsing Error: undefined entity"),
"expatDriver should not allow accessing chrome:");
});
addLoadEvent(SimpleTest.finish);
</script>
</body>
</html>

View File

@ -28,11 +28,6 @@ add_task(function* () {
// Migrate unencrypted cookies.
yield promiseMigration(migrator, MigrationUtils.resourceTypes.COOKIES, PROFILE);
do_register_cleanup(() => {
ForgetAboutSite.removeDataFromDomain(COOKIE.host);
Assert.equal(Services.cookies.countCookiesFromHost(COOKIE.host), 0,
"There are no cookies after cleanup");
});
Assert.equal(Services.cookies.countCookiesFromHost(COOKIE.host), 1,
"Migrated the expected number of unencrypted cookies");
Assert.equal(Services.cookies.countCookiesFromHost("encryptedcookie.invalid"), 0,
@ -46,4 +41,10 @@ add_task(function* () {
for (let prop of Object.keys(COOKIE)) {
Assert.equal(foundCookie[prop], COOKIE[prop], "Check cookie " + prop);
}
// Cleanup.
ForgetAboutSite.removeDataFromDomain(COOKIE.host);
Assert.equal(Services.cookies.countCookiesFromHost(COOKIE.host), 0,
"There are no cookies after cleanup");
});

View File

@ -1,6 +1,7 @@
[DEFAULT]
support-files = head.js
[browser_forbidden.js]
[browser_bug400731.js]
skip-if = e10s
[browser_bug415846.js]

View File

@ -0,0 +1,40 @@
/* Ensure that pages in the forbidden list are blocked. */
const PREF_FORBIDDEN_ENABLED = "browser.safebrowsing.forbiddenURIs.enabled";
const BENIGN_PAGE = "http://example.com/";
const FORBIDDEN_PAGE = "http://www.itisatrap.org/firefox/forbidden.html";
var tabbrowser = null;
registerCleanupFunction(function() {
tabbrowser = null;
Services.prefs.clearUserPref(PREF_FORBIDDEN_ENABLED);
while (gBrowser.tabs.length > 1) {
gBrowser.removeCurrentTab();
}
});
function testBenignPage(window) {
info("Non-forbidden content must not be blocked");
var getmeout_button = window.document.getElementById("getMeOutButton");
var ignorewarning_button = window.document.getElementById("ignoreWarningButton");
ok(!getmeout_button, "GetMeOut button not present");
ok(!ignorewarning_button, "IgnoreWarning button not present");
}
function testForbiddenPage(window) {
info("Forbidden content must be blocked");
ok(true, "about:blocked was shown");
}
add_task(function* testNormalBrowsing() {
tabbrowser = gBrowser;
let tab = tabbrowser.selectedTab = tabbrowser.addTab();
info("Load a test page that's not forbidden");
yield promiseTabLoadEvent(tab, BENIGN_PAGE, "load");
testBenignPage(tab.ownerDocument.defaultView);
info("Load a test page that is forbidden");
yield promiseTabLoadEvent(tab, FORBIDDEN_PAGE, "AboutBlockedLoaded");
testForbiddenPage(tab.ownerDocument.defaultView);
});

View File

@ -1,5 +1,57 @@
// Force SafeBrowsing to be initialized for the tests
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
"resource://gre/modules/Promise.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Task",
"resource://gre/modules/Task.jsm");
/**
* Waits for a load (or custom) event to finish in a given tab. If provided
* load an uri into the tab.
*
* @param tab
* The tab to load into.
* @param [optional] url
* The url to load, or the current url.
* @param [optional] event
* The load event type to wait for. Defaults to "load".
* @return {Promise} resolved when the event is handled.
* @resolves to the received event
* @rejects if a valid load event is not received within a meaningful interval
*/
function promiseTabLoadEvent(tab, url, eventType="load")
{
let deferred = Promise.defer();
info("Wait tab event: " + eventType);
function handle(event) {
if (event.originalTarget != tab.linkedBrowser.contentDocument ||
event.target.location.href == "about:blank" ||
(url && event.target.location.href != url)) {
info("Skipping spurious '" + eventType + "'' event" +
" for " + event.target.location.href);
return;
}
clearTimeout(timeout);
tab.linkedBrowser.removeEventListener(eventType, handle, true);
info("Tab event received: " + eventType);
deferred.resolve(event);
}
let timeout = setTimeout(() => {
tab.linkedBrowser.removeEventListener(eventType, handle, true);
deferred.reject(new Error("Timed out while waiting for a '" + eventType + "'' event"));
}, 30000);
tab.linkedBrowser.addEventListener(eventType, handle, true, true);
if (url) {
tab.linkedBrowser.loadURI(url);
}
return deferred.promise;
}
Services.prefs.setCharPref("urlclassifier.forbiddenTable", "test-forbid-simple");
Services.prefs.setCharPref("urlclassifier.malwareTable", "test-malware-simple,test-unwanted-simple");
Services.prefs.setCharPref("urlclassifier.phishTable", "test-phish-simple");
Services.prefs.setBoolPref("browser.safebrowsing.forbiddenURIs.enabled", true);
SafeBrowsing.init();

View File

@ -7,5 +7,5 @@
DEFINES['APP_VERSION'] = CONFIG['FIREFOX_VERSION']
DEFINES['MOZ_APP_NAME'] = CONFIG['MOZ_APP_NAME']
DEFINES['MOZ_APP_DISPLAYNAME'] = "'%s'" % CONFIG['MOZ_APP_DISPLAYNAME']
DEFINES['MOZ_APP_DISPLAYNAME'] = CONFIG['MOZ_APP_DISPLAYNAME']
DEFINES['MOZILLA_VERSION'] = CONFIG['MOZILLA_VERSION']

View File

@ -8,16 +8,21 @@
<!ENTITY safeb.palm.reportPage.label "Why was this page blocked?">
<!ENTITY safeb.blocked.malwarePage.title "Reported Attack Page!">
<!-- Localization note (safeb.blocked.malware.shortDesc) - Please don't translate the contents of the <span id="malware_sitename"/> tag. It will be replaced at runtime with a domain name (e.g. www.badsite.com) -->
<!-- Localization note (safeb.blocked.malwarePage.shortDesc) - Please don't translate the contents of the <span id="malware_sitename"/> tag. It will be replaced at runtime with a domain name (e.g. www.badsite.com) -->
<!ENTITY safeb.blocked.malwarePage.shortDesc "This web page at <span id='malware_sitename'/> has been reported as an attack page and has been blocked based on your security preferences.">
<!ENTITY safeb.blocked.malwarePage.longDesc "<p>Attack pages try to install programs that steal private information, use your computer to attack others, or damage your system.</p><p>Some attack pages intentionally distribute harmful software, but many are compromised without the knowledge or permission of their owners.</p>">
<!ENTITY safeb.blocked.unwantedPage.title "Reported Unwanted Software Page!">
<!-- Localization note (safeb.blocked.malware.shortDesc) - Please don't translate the contents of the <span id="unwanted_sitename"/> tag. It will be replaced at runtime with a domain name (e.g. www.badsite.com) -->
<!-- Localization note (safeb.blocked.unwantedPage.shortDesc) - Please don't translate the contents of the <span id="unwanted_sitename"/> tag. It will be replaced at runtime with a domain name (e.g. www.badsite.com) -->
<!ENTITY safeb.blocked.unwantedPage.shortDesc "This web page at <span id='unwanted_sitename'/> has been reported to contain unwanted software and has been blocked based on your security preferences.">
<!ENTITY safeb.blocked.unwantedPage.longDesc "<p>Unwanted software pages try to install software that can be deceptive and affect your system in unexpected ways.</p>">
<!ENTITY safeb.blocked.phishingPage.title "Reported Web Forgery!">
<!-- Localization note (safeb.blocked.phishing.shortDesc) - Please don't translate the contents of the <span id="phishing_sitename"/> tag. It will be replaced at runtime with a domain name (e.g. www.badsite.com) -->
<!-- Localization note (safeb.blocked.phishingPage.shortDesc) - Please don't translate the contents of the <span id="phishing_sitename"/> tag. It will be replaced at runtime with a domain name (e.g. www.badsite.com) -->
<!ENTITY safeb.blocked.phishingPage.shortDesc "This web page at <span id='phishing_sitename'/> has been reported as a web forgery and has been blocked based on your security preferences.">
<!ENTITY safeb.blocked.phishingPage.longDesc "<p>Web forgeries are designed to trick you into revealing personal or financial information by imitating sources you may trust.</p><p>Entering any information on this web page may result in identity theft or other fraud.</p>">
<!ENTITY safeb.blocked.forbiddenPage.title "Forbidden Site">
<!-- Localization note (safeb.blocked.forbiddenPage.shortDesc) - Please don't translate the contents of the <span id="forbidden_sitename"/> tag. It will be replaced at runtime with a domain name (e.g. www.badsite.com) -->
<!ENTITY safeb.blocked.forbiddenPage.shortDesc "This Web page at <span id='forbidden_sitename'/> has been blocked based on your browser configuration.">

View File

@ -32,6 +32,7 @@ externalProtocolLaunchBtn=Launch application
malwareBlocked=The site at %S has been reported as an attack site and has been blocked based on your security preferences.
unwantedBlocked=The site at %S has been reported as serving unwanted software and has been blocked based on your security preferences.
phishingBlocked=The website at %S has been reported as a web forgery designed to trick users into sharing personal or financial information.
forbiddenBlocked=The site at %S has been blocked by your browser configuration.
cspBlocked=This page has a content security policy that prevents it from being loaded in this way.
corruptedContentError=The page you are trying to view cannot be shown because an error in the data transmission was detected.
remoteXUL=This page uses an unsupported technology that is no longer available by default in Firefox.

View File

@ -175,6 +175,10 @@ be temporary, and you can try again later.</li>
<p>These types of web forgeries are used in scams known as phishing attacks, in which fraudulent web pages and emails are used to imitate sources you may trust.</p>
">
<!ENTITY forbiddenBlocked.title "Forbidden Site">
<!ENTITY forbiddenBlocked.longDesc "<p>&brandShortName; prevented this page from loading because it is configured to block it.</p>
">
<!ENTITY cspBlocked.title "Blocked by Content Security Policy">
<!ENTITY cspBlocked.longDesc "<p>&brandShortName; prevented this page from loading in this way because the page has a content security policy that disallows it.</p>">

View File

@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1"
xmlns="http://www.w3.org/2000/svg"

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -4,14 +4,45 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/devtools/DominatorTree.h"
#include "js/Debug.h"
#include "mozilla/CycleCollectedJSRuntime.h"
#include "mozilla/dom/DominatorTreeBinding.h"
namespace mozilla {
namespace devtools {
dom::Nullable<uint64_t>
DominatorTree::GetRetainedSize(uint64_t aNodeId, ErrorResult& aRv)
{
JS::ubi::Node::Id id(aNodeId);
auto node = mHeapSnapshot->getNodeById(id);
if (node.isNothing())
return dom::Nullable<uint64_t>();
auto ccrt = CycleCollectedJSRuntime::Get();
MOZ_ASSERT(ccrt);
auto rt = ccrt->Runtime();
MOZ_ASSERT(rt);
auto mallocSizeOf = JS::dbg::GetDebuggerMallocSizeOf(rt);
MOZ_ASSERT(mallocSizeOf);
JS::ubi::Node::Size size = 0;
if (!mDominatorTree.getRetainedSize(*node, mallocSizeOf, size)) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return dom::Nullable<uint64_t>();
}
MOZ_ASSERT(size != 0,
"The node should not have been unknown since we got it from the heap snapshot.");
return dom::Nullable<uint64_t>(size);
}
/*** Cycle Collection Boilerplate *****************************************************************/
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DominatorTree, mParent)
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DominatorTree, mParent, mHeapSnapshot)
NS_IMPL_CYCLE_COLLECTING_ADDREF(DominatorTree)
NS_IMPL_CYCLE_COLLECTING_RELEASE(DominatorTree)

View File

@ -6,6 +6,7 @@
#ifndef mozilla_devtools_DominatorTree__
#define mozilla_devtools_DominatorTree__
#include "mozilla/devtools/HeapSnapshot.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/RefCounted.h"
@ -25,13 +26,17 @@ protected:
private:
JS::ubi::DominatorTree mDominatorTree;
RefPtr<HeapSnapshot> mHeapSnapshot;
public:
explicit DominatorTree(JS::ubi::DominatorTree&& aDominatorTree, nsISupports* aParent)
explicit DominatorTree(JS::ubi::DominatorTree&& aDominatorTree, HeapSnapshot* aHeapSnapshot,
nsISupports* aParent)
: mParent(aParent)
, mDominatorTree(Move(aDominatorTree))
, mHeapSnapshot(aHeapSnapshot)
{
MOZ_ASSERT(aParent);
MOZ_ASSERT(aHeapSnapshot);
};
NS_DECL_CYCLE_COLLECTING_ISUPPORTS;
@ -42,7 +47,11 @@ public:
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
// readonly attribute NodeId root
uint64_t Root() const { return mDominatorTree.root().identifier(); }
// [Throws] NodeSize getRetainedSize(NodeId node)
dom::Nullable<uint64_t> GetRetainedSize(uint64_t aNodeId, ErrorResult& aRv);
};
} // namespace devtools

View File

@ -11,12 +11,15 @@
#include "js/Debug.h"
#include "js/TypeDecls.h"
#include "js/UbiNodeCensus.h"
#include "js/UbiNodeBreadthFirst.h"
#include "js/UbiNodeCensus.h"
#include "js/UbiNodeDominatorTree.h"
#include "mozilla/Attributes.h"
#include "mozilla/CycleCollectedJSRuntime.h"
#include "mozilla/devtools/AutoMemMap.h"
#include "mozilla/devtools/CoreDump.pb.h"
#include "mozilla/devtools/DeserializedNode.h"
#include "mozilla/devtools/DominatorTree.h"
#include "mozilla/devtools/FileDescriptorOutputStream.h"
#include "mozilla/devtools/HeapSnapshotTempFileHelperChild.h"
#include "mozilla/devtools/ZeroCopyNSIOutputStream.h"
@ -538,7 +541,7 @@ HeapSnapshot::ComputeDominatorTree(ErrorResult& rv)
return nullptr;
}
return MakeAndAddRef<DominatorTree>(Move(*maybeTree), mParent);
return MakeAndAddRef<DominatorTree>(Move(*maybeTree), this, mParent);
}

View File

@ -9,7 +9,6 @@
#include "js/HashTable.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/devtools/DeserializedNode.h"
#include "mozilla/devtools/DominatorTree.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/Nullable.h"
#include "mozilla/HashFunctions.h"
@ -30,6 +29,8 @@
namespace mozilla {
namespace devtools {
class DominatorTree;
struct NSFreePolicy {
void operator()(void* ptr) {
NS_Free(ptr);
@ -148,6 +149,13 @@ public:
return JS::ubi::Node(const_cast<DeserializedNode*>(&node));
}
Maybe<JS::ubi::Node> getNodeById(JS::ubi::Node::Id nodeId) {
auto p = nodes.lookup(nodeId);
if (!p)
return Nothing();
return Some(JS::ubi::Node(const_cast<DeserializedNode*>(&*p)));
}
void TakeCensus(JSContext* cx, JS::HandleObject options,
JS::MutableHandleValue rval, ErrorResult& rv);

View File

@ -79,8 +79,8 @@ ZeroCopyNSIOutputStream::Next(void** data, int* size)
void
ZeroCopyNSIOutputStream::BackUp(int count)
{
MOZ_ASSERT(count > 0,
"Must back up a positive number of bytes.");
MOZ_ASSERT(count >= 0,
"Cannot back up a negative amount of bytes.");
MOZ_ASSERT(amountUsed == BUFFER_SIZE,
"Can only call BackUp directly after calling Next.");
MOZ_ASSERT(count <= amountUsed,

View File

@ -0,0 +1,22 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Test that we can get the retained sizes of dominator trees.
function run_test() {
const dominatorTree = saveHeapSnapshotAndComputeDominatorTree();
equal(typeof dominatorTree.getRetainedSize, "function",
"getRetainedSize should be a function");
const size = dominatorTree.getRetainedSize(dominatorTree.root);
ok(size, "should get a size for the root");
equal(typeof size, "number", "retained sizes should be a number");
equal(Math.floor(size), size, "size should be an integer");
ok(size > 0, "size should be positive");
ok(size <= Math.pow(2, 64), "size should be less than or equal to 2^64");
const bad = dominatorTree.getRetainedSize(1);
equal(bad, null, "null is returned for unknown node ids");
do_test_finished();
}

View File

@ -31,6 +31,7 @@ support-files =
[test_DominatorTree_01.js]
[test_DominatorTree_02.js]
[test_DominatorTree_03.js]
[test_DominatorTree_04.js]
[test_HeapAnalyses_getCreationTime_01.js]
[test_HeapAnalyses_readHeapSnapshot_01.js]
[test_HeapAnalyses_takeCensusDiff_01.js]

View File

@ -4909,7 +4909,8 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI,
}
} else if (NS_ERROR_PHISHING_URI == aError ||
NS_ERROR_MALWARE_URI == aError ||
NS_ERROR_UNWANTED_URI == aError) {
NS_ERROR_UNWANTED_URI == aError ||
NS_ERROR_FORBIDDEN_URI == aError) {
nsAutoCString host;
aURI->GetHost(host);
CopyUTF8toUTF16(host, formatStrs[0]);
@ -4924,21 +4925,27 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI,
}
uint32_t bucketId;
bool sendTelemetry = false;
if (NS_ERROR_PHISHING_URI == aError) {
sendTelemetry = true;
error.AssignLiteral("phishingBlocked");
bucketId = IsFrame() ? nsISecurityUITelemetry::WARNING_PHISHING_PAGE_FRAME
: nsISecurityUITelemetry::WARNING_PHISHING_PAGE_TOP;
} else if (NS_ERROR_MALWARE_URI == aError) {
sendTelemetry = true;
error.AssignLiteral("malwareBlocked");
bucketId = IsFrame() ? nsISecurityUITelemetry::WARNING_MALWARE_PAGE_FRAME
: nsISecurityUITelemetry::WARNING_MALWARE_PAGE_TOP;
} else {
} else if (NS_ERROR_UNWANTED_URI == aError) {
sendTelemetry = true;
error.AssignLiteral("unwantedBlocked");
bucketId = IsFrame() ? nsISecurityUITelemetry::WARNING_UNWANTED_PAGE_FRAME
: nsISecurityUITelemetry::WARNING_UNWANTED_PAGE_TOP;
} else if (NS_ERROR_FORBIDDEN_URI == aError) {
error.AssignLiteral("forbiddenBlocked");
}
if (errorPage.EqualsIgnoreCase("blocked")) {
if (sendTelemetry && errorPage.EqualsIgnoreCase("blocked")) {
Telemetry::Accumulate(Telemetry::SECURITY_UI, bucketId);
}
@ -7699,6 +7706,7 @@ nsDocShell::EndPageLoad(nsIWebProgress* aProgress,
aStatus == NS_ERROR_MALWARE_URI ||
aStatus == NS_ERROR_PHISHING_URI ||
aStatus == NS_ERROR_UNWANTED_URI ||
aStatus == NS_ERROR_FORBIDDEN_URI ||
aStatus == NS_ERROR_UNSAFE_CONTENT_TYPE ||
aStatus == NS_ERROR_REMOTE_XUL ||
aStatus == NS_ERROR_INTERCEPTION_FAILED ||

View File

@ -295,6 +295,7 @@
<h1 id="et_nssBadCert">&nssBadCert.title;</h1>
<h1 id="et_malwareBlocked">&malwareBlocked.title;</h1>
<h1 id="et_unwantedBlocked">&unwantedBlocked.title;</h1>
<h1 id="et_forbiddenBlocked">&forbiddenBlocked.title;</h1>
<h1 id="et_cspBlocked">&cspBlocked.title;</h1>
<h1 id="et_remoteXUL">&remoteXUL.title;</h1>
<h1 id="et_corruptedContentError">&corruptedContentError.title;</h1>
@ -322,6 +323,7 @@
<div id="ed_nssBadCert">&nssBadCert.longDesc2;</div>
<div id="ed_malwareBlocked">&malwareBlocked.longDesc;</div>
<div id="ed_unwantedBlocked">&unwantedBlocked.longDesc;</div>
<div id="ed_forbiddenBlocked">&forbiddenBlocked.longDesc;</div>
<div id="ed_cspBlocked">&cspBlocked.longDesc;</div>
<div id="ed_remoteXUL">&remoteXUL.longDesc;</div>
<div id="ed_corruptedContentError">&corruptedContentError.longDesc;</div>

View File

@ -37,7 +37,7 @@ ArchiveReader::Constructor(const GlobalObject& aGlobal,
nsAutoCString encoding;
if (!EncodingUtils::FindEncodingForLabelNoReplacement(aOptions.mEncoding,
encoding)) {
aError.ThrowRangeError<MSG_ENCODING_NOT_SUPPORTED>(&aOptions.mEncoding);
aError.ThrowRangeError<MSG_ENCODING_NOT_SUPPORTED>(aOptions.mEncoding);
return nullptr;
}

View File

@ -329,35 +329,6 @@ protected:
void* mMappedMemory;
};
class UnlockDirectoryRunnable final
: public nsRunnable
{
RefPtr<DirectoryLock> mDirectoryLock;
public:
explicit
UnlockDirectoryRunnable(already_AddRefed<DirectoryLock> aDirectoryLock)
: mDirectoryLock(Move(aDirectoryLock))
{ }
private:
~UnlockDirectoryRunnable()
{
MOZ_ASSERT(!mDirectoryLock);
}
NS_IMETHOD
Run() override
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mDirectoryLock);
mDirectoryLock = nullptr;
return NS_OK;
}
};
// A runnable that implements a state machine required to open a cache entry.
// It executes in the parent for a cache access originating in the child.
// This runnable gets registered as an IPDL subprotocol actor so that it
@ -503,6 +474,9 @@ private:
nsresult
InitOnMainThread();
void
OpenDirectory();
nsresult
ReadMetadata();
@ -518,7 +492,7 @@ private:
void
DispatchToIOThread()
{
MOZ_ASSERT(NS_IsMainThread());
AssertIsOnOwningThread();
// If shutdown just started, the QuotaManager may have been deleted.
QuotaManager* qm = QuotaManager::Get();
@ -593,8 +567,8 @@ private:
// A cache entry has been selected to open.
mModuleIndex = aModuleIndex;
mState = eDispatchToMainThread;
NS_DispatchToMainThread(this);
mState = eReadyToOpenCacheFileForRead;
DispatchToIOThread();
return true;
}
@ -630,12 +604,13 @@ private:
enum State {
eInitial, // Just created, waiting to be dispatched to main thread
eWaitingToFinishInit, // Waiting to finish initialization
eWaitingToOpenDirectory, // Waiting to open directory
eWaitingToOpenMetadata, // Waiting to be called back from OpenDirectory
eReadyToReadMetadata, // Waiting to read the metadata file on the IO thread
eFailedToReadMetadata, // Waiting to be dispatched to owning thread after fail
eSendingMetadataForRead, // Waiting to send OnOpenMetadataForRead
eWaitingToOpenCacheFileForRead, // Waiting to hear back from child
eDispatchToMainThread, // IO thread dispatch allowed from main thread only
eReadyToOpenCacheFileForRead, // Waiting to open cache file for read
eSendingCacheFile, // Waiting to send OnOpenCacheFile on the owning thread
eOpened, // Finished calling OnOpenCacheFile, waiting to be closed
@ -711,9 +686,6 @@ ParentRunnable::InitOnMainThread()
return rv;
}
QuotaManager* qm = QuotaManager::GetOrCreate();
NS_ENSURE_STATE(qm);
rv = QuotaManager::GetInfoFromPrincipal(principal, &mGroup, &mOrigin,
&mIsApp);
NS_ENSURE_SUCCESS(rv, rv);
@ -726,6 +698,26 @@ ParentRunnable::InitOnMainThread()
return NS_OK;
}
void
ParentRunnable::OpenDirectory()
{
AssertIsOnOwningThread();
MOZ_ASSERT(mState == eWaitingToFinishInit ||
mState == eWaitingToOpenDirectory);
MOZ_ASSERT(QuotaManager::Get());
mState = eWaitingToOpenMetadata;
// XXX The exclusive lock shouldn't be needed for read operations.
QuotaManager::Get()->OpenDirectory(mPersistence,
mGroup,
mOrigin,
mIsApp,
quota::Client::ASMJS,
/* aExclusive */ true,
this);
}
nsresult
ParentRunnable::ReadMetadata()
{
@ -903,12 +895,7 @@ ParentRunnable::FinishOnOwningThread()
// releasing the directory lock.
FileDescriptorHolder::Finish();
if (mDirectoryLock) {
RefPtr<UnlockDirectoryRunnable> runnable =
new UnlockDirectoryRunnable(mDirectoryLock.forget());
NS_DispatchToMainThread(runnable);
}
mDirectoryLock = nullptr;
}
NS_IMETHODIMP
@ -928,17 +915,41 @@ ParentRunnable::Run()
return NS_OK;
}
mState = eWaitingToOpenMetadata;
mState = eWaitingToFinishInit;
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
mOwningThread->Dispatch(this, NS_DISPATCH_NORMAL)));
// XXX The exclusive lock shouldn't be needed for read operations.
QuotaManager::Get()->OpenDirectory(mPersistence,
mGroup,
mOrigin,
mIsApp,
quota::Client::ASMJS,
/* aExclusive */ true,
this);
return NS_OK;
}
case eWaitingToFinishInit: {
AssertIsOnOwningThread();
if (QuotaManager::IsShuttingDown()) {
Fail();
return NS_OK;
}
if (QuotaManager::Get()) {
OpenDirectory();
return NS_OK;
}
mState = eWaitingToOpenDirectory;
QuotaManager::GetOrCreate(this);
return NS_OK;
}
case eWaitingToOpenDirectory: {
AssertIsOnOwningThread();
if (NS_WARN_IF(!QuotaManager::Get())) {
Fail();
return NS_OK;
}
OpenDirectory();
return NS_OK;
}
@ -999,14 +1010,6 @@ ParentRunnable::Run()
return NS_OK;
}
case eDispatchToMainThread: {
MOZ_ASSERT(NS_IsMainThread());
mState = eReadyToOpenCacheFileForRead;
DispatchToIOThread();
return NS_OK;
}
case eReadyToOpenCacheFileForRead: {
AssertIsOnIOThread();
MOZ_ASSERT(mOpenMode == eOpenForRead);
@ -1064,7 +1067,7 @@ ParentRunnable::Run()
void
ParentRunnable::DirectoryLockAcquired(DirectoryLock* aLock)
{
MOZ_ASSERT(NS_IsMainThread());
AssertIsOnOwningThread();
MOZ_ASSERT(mState == eWaitingToOpenMetadata);
MOZ_ASSERT(!mDirectoryLock);
@ -1077,11 +1080,11 @@ ParentRunnable::DirectoryLockAcquired(DirectoryLock* aLock)
void
ParentRunnable::DirectoryLockFailed()
{
MOZ_ASSERT(NS_IsMainThread());
AssertIsOnOwningThread();
MOZ_ASSERT(mState == eWaitingToOpenMetadata);
MOZ_ASSERT(!mDirectoryLock);
FailOnNonOwningThread();
Fail();
}
NS_IMPL_ISUPPORTS_INHERITED0(ParentRunnable, FileDescriptorHolder)
@ -1812,7 +1815,11 @@ public:
{ }
virtual void
PerformIdleMaintenance() override
StartIdleMaintenance() override
{ }
virtual void
StopIdleMaintenance() override
{ }
virtual void

View File

@ -305,14 +305,13 @@ AutoJSAPI::AutoJSAPI()
: mCx(nullptr)
, mOwnErrorReporting(false)
, mOldAutoJSAPIOwnsErrorReporting(false)
, mIsMainThread(false) // For lack of anything better
{
}
AutoJSAPI::~AutoJSAPI()
{
if (mOwnErrorReporting) {
MOZ_ASSERT(NS_IsMainThread(), "See corresponding assertion in TakeOwnershipOfErrorReporting()");
ReportException();
// We need to do this _after_ processing the existing exception, because the
@ -332,7 +331,10 @@ void
AutoJSAPI::InitInternal(JSObject* aGlobal, JSContext* aCx, bool aIsMainThread)
{
MOZ_ASSERT(aCx);
MOZ_ASSERT(aIsMainThread == NS_IsMainThread());
mCx = aCx;
mIsMainThread = aIsMainThread;
if (aIsMainThread) {
// This Rooted<> is necessary only as long as AutoCxPusher::AutoCxPusher
// can GC, which is only possible because XPCJSContextStack::Push calls
@ -357,11 +359,12 @@ AutoJSAPI::AutoJSAPI(nsIGlobalObject* aGlobalObject,
JSContext* aCx)
: mOwnErrorReporting(false)
, mOldAutoJSAPIOwnsErrorReporting(false)
, mIsMainThread(aIsMainThread)
{
MOZ_ASSERT(aGlobalObject);
MOZ_ASSERT(aGlobalObject->GetGlobalJSObject(), "Must have a JS global");
MOZ_ASSERT(aCx);
MOZ_ASSERT_IF(aIsMainThread, NS_IsMainThread());
MOZ_ASSERT(aIsMainThread == NS_IsMainThread());
InitInternal(aGlobalObject->GetGlobalJSObject(), aCx, aIsMainThread);
}
@ -460,7 +463,9 @@ AutoJSAPI::InitWithLegacyErrorReporting(nsGlobalWindow* aWindow)
void
WarningOnlyErrorReporter(JSContext* aCx, const char* aMessage, JSErrorReport* aRep)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(JSREPORT_IS_WARNING(aRep->flags));
RefPtr<xpc::ErrorReport> xpcReport = new xpc::ErrorReport();
nsPIDOMWindow* win = xpc::CurrentWindowOrNull(aCx);
xpcReport->Init(aRep, aMessage, nsContentUtils::IsCallerChrome(),
@ -471,14 +476,19 @@ WarningOnlyErrorReporter(JSContext* aCx, const char* aMessage, JSErrorReport* aR
void
AutoJSAPI::TakeOwnershipOfErrorReporting()
{
MOZ_ASSERT(NS_IsMainThread(), "Can't own error reporting off-main-thread yet");
MOZ_ASSERT(!mOwnErrorReporting);
mOwnErrorReporting = true;
JSRuntime *rt = JS_GetRuntime(cx());
mOldAutoJSAPIOwnsErrorReporting = JS::ContextOptionsRef(cx()).autoJSAPIOwnsErrorReporting();
JS::ContextOptionsRef(cx()).setAutoJSAPIOwnsErrorReporting(true);
JS_SetErrorReporter(rt, WarningOnlyErrorReporter);
// Workers have their own error reporting mechanism which deals with warnings
// as well, so don't change the worker error reporter for now. Once we switch
// all of workers to TakeOwnershipOfErrorReporting(), we will just make the
// default worker error reporter assert that it only sees warnings.
if (mIsMainThread) {
JS_SetErrorReporter(rt, WarningOnlyErrorReporter);
}
}
void
@ -498,18 +508,35 @@ AutoJSAPI::ReportException()
if (!errorGlobal)
errorGlobal = xpc::PrivilegedJunkScope();
JSAutoCompartment ac(cx(), errorGlobal);
nsCOMPtr<nsPIDOMWindow> win = xpc::WindowGlobalOrNull(errorGlobal);
JS::Rooted<JS::Value> exn(cx());
js::ErrorReport jsReport(cx());
if (StealException(&exn) && jsReport.init(cx(), exn)) {
RefPtr<xpc::ErrorReport> xpcReport = new xpc::ErrorReport();
xpcReport->Init(jsReport.report(), jsReport.message(),
nsContentUtils::IsCallerChrome(),
win ? win->WindowID() : 0);
if (win) {
DispatchScriptErrorEvent(win, JS_GetRuntime(cx()), xpcReport, exn);
if (mIsMainThread) {
RefPtr<xpc::ErrorReport> xpcReport = new xpc::ErrorReport();
nsCOMPtr<nsPIDOMWindow> win = xpc::WindowGlobalOrNull(errorGlobal);
xpcReport->Init(jsReport.report(), jsReport.message(),
nsContentUtils::IsCallerChrome(),
win ? win->WindowID() : 0);
if (win) {
DispatchScriptErrorEvent(win, JS_GetRuntime(cx()), xpcReport, exn);
} else {
xpcReport->LogToConsole();
}
} else {
xpcReport->LogToConsole();
// On a worker, we just use the worker error reporting mechanism and don't
// bother with xpc::ErrorReport. This will ensure that all the right
// events (which are a lot more complicated than in the window case) get
// fired.
workers::WorkerPrivate* worker = workers::GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(worker);
MOZ_ASSERT(worker->GetJSContext() == cx());
// Before invoking ReportError, put the exception back on the context,
// because it may want to put it in its error events and has no other way
// to get hold of it. After we invoke ReportError, clear the exception on
// cx(), just in case ReportError didn't.
JS_SetPendingException(cx(), exn);
worker->ReportError(cx(), jsReport.message(), jsReport.report());
ClearException();
}
} else {
NS_WARNING("OOMed while acquiring uncaught exception from JSAPI");
@ -519,7 +546,7 @@ AutoJSAPI::ReportException()
bool
AutoJSAPI::StealException(JS::MutableHandle<JS::Value> aVal)
{
MOZ_ASSERT(CxPusherIsStackTop());
MOZ_ASSERT_IF(mIsMainThread, CxPusherIsStackTop());
MOZ_ASSERT(HasException());
MOZ_ASSERT(js::GetContextCompartment(cx()));
if (!JS_GetPendingException(cx(), aVal)) {

View File

@ -262,7 +262,7 @@ public:
JSContext* cx() const {
MOZ_ASSERT(mCx, "Must call Init before using an AutoJSAPI");
MOZ_ASSERT_IF(NS_IsMainThread(), CxPusherIsStackTop());
MOZ_ASSERT_IF(mIsMainThread, CxPusherIsStackTop());
return mCx;
}
@ -279,7 +279,7 @@ public:
void ReportException();
bool HasException() const {
MOZ_ASSERT(CxPusherIsStackTop());
MOZ_ASSERT_IF(NS_IsMainThread(), CxPusherIsStackTop());
return JS_IsExceptionPending(cx());
};
@ -292,7 +292,7 @@ public:
bool StealException(JS::MutableHandle<JS::Value> aVal);
void ClearException() {
MOZ_ASSERT(CxPusherIsStackTop());
MOZ_ASSERT_IF(NS_IsMainThread(), CxPusherIsStackTop());
JS_ClearPendingException(cx());
}
@ -312,6 +312,8 @@ private:
// Track state between the old and new error reporting modes.
bool mOwnErrorReporting;
bool mOldAutoJSAPIOwnsErrorReporting;
// Whether we're mainthread or not; set when we're initialized.
bool mIsMainThread;
Maybe<JSErrorReporter> mOldErrorReporter;
void InitInternal(JSObject* aGlobal, JSContext* aCx, bool aIsMainThread);

View File

@ -78,7 +78,7 @@ URL::Constructor(nsISupports* aParent, const nsAString& aUrl,
nsresult rv = NS_NewURI(getter_AddRefs(baseUri), aBase, nullptr, nullptr,
nsContentUtils::GetIOService());
if (NS_WARN_IF(NS_FAILED(rv))) {
aRv.ThrowTypeError<MSG_INVALID_URL>(&aBase);
aRv.ThrowTypeError<MSG_INVALID_URL>(aBase);
return nullptr;
}
@ -94,7 +94,7 @@ URL::Constructor(nsISupports* aParent, const nsAString& aUrl, nsIURI* aBase,
nsresult rv = NS_NewURI(getter_AddRefs(uri), aUrl, nullptr, aBase,
nsContentUtils::GetIOService());
if (NS_WARN_IF(NS_FAILED(rv))) {
aRv.ThrowTypeError<MSG_INVALID_URL>(&aUrl);
aRv.ThrowTypeError<MSG_INVALID_URL>(aUrl);
return nullptr;
}
@ -229,8 +229,7 @@ URL::SetHref(const nsAString& aHref, ErrorResult& aRv)
nsCOMPtr<nsIURI> uri;
rv = ioService->NewURI(href, nullptr, nullptr, getter_AddRefs(uri));
if (NS_FAILED(rv)) {
nsAutoString label(aHref);
aRv.ThrowTypeError<MSG_INVALID_URL>(&label);
aRv.ThrowTypeError<MSG_INVALID_URL>(aHref);
return;
}

View File

@ -158,7 +158,7 @@ WindowNamedPropertiesHandler::defineProperty(JSContext* aCx,
{
ErrorResult rv;
rv.ThrowTypeError<MSG_DEFINEPROPERTY_ON_GSP>();
rv.ReportErrorWithMessage(aCx);
rv.MaybeSetPendingException(aCx);
return false;
}

View File

@ -5115,19 +5115,17 @@ nsDocument::DocumentStatesChanged(EventStates aStateMask)
void
nsDocument::StyleRuleChanged(CSSStyleSheet* aSheet,
css::Rule* aOldStyleRule,
css::Rule* aNewStyleRule)
css::Rule* aStyleRule)
{
NS_DOCUMENT_NOTIFY_OBSERVERS(StyleRuleChanged,
(this, aSheet,
aOldStyleRule, aNewStyleRule));
aStyleRule));
if (StyleSheetChangeEventsEnabled()) {
DO_STYLESHEET_NOTIFICATION(StyleRuleChangeEvent,
"StyleRuleChanged",
mRule,
aNewStyleRule ? aNewStyleRule->GetDOMRule()
: nullptr);
aStyleRule ? aStyleRule->GetDOMRule() : nullptr);
}
}

View File

@ -884,8 +884,7 @@ public:
mozilla::EventStates aStateMask) override;
virtual void StyleRuleChanged(mozilla::CSSStyleSheet* aStyleSheet,
mozilla::css::Rule* aOldStyleRule,
mozilla::css::Rule* aNewStyleRule) override;
mozilla::css::Rule* aStyleRule) override;
virtual void StyleRuleAdded(mozilla::CSSStyleSheet* aStyleSheet,
mozilla::css::Rule* aStyleRule) override;
virtual void StyleRuleRemoved(mozilla::CSSStyleSheet* aStyleSheet,

View File

@ -6138,10 +6138,12 @@ nsGlobalWindow::FinishFullscreenChange(bool aIsFullscreen)
mWakeLock = pmService->NewWakeLock(NS_LITERAL_STRING("DOM_Fullscreen"),
this, rv);
NS_WARN_IF_FALSE(!rv.Failed(), "Failed to lock the wakelock");
rv.SuppressException();
} else if (mWakeLock && !mFullScreen) {
ErrorResult rv;
mWakeLock->Unlock(rv);
mWakeLock = nullptr;
rv.SuppressException();
}
}
@ -11764,6 +11766,7 @@ nsGlobalWindow::RunTimeoutHandler(nsTimeout* aTimeout,
ErrorResult ignored;
JS::Rooted<JS::Value> ignoredVal(CycleCollectedJSRuntime::Get()->Runtime());
callback->Call(me, handler->GetArgs(), &ignoredVal, ignored, reason);
ignored.SuppressException();
}
// We ignore any failures from calling EvaluateString() on the context or

View File

@ -1131,7 +1131,10 @@ public:
{
MOZ_ASSERT(IsOuterWindow());
mozilla::ErrorResult ignored;
return GetContentInternal(ignored, /* aUnprivilegedCaller = */ false);
nsCOMPtr<nsIDOMWindow> win =
GetContentInternal(ignored, /* aUnprivilegedCaller = */ false);
ignored.SuppressException();
return win.forget();
}
void Get_content(JSContext* aCx,

View File

@ -49,19 +49,19 @@ public:
const nsTArray<nsString>& aStringParams) = 0;
// A version of AddConsoleReport() that accepts the message parameters
// as variable nsString arguments. Note, the parameters must be exactly
// nsString and not another string class. All other args the same as
// AddConsoleReport().
// as variable nsString arguments (or really, any sort of const nsAString).
// All other args the same as AddConsoleReport().
template<typename... Params>
void
AddConsoleReport(uint32_t aErrorFlags, const nsACString& aCategory,
nsContentUtils::PropertiesFile aPropertiesFile,
const nsACString& aSourceFileURI, uint32_t aLineNumber,
uint32_t aColumnNumber, const nsACString& aMessageName,
Params... aParams)
Params&&... aParams)
{
nsTArray<nsString> params;
mozilla::dom::StringArrayAppender::Append(params, sizeof...(Params), aParams...);
mozilla::dom::StringArrayAppender::Append(params, sizeof...(Params),
mozilla::Forward<Params>(aParams)...);
AddConsoleReport(aErrorFlags, aCategory, aPropertiesFile, aSourceFileURI,
aLineNumber, aColumnNumber, aMessageName, params);
}

View File

@ -155,8 +155,8 @@ typedef CallbackObjectHolder<NodeFilter, nsIDOMNodeFilter> NodeFilterHolder;
} // namespace mozilla
#define NS_IDOCUMENT_IID \
{ 0xecc9e376, 0x6c31, 0x4f04, \
{ 0xbe, 0xde, 0xd6, 0x27, 0x61, 0xd7, 0x00, 0x84 } }
{ 0x13011a82, 0x46cd, 0x4c33, \
{ 0x9d, 0x4e, 0x31, 0x41, 0xbb, 0x3f, 0x18, 0xe9 } }
// Enum for requesting a particular type of document when creating a doc
enum DocumentFlavor {
@ -1290,8 +1290,7 @@ public:
// Observation hooks for style data to propagate notifications
// to document observers
virtual void StyleRuleChanged(mozilla::CSSStyleSheet* aStyleSheet,
mozilla::css::Rule* aOldStyleRule,
mozilla::css::Rule* aNewStyleRule) = 0;
mozilla::css::Rule* aStyleRule) = 0;
virtual void StyleRuleAdded(mozilla::CSSStyleSheet* aStyleSheet,
mozilla::css::Rule* aStyleRule) = 0;
virtual void StyleRuleRemoved(mozilla::CSSStyleSheet* aStyleSheet,

View File

@ -21,8 +21,8 @@ class Rule;
} // namespace mozilla
#define NS_IDOCUMENT_OBSERVER_IID \
{ 0x21c8ad67, 0x3a7d, 0x4881, \
{ 0xa5, 0x43, 0xcb, 0xa9, 0xbb, 0xe4, 0x9e, 0x39 } }
{ 0x71041fa3, 0x6dd7, 0x4cde, \
{ 0xbb, 0x76, 0xae, 0xcc, 0x69, 0xe1, 0x75, 0x78 } }
typedef uint32_t nsUpdateType;
@ -143,26 +143,13 @@ public:
* the document. The notification is passed on to all of
* the document observers.
*
* Since nsIStyleRule objects are immutable, there is a new object
* replacing the old one. However, the use of this method (rather
* than StyleRuleAdded and StyleRuleRemoved) implies that the new rule
* matches the same elements and has the same priority (weight,
* origin, specificity) as the old one. (However, if it is a CSS
* style rule, there may be a change in whether it has an important
* rule.)
*
* @param aDocument The document being observed
* @param aStyleSheet the StyleSheet that contians the rule
* @param aOldStyleRule The rule being removed. This rule may not be
* fully valid anymore -- however, it can still
* be used for pointer comparison and
* |QueryInterface|.
* @param aNewStyleRule The rule being added.
* @param aStyleRule The rule being changed.
*/
virtual void StyleRuleChanged(nsIDocument *aDocument,
mozilla::CSSStyleSheet* aStyleSheet,
mozilla::css::Rule* aOldStyleRule,
mozilla::css::Rule* aNewStyleRule) = 0;
mozilla::css::Rule* aStyleRule) = 0;
/**
* A StyleRule has just been added to a style sheet.
@ -238,8 +225,7 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsIDocumentObserver, NS_IDOCUMENT_OBSERVER_IID)
#define NS_DECL_NSIDOCUMENTOBSERVER_STYLERULECHANGED \
virtual void StyleRuleChanged(nsIDocument* aDocument, \
mozilla::CSSStyleSheet* aStyleSheet, \
mozilla::css::Rule* aOldStyleRule, \
mozilla::css::Rule* aNewStyleRule) override;
mozilla::css::Rule* aStyleRule) override;
#define NS_DECL_NSIDOCUMENTOBSERVER_STYLERULEADDED \
virtual void StyleRuleAdded(nsIDocument* aDocument, \
@ -327,8 +313,7 @@ _class::StyleSheetApplicableStateChanged(nsIDocument* aDocument, \
void \
_class::StyleRuleChanged(nsIDocument* aDocument, \
mozilla::CSSStyleSheet* aStyleSheet, \
mozilla::css::Rule* aOldStyleRule, \
mozilla::css::Rule* aNewStyleRule) \
mozilla::css::Rule* aStyleRule) \
{ \
} \
void \

View File

@ -272,6 +272,8 @@ skip-if = buildapp == 'b2g' # Requires webgl support
[test_audioWindowUtils.html]
[test_audioNotification.html]
skip-if = buildapp == 'mulet'
[test_audioNotificationStream.html]
skip-if = buildapp == 'mulet'
[test_audioNotificationStopOnNavigation.html]
skip-if = buildapp == 'mulet'
[test_audioNotificationWithEarlyPlay.html]

View File

@ -0,0 +1,71 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for audio controller in windows</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<pre id="test">
</pre>
<script type="application/javascript">
SimpleTest.waitForExplicitFinish();
var expectedNotification = null;
var observer = {
observe: function(subject, topic, data) {
is(topic, "audio-playback", "audio-playback received");
is(data, expectedNotification, "This is the right notification");
runTest();
}
};
var observerService = SpecialPowers.Cc["@mozilla.org/observer-service;1"]
.getService(SpecialPowers.Ci.nsIObserverService);
var audio = new Audio();
audio.srcObject = (new AudioContext()).createMediaStreamDestination().stream;
var tests = [
function() {
observerService.addObserver(observer, "audio-playback", false);
ok(true, "Observer set");
runTest();
},
function() {
expectedNotification = 'active';
audio.play();
},
function() {
expectedNotification = 'inactive';
audio.pause();
},
function() {
observerService.removeObserver(observer, "audio-playback");
ok(true, "Observer removed");
runTest();
}
];
function runTest() {
if (!tests.length) {
SimpleTest.finish();
return;
}
var test = tests.shift();
test();
}
runTest();
</script>
</body>
</html>

View File

@ -139,23 +139,10 @@ public:
}
// Return InternalType here so we can work with it usefully.
InternalType& Construct()
template<typename... Args>
InternalType& Construct(Args&&... aArgs)
{
mImpl.emplace();
return *mImpl;
}
template <class T1>
InternalType& Construct(const T1 &t1)
{
mImpl.emplace(t1);
return *mImpl;
}
template <class T1, class T2>
InternalType& Construct(const T1 &t1, const T2 &t2)
{
mImpl.emplace(t1, t2);
mImpl.emplace(Forward<Args>(aArgs)...);
return *mImpl;
}

View File

@ -125,38 +125,6 @@ ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs,
NamesOfInterfacesWithProtos(aProtoId));
}
bool
ThrowMethodFailed(JSContext* cx, ErrorResult& rv)
{
if (rv.IsUncatchableException()) {
// Nuke any existing exception on aCx, to make sure we're uncatchable.
JS_ClearPendingException(cx);
// Don't do any reporting. Just return false, to create an
// uncatchable exception.
return false;
}
if (rv.IsJSContextException()) {
// Whatever we need to throw is on the JSContext already. We
// can't assert that there is a pending exception on it, though,
// because in the uncatchable exception case there won't be one.
return false;
}
if (rv.IsErrorWithMessage()) {
rv.ReportErrorWithMessage(cx);
return false;
}
if (rv.IsJSException()) {
rv.ReportJSException(cx);
return false;
}
if (rv.IsDOMException()) {
rv.ReportDOMException(cx);
return false;
}
rv.ReportGenericError(cx);
return false;
}
bool
ThrowNoSetterArg(JSContext* aCx, prototypes::ID aProtoId)
{
@ -222,9 +190,9 @@ ErrorResult::DeserializeMessage(const IPC::Message* aMsg, void** aIter)
}
void
ErrorResult::ReportErrorWithMessage(JSContext* aCx)
ErrorResult::SetPendingExceptionWithMessage(JSContext* aCx)
{
MOZ_ASSERT(mMessage, "ReportErrorWithMessage() can be called only once");
MOZ_ASSERT(mMessage, "SetPendingExceptionWithMessage() can be called only once");
MOZ_ASSERT(mUnionState == HasMessage);
Message* message = mMessage;
@ -241,6 +209,7 @@ ErrorResult::ReportErrorWithMessage(JSContext* aCx)
argCount > 0 ? args : nullptr);
ClearMessage();
mResult = NS_OK;
}
void
@ -280,7 +249,7 @@ ErrorResult::ThrowJSException(JSContext* cx, JS::Handle<JS::Value> exn)
}
void
ErrorResult::ReportJSException(JSContext* cx)
ErrorResult::SetPendingJSException(JSContext* cx)
{
MOZ_ASSERT(!mMightHaveUnreportedJSException,
"Why didn't you tell us you planned to handle JS exceptions?");
@ -295,25 +264,6 @@ ErrorResult::ReportJSException(JSContext* cx)
// what, go ahead and unroot mJSException.
js::RemoveRawValueRoot(cx, &mJSException);
// We no longer have a useful exception but we do want to signal that an error
// occured.
mResult = NS_ERROR_FAILURE;
#ifdef DEBUG
mUnionState = HasNothing;
#endif // DEBUG
}
void
ErrorResult::StealJSException(JSContext* cx,
JS::MutableHandle<JS::Value> value)
{
MOZ_ASSERT(!mMightHaveUnreportedJSException,
"Must call WouldReportJSException unconditionally in all codepaths that might call StealJSException");
MOZ_ASSERT(IsJSException(), "No exception to steal");
MOZ_ASSERT(mUnionState == HasJSException);
value.set(mJSException);
js::RemoveRawValueRoot(cx, &mJSException);
mResult = NS_OK;
#ifdef DEBUG
mUnionState = HasNothing;
@ -373,14 +323,16 @@ ErrorResult::ThrowDOMException(nsresult rv, const nsACString& message)
}
void
ErrorResult::ReportDOMException(JSContext* cx)
ErrorResult::SetPendingDOMException(JSContext* cx)
{
MOZ_ASSERT(mDOMExceptionInfo, "ReportDOMException() can be called only once");
MOZ_ASSERT(mDOMExceptionInfo,
"SetPendingDOMException() can be called only once");
MOZ_ASSERT(mUnionState == HasDOMExceptionInfo);
dom::Throw(cx, mDOMExceptionInfo->mRv, mDOMExceptionInfo->mMessage);
ClearDOMExceptionInfo();
mResult = NS_OK;
}
void
@ -414,12 +366,13 @@ ErrorResult::ClearUnionData()
}
void
ErrorResult::ReportGenericError(JSContext* cx)
ErrorResult::SetPendingGenericErrorException(JSContext* cx)
{
MOZ_ASSERT(!IsErrorWithMessage());
MOZ_ASSERT(!IsJSException());
MOZ_ASSERT(!IsDOMException());
dom::Throw(cx, ErrorCode());
mResult = NS_OK;
}
ErrorResult&
@ -508,6 +461,39 @@ ErrorResult::SuppressException()
mResult = NS_OK;
}
void
ErrorResult::SetPendingException(JSContext* cx)
{
if (IsUncatchableException()) {
// Nuke any existing exception on cx, to make sure we're uncatchable.
JS_ClearPendingException(cx);
// Don't do any reporting. Just return, to create an
// uncatchable exception.
mResult = NS_OK;
return;
}
if (IsJSContextException()) {
// Whatever we need to throw is on the JSContext already. We
// can't assert that there is a pending exception on it, though,
// because in the uncatchable exception case there won't be one.
mResult = NS_OK;
return;
}
if (IsErrorWithMessage()) {
SetPendingExceptionWithMessage(cx);
return;
}
if (IsJSException()) {
SetPendingJSException(cx);
return;
}
if (IsDOMException()) {
SetPendingDOMException(cx);
return;
}
SetPendingGenericErrorException(cx);
}
namespace dom {
bool
@ -2777,10 +2763,10 @@ ConvertExceptionToPromise(JSContext* cx,
JS_ClearPendingException(cx);
ErrorResult rv;
RefPtr<Promise> promise = Promise::Reject(global, exn, rv);
if (rv.Failed()) {
// We just give up. Make sure to not leak memory on the
// ErrorResult, but then just put the original exception back.
ThrowMethodFailed(cx, rv);
if (rv.MaybeSetPendingException(cx)) {
// We just give up. We put the exception from the ErrorResult on
// the JSContext just to make sure to not leak memory on the
// ErrorResult, but now just put the original exception back.
JS_SetPendingException(cx, exn);
return false;
}

View File

@ -92,9 +92,6 @@ ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs,
const ErrNum aErrorNumber,
prototypes::ID aProtoId);
bool
ThrowMethodFailed(JSContext* cx, ErrorResult& rv);
// Returns true if the JSClass is used for DOM objects.
inline bool
IsDOMClass(const JSClass* clasp)

View File

@ -1663,11 +1663,7 @@ class CGClassConstructor(CGAbstractStaticMethod):
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
JS::Rooted<JSObject*> obj(cx, &args.callee());
$*{chromeOnlyCheck}
bool mayInvoke = args.isConstructing();
#ifdef RELEASE_BUILD
mayInvoke = mayInvoke || nsContentUtils::ThreadsafeIsCallerChrome();
#endif // RELEASE_BUILD
if (!mayInvoke) {
if (!args.isConstructing()) {
// XXXbz wish I could get the name from the callee instead of
// Adding more relocations
return ThrowConstructorWithoutNew(cx, "${ctorName}");
@ -1728,9 +1724,7 @@ class CGConstructNavigatorObject(CGAbstractMethod):
JS::Rooted<JS::Value> v(aCx);
{ // Scope to make sure |result| goes out of scope while |v| is rooted
RefPtr<mozilla::dom::${descriptorName}> result = ConstructNavigatorObjectHelper(aCx, global, rv);
rv.WouldReportJSException();
if (rv.Failed()) {
ThrowMethodFailed(aCx, rv);
if (rv.MaybeSetPendingException(aCx)) {
return nullptr;
}
if (!GetOrCreateDOMReflector(aCx, result, &v)) {
@ -5101,8 +5095,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
}
ErrorResult promiseRv;
$${declName} = Promise::Resolve(promiseGlobal, $${val}, promiseRv);
if (promiseRv.Failed()) {
ThrowMethodFailed(cx, promiseRv);
if (promiseRv.MaybeSetPendingException(cx)) {
$*{exceptionCode}
}
}
@ -6274,21 +6267,14 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode,
resultLoc = result
conversion = fill(
"""
{
// Scope for resultStr
MOZ_ASSERT(uint32_t(${result}) < ArrayLength(${strings}));
JSString* resultStr = JS_NewStringCopyN(cx, ${strings}[uint32_t(${result})].value, ${strings}[uint32_t(${result})].length);
if (!resultStr) {
$*{exceptionCode}
}
$*{setResultStr}
if (!ToJSValue(cx, ${result}, $${jsvalHandle})) {
$*{exceptionCode}
}
$*{successCode}
""",
result=resultLoc,
strings=(type.unroll().inner.identifier.name + "Values::" +
ENUM_ENTRY_VARIABLE_NAME),
exceptionCode=exceptionCode,
setResultStr=setString("resultStr"))
successCode=successCode)
if type.nullable():
conversion = CGIfElseWrapper(
@ -6664,23 +6650,18 @@ class CGCallGenerator(CGThing):
A class to generate an actual call to a C++ object. Assumes that the C++
object is stored in a variable whose name is given by the |object| argument.
errorReport should be a CGThing for an error report or None if no
error reporting is needed.
isFallible is a boolean indicating whether the call should be fallible.
resultVar: If the returnType is not void, then the result of the call is
stored in a C++ variable named by resultVar. The caller is responsible for
declaring the result variable. If the caller doesn't care about the result
value, resultVar can be omitted.
"""
def __init__(self, errorReport, arguments, argsPre, returnType,
def __init__(self, isFallible, arguments, argsPre, returnType,
extendedAttributes, descriptorProvider, nativeMethodName,
static, object="self", argsPost=[], resultVar=None):
CGThing.__init__(self)
assert errorReport is None or isinstance(errorReport, CGThing)
isFallible = errorReport is not None
result, resultOutParam, resultRooter, resultArgs, resultConversion = \
getRetvalDeclarationForType(returnType, descriptorProvider)
@ -6775,10 +6756,12 @@ class CGCallGenerator(CGThing):
if isFallible:
self.cgRoot.prepend(CGGeneric("ErrorResult rv;\n"))
self.cgRoot.append(CGGeneric("rv.WouldReportJSException();\n"))
self.cgRoot.append(CGGeneric("if (MOZ_UNLIKELY(rv.Failed())) {\n"))
self.cgRoot.append(CGIndenter(errorReport))
self.cgRoot.append(CGGeneric("}\n"))
self.cgRoot.append(CGGeneric(dedent(
"""
if (MOZ_UNLIKELY(rv.MaybeSetPendingException(cx))) {
return false;
}
""")))
self.cgRoot.append(CGGeneric("MOZ_ASSERT(!JS_IsExceptionPending(cx));\n"))
@ -7172,7 +7155,7 @@ class CGPerSignatureCall(CGThing):
idlNode.identifier.name))
else:
cgThings.append(CGCallGenerator(
self.getErrorReport() if self.isFallible() else None,
self.isFallible(),
self.getArguments(), argsPre, returnType,
self.extendedAttributes, descriptor, nativeMethodName,
static, argsPost=argsPost, resultVar=resultVar))
@ -7279,9 +7262,6 @@ class CGPerSignatureCall(CGThing):
maybeWrap=getMaybeWrapValueFuncForType(self.idlNode.type))
return wrapCode
def getErrorReport(self):
return CGGeneric('return ThrowMethodFailed(cx, rv);\n')
def define(self):
return (self.cgRoot.define() + self.wrap_return_value())
@ -8250,9 +8230,8 @@ class CGEnumerateHook(CGAbstractBindingMethod):
nsAutoTArray<nsString, 8> names;
ErrorResult rv;
self->GetOwnPropertyNames(cx, names, rv);
rv.WouldReportJSException();
if (rv.Failed()) {
return ThrowMethodFailed(cx, rv);
if (rv.MaybeSetPendingException(cx)) {
return false;
}
bool dummy;
for (uint32_t i = 0; i < names.Length(); ++i) {
@ -9068,11 +9047,53 @@ def getEnumValueName(value):
' rename our internal EndGuard_ to something else')
return nativeName
class CGEnumToJSValue(CGAbstractMethod):
def __init__(self, enum):
enumType = enum.identifier.name
self.stringsArray = enumType + "Values::" + ENUM_ENTRY_VARIABLE_NAME
CGAbstractMethod.__init__(self, None, "ToJSValue", "bool",
[Argument("JSContext*", "aCx"),
Argument(enumType, "aArgument"),
Argument("JS::MutableHandle<JS::Value>",
"aValue")])
def definition_body(self):
return fill(
"""
MOZ_ASSERT(uint32_t(aArgument) < ArrayLength(${strings}));
JSString* resultStr =
JS_NewStringCopyN(aCx, ${strings}[uint32_t(aArgument)].value,
${strings}[uint32_t(aArgument)].length);
if (!resultStr) {
return false;
}
aValue.setString(resultStr);
return true;
""",
strings=self.stringsArray)
class CGEnum(CGThing):
def __init__(self, enum):
CGThing.__init__(self)
self.enum = enum
strings = CGNamespace(
self.stringsNamespace(),
CGGeneric(declare=("extern const EnumEntry %s[%d];\n" %
(ENUM_ENTRY_VARIABLE_NAME, self.nEnumStrings())),
define=fill(
"""
extern const EnumEntry ${name}[${count}] = {
$*{entries}
{ nullptr, 0 }
};
""",
name=ENUM_ENTRY_VARIABLE_NAME,
count=self.nEnumStrings(),
entries=''.join('{"%s", %d},\n' % (val, len(val))
for val in self.enum.values()))))
toJSValue = CGEnumToJSValue(enum)
self.cgThings = CGList([strings, toJSValue], "\n")
def stringsNamespace(self):
return self.enum.identifier.name + "Values"
@ -9093,22 +9114,10 @@ class CGEnum(CGThing):
strings = CGNamespace(self.stringsNamespace(),
CGGeneric(declare="extern const EnumEntry %s[%d];\n"
% (ENUM_ENTRY_VARIABLE_NAME, self.nEnumStrings())))
return decl + "\n" + strings.declare()
return decl + "\n" + self.cgThings.declare()
def define(self):
strings = fill(
"""
extern const EnumEntry ${name}[${count}] = {
$*{entries}
{ nullptr, 0 }
};
""",
name=ENUM_ENTRY_VARIABLE_NAME,
count=self.nEnumStrings(),
entries=''.join('{"%s", %d},\n' % (val, len(val))
for val in self.enum.values()))
return CGNamespace(self.stringsNamespace(),
CGGeneric(define=indent(strings))).define()
return self.cgThings.define()
def deps(self):
return self.enum.getDeps()
@ -10308,9 +10317,8 @@ class CGEnumerateOwnPropertiesViaGetOwnPropertyNames(CGAbstractBindingMethod):
nsAutoTArray<nsString, 8> names;
ErrorResult rv;
self->GetOwnPropertyNames(cx, names, rv);
rv.WouldReportJSException();
if (rv.Failed()) {
return ThrowMethodFailed(cx, rv);
if (rv.MaybeSetPendingException(cx)) {
return false;
}
// OK to pass null as "proxy" because it's ignored if
// shadowPrototypeProperties is true
@ -12172,11 +12180,9 @@ class CGDictionary(CGThing):
if m.canHaveMissingValue():
memberAssign = CGGeneric(fill(
"""
${name}.Reset();
if (aOther.${name}.WasPassed()) {
${name}.Construct();
${name}.Value() = aOther.${name}.Value();
} else {
${name}.Reset();
${name}.Construct(aOther.${name}.Value());
}
""",
name=memberName))
@ -13014,6 +13020,11 @@ class CGBindingRoot(CGThing):
bindingHeaders["mozilla/dom/DOMJSClass.h"] = descriptors
bindingHeaders["mozilla/dom/ScriptSettings.h"] = dictionaries # AutoJSAPI
bindingHeaders["xpcpublic.h"] = dictionaries # xpc::UnprivilegedJunkScope
# Ensure we see our enums in the generated .cpp file, for the ToJSValue
# method body. Also ensure that we see jsapi.h.
if enums:
bindingHeaders[CGHeaders.getDeclarationFilename(enums[0])] = True
bindingHeaders["jsapi.h"] = True
# For things that have [UseCounter]
def descriptorRequiresTelemetry(desc):

View File

@ -6,6 +6,17 @@
/**
* A struct for tracking exceptions that need to be thrown to JS.
*
* Conceptually, an ErrorResult represents either success or an exception in the
* process of being thrown. This means that a failing ErrorResult _must_ be
* handled in one of the following ways before coming off the stack:
*
* 1) Suppressed via SuppressException().
* 2) Converted to a pure nsresult return value via StealNSResult().
* 3) Converted to an actual pending exception on a JSContext via
* MaybeSetPendingException.
* 4) Converted to an exception JS::Value (probably to then reject a Promise
* with) via dom::ToJSValue.
*/
#ifndef mozilla_ErrorResult_h
@ -61,14 +72,14 @@ struct StringArrayAppender
}
template<typename... Ts>
static void Append(nsTArray<nsString>& aArgs, uint16_t aCount, const nsAString* aFirst, Ts... aOtherArgs)
static void Append(nsTArray<nsString>& aArgs, uint16_t aCount, const nsAString& aFirst, Ts&&... aOtherArgs)
{
if (aCount == 0) {
MOZ_ASSERT(false, "There should not be more string arguments provided than are required by the ErrNum.");
return;
}
aArgs.AppendElement(*aFirst);
Append(aArgs, aCount - 1, aOtherArgs...);
aArgs.AppendElement(aFirst);
Append(aArgs, aCount - 1, Forward<Ts>(aOtherArgs)...);
}
};
@ -87,8 +98,9 @@ public:
#ifdef DEBUG
~ErrorResult() {
MOZ_ASSERT_IF(IsErrorWithMessage(), !mMessage);
MOZ_ASSERT_IF(IsDOMException(), !mDOMExceptionInfo);
// Consumers should have called one of MaybeSetPendingException
// (possibly via ToJSValue), StealNSResult, and SuppressException
MOZ_ASSERT(!Failed());
MOZ_ASSERT(!mMightHaveUnreportedJSException);
MOZ_ASSERT(mUnionState == HasNothing);
}
@ -134,33 +146,71 @@ public:
return rv;
}
template<dom::ErrNum errorNumber, typename... Ts>
void ThrowTypeError(Ts... messageArgs)
// Use MaybeSetPendingException to convert an ErrorResult to a pending
// exception on the given JSContext. This is the normal "throw an exception"
// codepath.
//
// The return value is false if the ErrorResult represents success, true
// otherwise. This does mean that in JSAPI method implementations you can't
// just use this as |return rv.MaybeSetPendingException(cx)| (though you could
// |return !rv.MaybeSetPendingException(cx)|), but in practice pretty much any
// consumer would want to do some more work on the success codepath. So
// instead the way you use this is:
//
// if (rv.MaybeSetPendingException(cx)) {
// bail out here
// }
// go on to do something useful
//
// The success path is inline, since it should be the common case and we don't
// want to pay the price of a function call in some of the consumers of this
// method in the common case.
//
// Note that a true return value does NOT mean there is now a pending
// exception on aCx, due to uncatchable exceptions. It should still be
// considered equivalent to a JSAPI failure in terms of what callers should do
// after true is returned.
//
// After this call, the ErrorResult will no longer return true from Failed(),
// since the exception will have moved to the JSContext.
bool MaybeSetPendingException(JSContext* cx)
{
ThrowErrorWithMessage<errorNumber>(NS_ERROR_TYPE_ERR, messageArgs...);
WouldReportJSException();
if (!Failed()) {
return false;
}
SetPendingException(cx);
return true;
}
template<dom::ErrNum errorNumber, typename... Ts>
void ThrowRangeError(Ts... messageArgs)
void ThrowTypeError(Ts&&... messageArgs)
{
ThrowErrorWithMessage<errorNumber>(NS_ERROR_RANGE_ERR, messageArgs...);
ThrowErrorWithMessage<errorNumber>(NS_ERROR_TYPE_ERR,
Forward<Ts>(messageArgs)...);
}
template<dom::ErrNum errorNumber, typename... Ts>
void ThrowRangeError(Ts&&... messageArgs)
{
ThrowErrorWithMessage<errorNumber>(NS_ERROR_RANGE_ERR,
Forward<Ts>(messageArgs)...);
}
void ReportErrorWithMessage(JSContext* cx);
bool IsErrorWithMessage() const { return ErrorCode() == NS_ERROR_TYPE_ERR || ErrorCode() == NS_ERROR_RANGE_ERR; }
// Facilities for throwing a preexisting JS exception value via this
// ErrorResult. The contract is that any code which might end up calling
// ThrowJSException() must call MightThrowJSException() even if no exception
// is being thrown. Code that would call ReportJSException or
// StealJSException as needed must first call WouldReportJSException even if
// is being thrown. Code that conditionally calls ToJSValue on this
// ErrorResult only if Failed() must first call WouldReportJSException even if
// this ErrorResult has not failed.
//
// The exn argument to ThrowJSException can be in any compartment. It does
// not have to be in the compartment of cx. If someone later uses it, they
// will wrap it into whatever compartment they're working in, as needed.
void ThrowJSException(JSContext* cx, JS::Handle<JS::Value> exn);
void ReportJSException(JSContext* cx);
bool IsJSException() const { return ErrorCode() == NS_ERROR_DOM_JS_EXCEPTION; }
// Facilities for throwing a DOMException. If an empty message string is
@ -169,7 +219,6 @@ public:
// passed in must be one we create DOMExceptions for; otherwise you may get an
// XPConnect Exception.
void ThrowDOMException(nsresult rv, const nsACString& message = EmptyCString());
void ReportDOMException(JSContext* cx);
bool IsDOMException() const { return ErrorCode() == NS_ERROR_DOM_DOMEXCEPTION; }
// Flag on the ErrorResult that whatever needs throwing has been
@ -183,10 +232,6 @@ public:
return ErrorCode() == NS_ERROR_DOM_EXCEPTION_ON_JSCONTEXT;
}
// Report a generic error. This should only be used if we're not
// some more specific exception type.
void ReportGenericError(JSContext* cx);
// Support for uncatchable exceptions.
void ThrowUncatchableException() {
Throw(NS_ERROR_UNCATCHABLE_EXCEPTION);
@ -195,11 +240,6 @@ public:
return ErrorCode() == NS_ERROR_UNCATCHABLE_EXCEPTION;
}
// StealJSException steals the JS Exception from the object. This method must
// be called only if IsJSException() returns true. This method also resets the
// error code to NS_OK.
void StealJSException(JSContext* cx, JS::MutableHandle<JS::Value> value);
void MOZ_ALWAYS_INLINE MightThrowJSException()
{
#ifdef DEBUG
@ -264,7 +304,7 @@ private:
nsTArray<nsString>& CreateErrorMessageHelper(const dom::ErrNum errorNumber, nsresult errorType);
template<dom::ErrNum errorNumber, typename... Ts>
void ThrowErrorWithMessage(nsresult errorType, Ts... messageArgs)
void ThrowErrorWithMessage(nsresult errorType, Ts&&... messageArgs)
{
#if defined(DEBUG) && (defined(__clang__) || defined(__GNUC__))
static_assert(dom::ErrorFormatNumArgs[errorNumber] == sizeof...(messageArgs),
@ -275,7 +315,8 @@ private:
nsTArray<nsString>& messageArgsArray = CreateErrorMessageHelper(errorNumber, errorType);
uint16_t argCount = dom::GetErrorArgCount(errorNumber);
dom::StringArrayAppender::Append(messageArgsArray, argCount, messageArgs...);
dom::StringArrayAppender::Append(messageArgsArray, argCount,
Forward<Ts>(messageArgs)...);
#ifdef DEBUG
mUnionState = HasMessage;
#endif // DEBUG
@ -306,6 +347,17 @@ private:
// anymore.
void ClearUnionData();
// Implementation of MaybeSetPendingException for the case when we're a
// failure result.
void SetPendingException(JSContext* cx);
// Methods for setting various specific kinds of pending exceptions.
void SetPendingExceptionWithMessage(JSContext* cx);
void SetPendingJSException(JSContext* cx);
void SetPendingDOMException(JSContext* cx);
void SetPendingGenericErrorException(JSContext* cx);
// Special values of mResult:
// NS_ERROR_TYPE_ERR -- ThrowTypeError() called on us.
// NS_ERROR_RANGE_ERR -- ThrowRangeError() called on us.
@ -317,11 +369,11 @@ private:
struct Message;
struct DOMExceptionInfo;
// mMessage is set by ThrowErrorWithMessage and reported (and deallocated) by
// ReportErrorWithMessage.
// SetPendingExceptionWithMessage.
// mJSException is set (and rooted) by ThrowJSException and reported
// (and unrooted) by ReportJSException.
// (and unrooted) by SetPendingJSException.
// mDOMExceptionInfo is set by ThrowDOMException and reported
// (and deallocated) by ReportDOMException.
// (and deallocated) by SetPendingDOMException.
union {
Message* mMessage; // valid when IsErrorWithMessage()
JS::Value mJSException; // valid when IsJSException()

View File

@ -56,8 +56,8 @@ ToJSValue(JSContext* aCx,
MOZ_ASSERT(!aArgument.IsUncatchableException(),
"Doesn't make sense to convert uncatchable exception to a JS value!");
AutoForceSetExceptionOnContext forceExn(aCx);
DebugOnly<bool> throwResult = ThrowMethodFailed(aCx, aArgument);
MOZ_ASSERT(!throwResult);
DebugOnly<bool> throwResult = aArgument.MaybeSetPendingException(aCx);
MOZ_ASSERT(throwResult);
DebugOnly<bool> getPendingResult = JS_GetPendingException(aCx, aValue);
MOZ_ASSERT(getPendingResult);
JS_ClearPendingException(aCx);

View File

@ -19,6 +19,7 @@
#include "mozilla/Services.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/unused.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/bluetooth/BluetoothTypes.h"
#include "mozilla/dom/ipc/BlobChild.h"

View File

@ -2037,6 +2037,9 @@ BrowserElementChild.prototype = {
case Cr.NS_ERROR_UNWANTED_URI :
sendAsyncMsg('error', { type: 'unwantedBlocked' });
return;
case Cr.NS_ERROR_FORBIDDEN_URI :
sendAsyncMsg('error', { type: 'forbiddenBlocked' });
return;
case Cr.NS_ERROR_OFFLINE :
sendAsyncMsg('error', { type: 'offline' });

6
dom/cache/Cache.cpp vendored
View File

@ -46,8 +46,8 @@ IsValidPutRequestURL(const nsAString& aUrl, ErrorResult& aRv)
}
if (!validScheme) {
NS_NAMED_LITERAL_STRING(label, "Request");
aRv.ThrowTypeError<MSG_INVALID_URL_SCHEME>(&label, &aUrl);
aRv.ThrowTypeError<MSG_INVALID_URL_SCHEME>(NS_LITERAL_STRING("Request"),
aUrl);
return false;
}
@ -61,7 +61,7 @@ IsValidPutRequestMethod(const Request& aRequest, ErrorResult& aRv)
aRequest.GetMethod(method);
if (!method.LowerCaseEqualsLiteral("get")) {
NS_ConvertASCIItoUTF16 label(method);
aRv.ThrowTypeError<MSG_INVALID_REQUEST_METHOD>(&label);
aRv.ThrowTypeError<MSG_INVALID_REQUEST_METHOD>(label);
return false;
}

View File

@ -261,8 +261,8 @@ CacheStorage::DefineCaches(JSContext* aCx, JS::Handle<JSObject*> aGlobal)
false, /* private browsing */
true, /* force trusted */
rv);
if (NS_WARN_IF(rv.Failed())) {
return ThrowMethodFailed(aCx, rv);
if (NS_WARN_IF(rv.MaybeSetPendingException(aCx))) {
return false;
}
JS::Rooted<JS::Value> caches(aCx);

121
dom/cache/Context.cpp vendored
View File

@ -132,7 +132,7 @@ public:
NS_ASSERT_OWNINGTHREAD(QuotaInitRunnable);
MOZ_ASSERT(mState == STATE_INIT);
mState = STATE_OPEN_DIRECTORY;
mState = STATE_GET_INFO;
nsresult rv = NS_DispatchToMainThread(this, nsIThread::DISPATCH_NORMAL);
if (NS_WARN_IF(NS_FAILED(rv))) {
mState = STATE_COMPLETE;
@ -149,6 +149,8 @@ public:
mInitAction->CancelOnInitiatingThread();
}
void OpenDirectory();
// OpenDirectoryListener methods
virtual void
DirectoryLockAcquired(DirectoryLock* aLock) override;
@ -195,6 +197,8 @@ private:
enum State
{
STATE_INIT,
STATE_GET_INFO,
STATE_CREATE_QUOTA_MANAGER,
STATE_OPEN_DIRECTORY,
STATE_WAIT_FOR_DIRECTORY_LOCK,
STATE_ENSURE_ORIGIN_INITIALIZED,
@ -234,7 +238,7 @@ private:
nsCOMPtr<nsIThread> mInitiatingThread;
nsresult mResult;
QuotaInfo mQuotaInfo;
nsMainThreadPtrHandle<DirectoryLock> mDirectoryLock;
RefPtr<DirectoryLock> mDirectoryLock;
State mState;
Atomic<bool> mCanceled;
@ -243,14 +247,35 @@ public:
NS_DECL_NSIRUNNABLE
};
void
Context::QuotaInitRunnable::OpenDirectory()
{
NS_ASSERT_OWNINGTHREAD(QuotaInitRunnable);
MOZ_ASSERT(mState == STATE_CREATE_QUOTA_MANAGER ||
mState == STATE_OPEN_DIRECTORY);
MOZ_ASSERT(QuotaManager::Get());
// QuotaManager::OpenDirectory() will hold a reference to us as
// a listener. We will then get DirectoryLockAcquired() on the owning
// thread when it is safe to access our storage directory.
mState = STATE_WAIT_FOR_DIRECTORY_LOCK;
QuotaManager::Get()->OpenDirectory(PERSISTENCE_TYPE_DEFAULT,
mQuotaInfo.mGroup,
mQuotaInfo.mOrigin,
mQuotaInfo.mIsApp,
quota::Client::DOMCACHE,
/* aExclusive */ false,
this);
}
void
Context::QuotaInitRunnable::DirectoryLockAcquired(DirectoryLock* aLock)
{
MOZ_ASSERT(NS_IsMainThread());
NS_ASSERT_OWNINGTHREAD(QuotaInitRunnable);
MOZ_ASSERT(mState == STATE_WAIT_FOR_DIRECTORY_LOCK);
MOZ_ASSERT(!mDirectoryLock);
mDirectoryLock = new nsMainThreadPtrHolder<DirectoryLock>(aLock);
mDirectoryLock = aLock;
if (mCanceled) {
Complete(NS_ERROR_ABORT);
@ -271,7 +296,7 @@ Context::QuotaInitRunnable::DirectoryLockAcquired(DirectoryLock* aLock)
void
Context::QuotaInitRunnable::DirectoryLockFailed()
{
MOZ_ASSERT(NS_IsMainThread());
NS_ASSERT_OWNINGTHREAD(QuotaInitRunnable);
MOZ_ASSERT(mState == STATE_WAIT_FOR_DIRECTORY_LOCK);
MOZ_ASSERT(!mDirectoryLock);
@ -290,13 +315,23 @@ NS_IMPL_ISUPPORTS(mozilla::dom::cache::Context::QuotaInitRunnable, nsIRunnable);
// +-------+-------+ |
// | |
// +----------v-----------+ |
// | OpenDirectory | Resolve(error) |
// | GetInfo | Resolve(error) |
// | (Main Thread) +-----------------+
// +----------+-----------+ |
// | |
// +----------v-----------+ |
// | CreateQuotaManager | Resolve(error) |
// | (Orig Thread) +-----------------+
// +----------+-----------+ |
// | |
// +----------v-----------+ |
// | OpenDirectory | Resolve(error) |
// | (Orig Thread) +-----------------+
// +----------+-----------+ |
// | |
// +----------v-----------+ |
// | WaitForDirectoryLock | Resolve(error) |
// | (Main Thread) +-----------------+
// | (Orig Thread) +-----------------+
// +----------+-----------+ |
// | |
// +----------v------------+ |
@ -330,43 +365,61 @@ Context::QuotaInitRunnable::Run()
switch(mState) {
// -----------------------------------
case STATE_OPEN_DIRECTORY:
case STATE_GET_INFO:
{
MOZ_ASSERT(NS_IsMainThread());
if (mCanceled) {
resolver->Resolve(NS_ERROR_ABORT);
break;
}
RefPtr<ManagerId> managerId = mManager->GetManagerId();
nsCOMPtr<nsIPrincipal> principal = managerId->Principal();
nsresult rv = QuotaManager::GetInfoFromPrincipal(principal,
&mQuotaInfo.mGroup,
&mQuotaInfo.mOrigin,
&mQuotaInfo.mIsApp);
if (NS_WARN_IF(NS_FAILED(rv))) {
resolver->Resolve(rv);
break;
}
mState = STATE_CREATE_QUOTA_MANAGER;
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
mInitiatingThread->Dispatch(this, nsIThread::DISPATCH_NORMAL)));
break;
}
// ----------------------------------
case STATE_CREATE_QUOTA_MANAGER:
{
NS_ASSERT_OWNINGTHREAD(QuotaInitRunnable);
if (mCanceled || QuotaManager::IsShuttingDown()) {
resolver->Resolve(NS_ERROR_ABORT);
break;
}
QuotaManager* qm = QuotaManager::GetOrCreate();
if (!qm) {
if (QuotaManager::Get()) {
OpenDirectory();
return NS_OK;
}
mState = STATE_OPEN_DIRECTORY;
QuotaManager::GetOrCreate(this);
break;
}
// ----------------------------------
case STATE_OPEN_DIRECTORY:
{
NS_ASSERT_OWNINGTHREAD(QuotaInitRunnable);
if (NS_WARN_IF(!QuotaManager::Get())) {
resolver->Resolve(NS_ERROR_FAILURE);
break;
}
RefPtr<ManagerId> managerId = mManager->GetManagerId();
nsCOMPtr<nsIPrincipal> principal = managerId->Principal();
nsresult rv = qm->GetInfoFromPrincipal(principal,
&mQuotaInfo.mGroup,
&mQuotaInfo.mOrigin,
&mQuotaInfo.mIsApp);
if (NS_WARN_IF(NS_FAILED(rv))) {
resolver->Resolve(rv);
break;
}
// QuotaManager::OpenDirectory() will hold a reference to us as
// a listener. We will then get DirectoryLockAcquired() on the main
// thread when it is safe to access our storage directory.
mState = STATE_WAIT_FOR_DIRECTORY_LOCK;
qm->OpenDirectory(PERSISTENCE_TYPE_DEFAULT,
mQuotaInfo.mGroup,
mQuotaInfo.mOrigin,
mQuotaInfo.mIsApp,
quota::Client::DOMCACHE,
/* aExclusive */ false,
this);
OpenDirectory();
break;
}
// ----------------------------------
@ -425,7 +478,7 @@ Context::QuotaInitRunnable::Run()
{
NS_ASSERT_OWNINGTHREAD(QuotaInitRunnable);
mInitAction->CompleteOnInitiatingThread(mResult);
mContext->OnQuotaInit(mResult, mQuotaInfo, mDirectoryLock);
mContext->OnQuotaInit(mResult, mQuotaInfo, mDirectoryLock.forget());
mState = STATE_COMPLETE;
// Explicitly cleanup here as the destructor could fire on any of
@ -987,7 +1040,7 @@ Context::DispatchAction(Action* aAction, bool aDoomData)
void
Context::OnQuotaInit(nsresult aRv, const QuotaInfo& aQuotaInfo,
nsMainThreadPtrHandle<DirectoryLock>& aDirectoryLock)
already_AddRefed<DirectoryLock> aDirectoryLock)
{
NS_ASSERT_OWNINGTHREAD(Context);

5
dom/cache/Context.h vendored
View File

@ -190,7 +190,8 @@ private:
void Start();
void DispatchAction(Action* aAction, bool aDoomData = false);
void OnQuotaInit(nsresult aRv, const QuotaInfo& aQuotaInfo,
nsMainThreadPtrHandle<DirectoryLock>& aDirectoryLock);
already_AddRefed<DirectoryLock> aDirectoryLock);
already_AddRefed<ThreadsafeHandle>
CreateThreadsafeHandle();
@ -221,7 +222,7 @@ private:
// when ThreadsafeHandle::AllowToClose() is called.
RefPtr<ThreadsafeHandle> mThreadsafeHandle;
nsMainThreadPtrHandle<DirectoryLock> mDirectoryLock;
RefPtr<DirectoryLock> mDirectoryLock;
RefPtr<Context> mNextContext;
public:

208
dom/cache/Manager.cpp vendored
View File

@ -242,55 +242,61 @@ public:
}
static void
StartAbortOnMainThread(const nsACString& aOrigin)
Abort(const nsACString& aOrigin)
{
MOZ_ASSERT(NS_IsMainThread());
mozilla::ipc::AssertIsOnBackgroundThread();
// Lock for sBackgroundThread.
StaticMutexAutoLock lock(sMutex);
if (!sBackgroundThread) {
if (!sFactory) {
return;
}
// Guaranteed to succeed because we should get abort only before the
// background thread is destroyed.
nsCOMPtr<nsIRunnable> runnable = new AbortRunnable(aOrigin);
nsresult rv = sBackgroundThread->Dispatch(runnable,
nsIThread::DISPATCH_NORMAL);
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(rv));
MOZ_ASSERT(!sFactory->mManagerList.IsEmpty());
{
ManagerList::ForwardIterator iter(sFactory->mManagerList);
while (iter.HasMore()) {
RefPtr<Manager> manager = iter.GetNext();
if (aOrigin.IsVoid() ||
manager->mManagerId->QuotaOrigin() == aOrigin) {
manager->Abort();
}
}
}
}
static void
StartShutdownAllOnMainThread()
ShutdownAll()
{
MOZ_ASSERT(NS_IsMainThread());
mozilla::ipc::AssertIsOnBackgroundThread();
// Lock for sFactoryShutdown and sBackgroundThread.
StaticMutexAutoLock lock(sMutex);
sFactoryShutdown = true;
if (!sBackgroundThread) {
if (!sFactory) {
return;
}
// Guaranteed to succeed because we should be shutdown before the
// background thread is destroyed.
nsCOMPtr<nsIRunnable> runnable = new ShutdownAllRunnable();
nsresult rv = sBackgroundThread->Dispatch(runnable,
nsIThread::DISPATCH_NORMAL);
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(rv));
MOZ_ASSERT(!sFactory->mManagerList.IsEmpty());
{
// Note that we are synchronously calling shutdown code here. If any
// of the shutdown code synchronously decides to delete the Factory
// we need to delay that delete until the end of this method.
AutoRestore<bool> restore(sFactory->mInSyncShutdown);
sFactory->mInSyncShutdown = true;
ManagerList::ForwardIterator iter(sFactory->mManagerList);
while (iter.HasMore()) {
RefPtr<Manager> manager = iter.GetNext();
manager->Shutdown();
}
}
MaybeDestroyInstance();
}
static bool
IsShutdownAllCompleteOnMainThread()
IsShutdownAllComplete()
{
MOZ_ASSERT(NS_IsMainThread());
StaticMutexAutoLock lock(sMutex);
// Infer whether we have shutdown using the sBackgroundThread value. We
// guarantee this is nullptr when sFactory is destroyed.
return sFactoryShutdown && !sBackgroundThread;
mozilla::ipc::AssertIsOnBackgroundThread();
return !sFactory;
}
private:
@ -322,12 +328,6 @@ private:
if (sFactoryShutdown) {
return NS_ERROR_ILLEGAL_DURING_SHUTDOWN;
}
// Cannot use ClearOnShutdown() because we're on the background thread.
// This is automatically cleared when Factory::Remove() calls
// MaybeDestroyInstance().
MOZ_ASSERT(!sBackgroundThread);
sBackgroundThread = NS_GetCurrentThread();
}
// We cannot use ClearOnShutdown() here because we're not on the main
@ -359,134 +359,21 @@ private:
return;
}
// Be clear about what we are locking. sFactory is bg thread only, so
// we don't need to lock it here. Just protect sBackgroundThread.
{
StaticMutexAutoLock lock(sMutex);
MOZ_ASSERT(sBackgroundThread);
sBackgroundThread = nullptr;
}
sFactory = nullptr;
}
static void
AbortOnBackgroundThread(const nsACString& aOrigin)
{
mozilla::ipc::AssertIsOnBackgroundThread();
// The factory was destroyed between when abort started on main thread and
// when we could start abort on the worker thread. Just declare abort
// complete.
if (!sFactory) {
#ifdef DEBUG
StaticMutexAutoLock lock(sMutex);
MOZ_ASSERT(!sBackgroundThread);
#endif
return;
}
MOZ_ASSERT(!sFactory->mManagerList.IsEmpty());
{
ManagerList::ForwardIterator iter(sFactory->mManagerList);
while (iter.HasMore()) {
RefPtr<Manager> manager = iter.GetNext();
if (aOrigin.IsVoid() ||
manager->mManagerId->QuotaOrigin() == aOrigin) {
manager->Abort();
}
}
}
}
static void
ShutdownAllOnBackgroundThread()
{
mozilla::ipc::AssertIsOnBackgroundThread();
// The factory shutdown between when shutdown started on main thread and
// when we could start shutdown on the worker thread. Just declare
// shutdown complete. The sFactoryShutdown flag prevents the factory
// from racing to restart here.
if (!sFactory) {
#ifdef DEBUG
StaticMutexAutoLock lock(sMutex);
MOZ_ASSERT(!sBackgroundThread);
#endif
return;
}
MOZ_ASSERT(!sFactory->mManagerList.IsEmpty());
{
// Note that we are synchronously calling shutdown code here. If any
// of the shutdown code synchronously decides to delete the Factory
// we need to delay that delete until the end of this method.
AutoRestore<bool> restore(sFactory->mInSyncShutdown);
sFactory->mInSyncShutdown = true;
ManagerList::ForwardIterator iter(sFactory->mManagerList);
while (iter.HasMore()) {
RefPtr<Manager> manager = iter.GetNext();
manager->Shutdown();
}
}
MaybeDestroyInstance();
}
class AbortRunnable final : public nsRunnable
{
public:
explicit AbortRunnable(const nsACString& aOrigin)
: mOrigin(aOrigin)
{ }
NS_IMETHOD
Run() override
{
mozilla::ipc::AssertIsOnBackgroundThread();
AbortOnBackgroundThread(mOrigin);
return NS_OK;
}
private:
~AbortRunnable() { }
const nsCString mOrigin;
};
class ShutdownAllRunnable final : public nsRunnable
{
public:
NS_IMETHOD
Run() override
{
mozilla::ipc::AssertIsOnBackgroundThread();
ShutdownAllOnBackgroundThread();
return NS_OK;
}
private:
~ShutdownAllRunnable() { }
};
// Singleton created on demand and deleted when last Manager is cleared
// in Remove().
// PBackground thread only.
static StaticAutoPtr<Factory> sFactory;
// protects following static attributes
// protects following static attribute
static StaticMutex sMutex;
// Indicate if shutdown has occurred to block re-creation of sFactory.
// Must hold sMutex to access.
static bool sFactoryShutdown;
// Background thread owning all Manager objects. Only set while sFactory is
// set.
// Must hold sMutex to access.
static StaticRefPtr<nsIThread> sBackgroundThread;
// Weak references as we don't want to keep Manager objects alive forever.
// When a Manager is destroyed it calls Factory::Remove() to clear itself.
// PBackground thread only.
@ -508,9 +395,6 @@ StaticMutex Manager::Factory::sMutex;
// static
bool Manager::Factory::sFactoryShutdown = false;
// static
StaticRefPtr<nsIThread> Manager::Factory::sBackgroundThread;
// ----------------------------------------------------------------------------
// Abstract class to help implement the various Actions. The vast majority
@ -1531,13 +1415,13 @@ Manager::Get(ManagerId* aManagerId)
// static
void
Manager::ShutdownAllOnMainThread()
Manager::ShutdownAll()
{
MOZ_ASSERT(NS_IsMainThread());
mozilla::ipc::AssertIsOnBackgroundThread();
Factory::StartShutdownAllOnMainThread();
Factory::ShutdownAll();
while (!Factory::IsShutdownAllCompleteOnMainThread()) {
while (!Factory::IsShutdownAllComplete()) {
if (!NS_ProcessNextEvent()) {
NS_WARNING("Something bad happened!");
break;
@ -1547,11 +1431,11 @@ Manager::ShutdownAllOnMainThread()
// static
void
Manager::AbortOnMainThread(const nsACString& aOrigin)
Manager::Abort(const nsACString& aOrigin)
{
MOZ_ASSERT(NS_IsMainThread());
mozilla::ipc::AssertIsOnBackgroundThread();
Factory::StartAbortOnMainThread(aOrigin);
Factory::Abort(aOrigin);
}
void

6
dom/cache/Manager.h vendored
View File

@ -131,11 +131,11 @@ public:
static nsresult GetOrCreate(ManagerId* aManagerId, Manager** aManagerOut);
static already_AddRefed<Manager> Get(ManagerId* aManagerId);
// Synchronously shutdown from main thread. This spins the event loop.
static void ShutdownAllOnMainThread();
// Synchronously shutdown. This spins the event loop.
static void ShutdownAll();
// Cancel actions for given origin or all actions if passed string is null.
static void AbortOnMainThread(const nsACString& aOrigin);
static void Abort(const nsACString& aOrigin);
// Must be called by Listener objects before they are destroyed.
void RemoveListener(Listener* aListener);

View File

@ -10,6 +10,7 @@
#include "mozilla/dom/cache/Manager.h"
#include "mozilla/dom/quota/QuotaManager.h"
#include "mozilla/dom/quota/UsageInfo.h"
#include "mozilla/ipc/BackgroundParent.h"
#include "nsIFile.h"
#include "nsISimpleEnumerator.h"
#include "nsThreadUtils.h"
@ -23,6 +24,7 @@ using mozilla::dom::quota::Client;
using mozilla::dom::quota::PersistenceType;
using mozilla::dom::quota::QuotaManager;
using mozilla::dom::quota::UsageInfo;
using mozilla::ipc::AssertIsOnBackgroundThread;
static nsresult
GetBodyUsage(nsIFile* aDir, UsageInfo* aUsageInfo)
@ -175,9 +177,9 @@ public:
virtual void
AbortOperations(const nsACString& aOrigin) override
{
MOZ_ASSERT(NS_IsMainThread());
AssertIsOnBackgroundThread();
Manager::AbortOnMainThread(aOrigin);
Manager::Abort(aOrigin);
}
virtual void
@ -195,22 +197,26 @@ public:
}
virtual void
PerformIdleMaintenance() override
StartIdleMaintenance() override
{ }
virtual void
StopIdleMaintenance() override
{ }
virtual void
ShutdownWorkThreads() override
{
MOZ_ASSERT(NS_IsMainThread());
AssertIsOnBackgroundThread();
// spins the event loop and synchronously shuts down all Managers
Manager::ShutdownAllOnMainThread();
Manager::ShutdownAll();
}
private:
~CacheQuotaClient()
{
MOZ_ASSERT(NS_IsMainThread());
AssertIsOnBackgroundThread();
}
NS_INLINE_DECL_REFCOUNTING(CacheQuotaClient, override)
@ -224,6 +230,8 @@ namespace cache {
already_AddRefed<quota::Client> CreateQuotaClient()
{
AssertIsOnBackgroundThread();
RefPtr<CacheQuotaClient> ref = new CacheQuotaClient();
return ref.forget();
}

View File

@ -162,9 +162,9 @@ TypeUtils::ToCacheRequest(CacheRequest& aOut, InternalRequest* aIn,
if (!schemeValid) {
if (aSchemeAction == TypeErrorOnInvalidScheme) {
NS_NAMED_LITERAL_STRING(label, "Request");
NS_ConvertUTF8toUTF16 urlUTF16(url);
aRv.ThrowTypeError<MSG_INVALID_URL_SCHEME>(&label, &urlUTF16);
aRv.ThrowTypeError<MSG_INVALID_URL_SCHEME>(NS_LITERAL_STRING("Request"),
urlUTF16);
return;
}
}

View File

@ -35,7 +35,11 @@ function runTests(testFile, order) {
// adapted from dom/indexedDB/test/helpers.js
function clearStorage() {
return new Promise(function(resolve, reject) {
SpecialPowers.clearStorageForDoc(SpecialPowers.wrap(document), resolve);
var qms = SpecialPowers.Services.qms;
var principal = SpecialPowers.wrap(document).nodePrincipal;
var request = qms.clearStoragesForPrincipal(principal);
var cb = SpecialPowers.wrapCallback(resolve);
request.callback = cb;
});
}

View File

@ -24,19 +24,31 @@ function setupTestIframe() {
function clearStorage() {
return new Promise(function(resolve, reject) {
SpecialPowers.clearStorageForDoc(SpecialPowers.wrap(document), resolve);
var qms = SpecialPowers.Services.qms;
var principal = SpecialPowers.wrap(document).nodePrincipal;
var request = qms.clearStoragesForPrincipal(principal);
var cb = SpecialPowers.wrapCallback(resolve);
request.callback = cb;
});
}
function storageUsage() {
return new Promise(function(resolve, reject) {
SpecialPowers.getStorageUsageForDoc(SpecialPowers.wrap(document), resolve);
var qms = SpecialPowers.Services.qms;
var principal = SpecialPowers.wrap(document).nodePrincipal;
var cb = SpecialPowers.wrapCallback(function(request) {
resolve(request.usage, request.fileUsage);
});
qms.getUsageForPrincipal(principal, cb);
});
}
function resetStorage() {
return new Promise(function(resolve, reject) {
SpecialPowers.resetStorageForDoc(SpecialPowers.wrap(document), resolve);
var qms = SpecialPowers.Services.qms;
var request = qms.reset();
var cb = SpecialPowers.wrapCallback(resolve);
request.callback = cb;
});
}

View File

@ -24,19 +24,31 @@ function setupTestIframe() {
function clearStorage() {
return new Promise(function(resolve, reject) {
SpecialPowers.clearStorageForDoc(SpecialPowers.wrap(document), resolve);
var qms = SpecialPowers.Services.qms;
var principal = SpecialPowers.wrap(document).nodePrincipal;
var request = qms.clearStoragesForPrincipal(principal);
var cb = SpecialPowers.wrapCallback(resolve);
request.callback = cb;
});
}
function storageUsage() {
return new Promise(function(resolve, reject) {
SpecialPowers.getStorageUsageForDoc(SpecialPowers.wrap(document), resolve);
var qms = SpecialPowers.Services.qms;
var principal = SpecialPowers.wrap(document).nodePrincipal;
var cb = SpecialPowers.wrapCallback(function(request) {
resolve(request.usage, request.fileUsage);
});
qms.getUsageForPrincipal(principal, cb);
});
}
function resetStorage() {
return new Promise(function(resolve, reject) {
SpecialPowers.resetStorageForDoc(SpecialPowers.wrap(document), resolve);
var qms = SpecialPowers.Services.qms;
var request = qms.reset();
var cb = SpecialPowers.wrapCallback(resolve);
request.callback = cb;
});
}

View File

@ -23,7 +23,10 @@ function setupTestIframe() {
function resetStorage() {
return new Promise(function(resolve, reject) {
SpecialPowers.resetStorageForDoc(SpecialPowers.wrap(document), resolve);
var qms = SpecialPowers.Services.qms;
var request = qms.reset();
var cb = SpecialPowers.wrapCallback(resolve);
request.callback = cb;
});
}

View File

@ -24,19 +24,31 @@ function setupTestIframe() {
function clearStorage() {
return new Promise(function(resolve, reject) {
SpecialPowers.clearStorageForDoc(SpecialPowers.wrap(document), resolve);
var qms = SpecialPowers.Services.qms;
var principal = SpecialPowers.wrap(document).nodePrincipal;
var request = qms.clearStoragesForPrincipal(principal);
var cb = SpecialPowers.wrapCallback(resolve);
request.callback = cb;
});
}
function storageUsage() {
return new Promise(function(resolve, reject) {
SpecialPowers.getStorageUsageForDoc(SpecialPowers.wrap(document), resolve);
var qms = SpecialPowers.Services.qms;
var principal = SpecialPowers.wrap(document).nodePrincipal;
var cb = SpecialPowers.wrapCallback(function(request) {
resolve(request.usage, request.fileUsage);
});
qms.getUsageForPrincipal(principal, cb);
});
}
function resetStorage() {
return new Promise(function(resolve, reject) {
SpecialPowers.resetStorageForDoc(SpecialPowers.wrap(document), resolve);
var qms = SpecialPowers.Services.qms;
var request = qms.reset();
var cb = SpecialPowers.wrapCallback(resolve);
request.callback = cb;
});
}

View File

@ -92,22 +92,11 @@ function resetQuotaManager() {
var pref = 'dom.quotaManager.testing';
prefService.getBranch(null).setBoolPref(pref, true);
qm.reset();
var request = qm.reset();
request.callback = resolve;
// disable quota manager testing mode
//prefService.getBranch(null).setBoolPref(pref, false);
var uri = Cc['@mozilla.org/network/io-service;1']
.getService(Ci.nsIIOService)
.newURI('http://example.com', null, null);
var principal = Cc['@mozilla.org/scriptsecuritymanager;1']
.getService(Ci.nsIScriptSecurityManager)
.getSystemPrincipal();
// use getUsageForPrincipal() to get a callback when the reset() is done
qm.getUsageForPrincipal(principal, function(principal, usage, fileUsage) {
resolve(usage);
});
});
}

View File

@ -1276,8 +1276,6 @@ nsDOMCameraControl::OnHardwareStateChange(CameraControlListener::HardwareState a
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
MOZ_ASSERT(NS_IsMainThread());
ErrorResult ignored;
switch (aState) {
case CameraControlListener::kHardwareOpen:
DOM_CAMERA_LOGI("DOM OnHardwareStateChange: open\n");
@ -1405,7 +1403,6 @@ nsDOMCameraControl::OnRecorderStateChange(CameraControlListener::RecorderState a
DOM_CAMERA_LOGT("%s:%d : this=%p, state=%u\n", __func__, __LINE__, this, aState);
MOZ_ASSERT(NS_IsMainThread());
ErrorResult ignored;
nsString state;
switch (aState) {

View File

@ -3967,6 +3967,7 @@ gfxFontGroup *CanvasRenderingContext2D::GetCurrentFontStyle()
nsCOMPtr<nsIPresShell> presShell = GetPresShell();
bool fontUpdated = SetFontInternal(kDefaultFontStyle, err);
if (err.Failed() || !fontUpdated) {
err.SuppressException();
gfxFontStyle style;
style.size = kDefaultFontSize;
gfxTextPerfMetrics* tp = nullptr;

View File

@ -1,5 +1,5 @@
# WebGL Reftests!
default-preferences pref(webgl.force-enabled,true)
default-preferences pref(webgl.force-enabled,true) pref(media.useAudioChannelAPI,true) pref(dom.audiochannel.mutedByDefault,false)
# Check that disabling works:
== webgl-disable-test.html?nogl wrapper.html?green.png

View File

@ -1,8 +0,0 @@
{
"runtests":{
},
"excludetests":{
"dom/devicestorage/test/test_dirs.html":"excluded",
"dom/devicestorage/test/test_storageAreaListener.html":"excluded"
}
}

View File

@ -1,8 +0,0 @@
[DEFAULT]
skip-if = toolkit == 'android' || e10s #bug 781789 & bug 782275
support-files =
../test/devicestorage_common.js
ipc.json
[test_ipc.html]
skip-if = buildapp == 'mulet' || buildapp == 'b2g' # b2g(nested ipc not working) b2g-debug(nested ipc not working) b2g-desktop(nested ipc not working)

View File

@ -1,173 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for OOP DeviceStorage</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<script type="application/javascript;version=1.7">
"use strict";
SimpleTest.waitForExplicitFinish();
SimpleTest.requestFlakyTimeout("untriaged");
// The crash observer registration functions are stubbed out here to
// prevent the iframe test runner from breaking later crash-related tests.
function iframeScriptFirst() {
SpecialPowers.prototype.registerProcessCrashObservers = () => {};
SpecialPowers.prototype.unregisterProcessCrashObservers = () => {};
content.wrappedJSObject.RunSet.reloadAndRunAll({
preventDefault: function() { },
__exposedProps__: { preventDefault: 'r' }
});
}
function iframeScriptSecond() {
let TestRunner = content.wrappedJSObject.TestRunner;
let oldComplete = TestRunner.onComplete;
TestRunner.onComplete = function() {
TestRunner.onComplete = oldComplete;
sendAsyncMessage("test:DeviceStorage:ipcTestComplete", {
result: JSON.stringify(TestRunner._failedTests)
});
if (oldComplete) {
oldComplete();
}
};
TestRunner.structuredLogger._dumpMessage = function(msg) {
sendAsyncMessage("test:DeviceStorage:ipcTestMessage", { msg: msg });
}
}
let VALID_ACTIONS = ['suite_start', 'suite_end', 'test_start', 'test_end', 'test_status', 'process_output', 'log'];
function validStructuredMessage(message) {
return message.action !== undefined && VALID_ACTIONS.indexOf(message.action) >= 0;
}
function onTestMessage(data) {
let message = SpecialPowers.wrap(data).data.msg;
if (validStructuredMessage(message)) {
switch (message.action) {
case "test_status":
case "test_end":
let test_tokens = message.test.split("/");
let test_name = test_tokens[test_tokens.length - 1];
if (message.subtest) {
test_name += " | " + message.subtest;
}
ok(message.expected === undefined, test_name, message.message);
break;
case "log":
info(message.message);
break;
default:
// nothing
}
}
}
function onTestComplete() {
let comp = SpecialPowers.wrap(SpecialPowers.Components);
let mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
let spObserver = comp.classes["@mozilla.org/special-powers-observer;1"]
.getService(comp.interfaces.nsIMessageListener);
mm.removeMessageListener("SPPrefService", spObserver);
mm.removeMessageListener("SPProcessCrashService", spObserver);
mm.removeMessageListener("SPPingService", spObserver);
mm.removeMessageListener("SpecialPowers.Quit", spObserver);
mm.removeMessageListener("SPPermissionManager", spObserver);
mm.removeMessageListener("test:DeviceStorage:ipcTestMessage", onTestMessage);
mm.removeMessageListener("test:DeviceStorage:ipcTestComplete", onTestComplete);
SimpleTest.executeSoon(function () { SimpleTest.finish(); });
}
function runTests() {
let iframe = document.createElement("iframe");
SpecialPowers.wrap(iframe).mozbrowser = true;
iframe.id = "iframe";
iframe.style.width = "100%";
iframe.style.height = "1000px";
function iframeLoadSecond() {
ok(true, "Got second iframe load event.");
iframe.removeEventListener("mozbrowserloadend", iframeLoadSecond);
let mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
mm.loadFrameScript("data:,(" + iframeScriptSecond.toString() + ")();",
false);
}
function iframeLoadFirst() {
ok(true, "Got first iframe load event.");
iframe.removeEventListener("mozbrowserloadend", iframeLoadFirst);
iframe.addEventListener("mozbrowserloadend", iframeLoadSecond);
let mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
let comp = SpecialPowers.wrap(SpecialPowers.Components);
let spObserver =
comp.classes["@mozilla.org/special-powers-observer;1"]
.getService(comp.interfaces.nsIMessageListener);
mm.addMessageListener("SPPrefService", spObserver);
mm.addMessageListener("SPProcessCrashService", spObserver);
mm.addMessageListener("SPPingService", spObserver);
mm.addMessageListener("SpecialPowers.Quit", spObserver);
mm.addMessageListener("SPPermissionManager", spObserver);
mm.addMessageListener("test:DeviceStorage:ipcTestMessage", onTestMessage);
mm.addMessageListener("test:DeviceStorage:ipcTestComplete", onTestComplete);
let specialPowersBase = "chrome://specialpowers/content/";
mm.loadFrameScript(specialPowersBase + "MozillaLogger.js", false);
mm.loadFrameScript(specialPowersBase + "specialpowersAPI.js", false);
mm.loadFrameScript(specialPowersBase + "specialpowers.js", false);
mm.loadFrameScript("data:,(" + iframeScriptFirst.toString() + ")();", false);
}
iframe.addEventListener("mozbrowserloadend", iframeLoadFirst);
// Strip this filename and one directory level and then add "/test".
let href = window.location.href;
href = href.substring(0, href.lastIndexOf('/'));
href = href.substring(0, href.lastIndexOf('/'));
let manifest = "tests/dom/devicestorage/ipc/ipc.json";
iframe.src = href + "/test?consoleLevel=INFO&testManifest=" + manifest;
document.body.appendChild(iframe);
}
addEventListener("load", function() {
SpecialPowers.addPermission("browser", true, document);
SpecialPowers.pushPrefEnv({
"set": [
["device.storage.enabled", true],
["device.storage.testing", true],
["device.storage.prompt.testing", true],
// TODO: remove this as part of bug 820712
["network.disable.ipc.security", true],
["dom.ipc.browser_frames.oop_by_default", true],
["dom.mozBrowserFramesEnabled", true],
["browser.pagethumbnails.capturing_disabled", true]
]
}, runTests);
});
</script>
</body>
</html>

View File

@ -41,7 +41,6 @@ LOCAL_INCLUDES += [
]
MOCHITEST_MANIFESTS += [
'ipc/mochitest.ini',
'test/mochitest.ini',
]
MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini']

View File

@ -4,7 +4,7 @@
*/
var oldVal = false;
Object.defineProperty(Array.prototype, "remove", {
enumerable: false,
configurable: false,
@ -17,36 +17,18 @@ Object.defineProperty(Array.prototype, "remove", {
}
});
function devicestorage_setup() {
// ensure that the directory we are writing into is empty
try {
const Cc = SpecialPowers.Cc;
const Ci = SpecialPowers.Ci;
var directoryService = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
var f = directoryService.get("TmpD", Ci.nsIFile);
f.appendRelativePath("device-storage-testing");
f.remove(true);
} catch(e) {}
function devicestorage_setup(callback) {
SimpleTest.waitForExplicitFinish();
if (SpecialPowers.isMainProcess()) {
try {
oldVal = SpecialPowers.getBoolPref("device.storage.enabled");
} catch(e) {}
SpecialPowers.setBoolPref("device.storage.enabled", true);
SpecialPowers.setBoolPref("device.storage.testing", true);
SpecialPowers.setBoolPref("device.storage.prompt.testing", true);
}
}
function devicestorage_cleanup() {
if (SpecialPowers.isMainProcess()) {
SpecialPowers.setBoolPref("device.storage.enabled", oldVal);
SpecialPowers.setBoolPref("device.storage.testing", false);
SpecialPowers.setBoolPref("device.storage.prompt.testing", false);
}
SimpleTest.finish();
let script = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('remove_testing_directory.js'));
script.addMessageListener('directory-removed', function listener () {
script.removeMessageListener('directory-removed', listener);
var prefs = [["device.storage.enabled", true],
["device.storage.testing", true],
["device.storage.prompt.testing", true]];
SpecialPowers.pushPrefEnv({"set": prefs}, callback);
});
}
function getRandomBuffer() {
@ -75,7 +57,7 @@ function randomFilename(l) {
function reportErrorAndQuit(e) {
ok(false, "handleError was called : " + e.target.error.name);
devicestorage_cleanup();
SimpleTest.finish();
}
function createTestFiles(storage, paths) {

View File

@ -1,6 +1,7 @@
[DEFAULT]
skip-if = e10s || (toolkit == 'android' && processor == 'x86') # e10s: bug 1222522. Android: bug 781789 & bug 782275
skip-if = (toolkit == 'android' && processor == 'x86') # Android: bug 781789 & bug 782275
support-files = devicestorage_common.js
remove_testing_directory.js
[test_823965.html]
# [test_add.html]
@ -9,6 +10,7 @@ support-files = devicestorage_common.js
[test_available.html]
[test_basic.html]
[test_dirs.html]
skip-if = e10s # Bug 1063569.
# [test_diskSpace.html]
# Possible race between the time we write a file, and the
# time it takes to be reflected by statfs(). Bug # 791287

View File

@ -0,0 +1,11 @@
// ensure that the directory we are writing into is empty
try {
var Cc = Components.classes;
var Ci = Components.interfaces;
var directoryService = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
var f = directoryService.get("TmpD", Ci.nsIFile);
f.appendRelativePath("device-storage-testing");
f.remove(true);
} catch(e) {}
sendAsyncMessage('directory-removed', {});

View File

@ -22,7 +22,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=823965
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup();
devicestorage_setup(function () {
var gFileName = "devicestorage/" + randomFilename(12) + "/hi.png";
var gData = "My name is Doug Turner (?!?). My IRC nick is DougT. I like Maple cookies."
@ -43,11 +43,11 @@ function getSuccess(e) {
var dreq = storage2.delete(mreq.result.name);
dreq.onerror = function () {
ok(true, "The bug has been fixed");
devicestorage_cleanup();
SimpleTest.finish();
};
dreq.onsuccess = function () {
ok(false, "The bug has been fixed");
devicestorage_cleanup();
SimpleTest.finish();
};
};
@ -56,7 +56,7 @@ function getSuccess(e) {
function getError(e) {
ok(false, "getError was called : " + e.target.error.name);
devicestorage_cleanup();
SimpleTest.finish();
}
function addSuccess(e) {
@ -85,7 +85,7 @@ function addSuccess(e) {
function addError(e) {
ok(false, "addError was called : " + e.target.error.name);
devicestorage_cleanup();
SimpleTest.finish();
}
ok(navigator.getDeviceStorage, "Should have getDeviceStorage");
@ -99,8 +99,9 @@ ok(request, "Should have a non-null request");
request.onsuccess = addSuccess;
request.onerror = addError;
});
</script>
</pre>
</body>
</html>

View File

@ -18,13 +18,13 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=786922
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=786922">Mozilla Bug 786922</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup();
devicestorage_setup(function () {
function add(storage, mime) {
dump("adding: " + mime + "\n");
@ -40,18 +40,18 @@ var tests = [
function fail(e) {
ok(false, "onerror was called");
devicestorage_cleanup();
SimpleTest.finish();
}
function next(e) {
if (e != undefined)
ok(true, "addError was called");
var f = tests.pop();
if (f == undefined) {
devicestorage_cleanup();
SimpleTest.finish();
return;
}
@ -62,8 +62,9 @@ function next(e) {
next();
});
</script>
</pre>
</body>
</html>

View File

@ -18,13 +18,13 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=786922
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=786922">Mozilla Bug 786922</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup();
devicestorage_setup(function () {
function addNamed(storage, mime, fileExtension) {
dump("adding: " + mime + " " + fileExtension + "\n");
@ -45,18 +45,18 @@ function fail(e) {
ok(false, "addSuccess was called");
ok(e.target.error.name == "TypeMismatchError", "Error must be TypeMismatchError");
devicestorage_cleanup();
SimpleTest.finish();
}
function next(e) {
if (e != undefined)
ok(true, "addError was called");
var f = tests.pop();
if (f == undefined) {
devicestorage_cleanup();
SimpleTest.finish();
return;
}
@ -67,8 +67,9 @@ function next(e) {
next();
});
</script>
</pre>
</body>
</html>

View File

@ -22,16 +22,16 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=834595
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup();
devicestorage_setup(function () {
function availableSuccess(e) {
isnot(e.target.result, null, "result should not be null");
devicestorage_cleanup();
SimpleTest.finish();
}
function availableError(e) {
ok(false, "availableError was called");
devicestorage_cleanup();
SimpleTest.finish();
}
var storage = navigator.getDeviceStorage("pictures");
@ -42,6 +42,8 @@ ok(request, "Should have a non-null request");
request.onsuccess = availableSuccess;
request.onerror = availableError;
});
</script>
</pre>
</body>

View File

@ -17,12 +17,12 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=717103
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=717103">Mozilla Bug 717103</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup();
devicestorage_setup(function() {
var gFileName = "devicestorage/" + randomFilename(12) + "/hi.png";
var gData = "My name is Doug Turner. My IRC nick is DougT. I like Maple cookies."
@ -31,12 +31,12 @@ var gFileReader = new FileReader();
function getAfterDeleteSuccess(e) {
ok(false, "file was deleted not successfully");
devicestorage_cleanup();
SimpleTest.finish();
}
function getAfterDeleteError(e) {
ok(true, "file was deleted successfully");
devicestorage_cleanup();
SimpleTest.finish();
}
function deleteSuccess(e) {
@ -53,7 +53,7 @@ function deleteSuccess(e) {
function deleteError(e) {
ok(false, "deleteError was called : " + e.target.error.name);
devicestorage_cleanup();
SimpleTest.finish();
}
function getSuccess(e) {
@ -88,7 +88,7 @@ function readerCallback(e) {
function getError(e) {
ok(false, "getError was called : " + e.target.error.name);
devicestorage_cleanup();
SimpleTest.finish();
}
function addSuccess(e) {
@ -119,7 +119,7 @@ function addSuccess(e) {
function addError(e) {
ok(false, "addError was called : " + e.target.error.name);
devicestorage_cleanup();
SimpleTest.finish();
}
ok(navigator.getDeviceStorage, "Should have getDeviceStorage");
@ -133,8 +133,9 @@ ok(request, "Should have a non-null request");
request.onsuccess = addSuccess;
request.onerror = addError;
});
</script>
</pre>
</body>
</html>

View File

@ -17,13 +17,12 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=717103
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=717103">Mozilla Bug 717103</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup();
devicestorage_setup(function () {
var freeBytes = -1;
var stats = 0;
@ -39,7 +38,7 @@ function stat(s, file_list_length) {
stats = stats + 1;
if (stats == 2) {
devicestorage_cleanup();
SimpleTest.finish();
}
}
@ -60,7 +59,7 @@ function addSuccess(e) {
function addError(e) {
ok(false, "addError was called : " + e.target.error.name);
devicestorage_cleanup();
SimpleTest.finish();
}
ok(true, "hi");
@ -94,8 +93,9 @@ for (var i=0; i < music_files.length; i++) {
request.onerror = addError;
}
});
</script>
</pre>
</body>
</html>

View File

@ -17,12 +17,12 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=717103
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=717103">Mozilla Bug 717103</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup();
devicestorage_setup(function () {
function testingStorage() {
return navigator.getDeviceStorage("pictures");
@ -40,20 +40,20 @@ var gFileName = "../owned.png";
function fail(e) {
ok(false, "addSuccess was called");
dump(request);
devicestorage_cleanup();
SimpleTest.finish();
}
function next(e) {
if (e != undefined) {
ok(true, "addError was called");
ok(true, "addError was called");
ok(e.target.error.name == "SecurityError", "Error must be SecurityError");
}
var f = tests.pop();
if (f == undefined) {
devicestorage_cleanup();
SimpleTest.finish();
return;
}
@ -64,10 +64,9 @@ function next(e) {
next();
});
</script>
</pre>
</body>
</html>

View File

@ -17,22 +17,22 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=717103
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=717103">Mozilla Bug 717103</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup();
devicestorage_setup(function () {
function enumerateSuccess(e) {
if (e.target.result == null) {
ok(files.length == 0, "when the enumeration is done, we shouldn't have any files in this array")
dump("We still have length = " + files.length + "\n");
devicestorage_cleanup();
SimpleTest.finish();
return;
}
var filename = e.target.result.name;
if (filename[0] == "/") {
// We got /storageName/prefix/filename
@ -61,7 +61,7 @@ function enumerateSuccess(e) {
function handleError(e) {
ok(false, "handleError was called : " + e.target.error.name);
devicestorage_cleanup();
SimpleTest.finish();
}
function addSuccess(e) {
@ -76,7 +76,7 @@ function addSuccess(e) {
function addError(e) {
ok(false, "addError was called : " + e.target.error.name);
devicestorage_cleanup();
SimpleTest.finish();
}
var storage = navigator.getDeviceStorage("pictures");
@ -96,8 +96,9 @@ for (var i=0; i<files.length; i++) {
request.onerror = addError;
}
});
</script>
</pre>
</body>
</html>

View File

@ -17,12 +17,12 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=717103
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=717103">Mozilla Bug 717103</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup();
devicestorage_setup(function () {
function enumerateSuccess(e) {
}
@ -39,12 +39,12 @@ try {
}
catch (e) {
ok(true, "Calling continue before enumerateSuccess fires should throw");
devicestorage_cleanup();
SimpleTest.finish();
}
});
</script>
</pre>
</body>
</html>

View File

@ -35,7 +35,7 @@ function enumerateSuccess(e) {
if (e.target.result == null) {
ok(files.length == 0, "when the enumeration is done, we shouldn't have any files in this array")
devicestorage_cleanup();
SimpleTest.finish();
return;
}
@ -67,7 +67,7 @@ function enumerateSuccess(e) {
function handleError(e) {
ok(false, "handleError was called : " + e.target.error.name);
devicestorage_cleanup();
SimpleTest.finish();
}
function addSuccess(e) {
@ -82,7 +82,7 @@ function addSuccess(e) {
function addError(e) {
ok(false, "addError was called : " + e.target.error.name);
devicestorage_cleanup();
SimpleTest.finish();
}
var storage = navigator.getDeviceStorage("pictures");

View File

@ -18,12 +18,12 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=717103
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=717103">Mozilla Bug 717103</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup()
devicestorage_setup(function () {
storage = navigator.getDeviceStorage("pictures");
@ -70,12 +70,11 @@ var cursor = storage.enumerate({"path": "a", "since": new Date(0) });
} catch(e) {throws = true}
ok(!throws, "enumerate object parameter with path");
SimpleTest.finish()
});
devicestorage_cleanup()
</script>
</pre>
</body>
</html>

View File

@ -22,23 +22,23 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=717103
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup();
devicestorage_setup(function () {
function freeSpaceSuccess(e) {
ok(e.target.result > 0, "free bytes should exist and be greater than zero");
devicestorage_cleanup();
SimpleTest.finish();
}
function freeSpaceError(e) {
ok(false, "freeSpaceError was called");
devicestorage_cleanup();
SimpleTest.finish();
}
var storage = navigator.getDeviceStorage("pictures");
function addError(e) {
ok(false, "addError was called : " + e.target.error.name);
devicestorage_cleanup();
SimpleTest.finish();
}
function addSuccess(e) {
@ -54,8 +54,9 @@ request = storage.addNamed(createRandomBlob('image/png'), prefix + "/a/b.png");
request.onsuccess = addSuccess;
request.onerror = addError;
});
</script>
</pre>
</body>
</html>

View File

@ -26,15 +26,15 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=855952
var file = new Blob(["This is a text file."], {type: "text/plain"});
var appendFile = new Blob([" Another text file."], {type: "text/plain"});
devicestorage_setup();
devicestorage_setup(function () {
function deleteSuccess(e) {
devicestorage_cleanup();
SimpleTest.finish();
}
function deleteError(e) {
ok(false, "deleteError was called : " + e.target.error.name);
devicestorage_cleanup();
SimpleTest.finish();
}
function appendSuccess(e) {
@ -47,7 +47,7 @@ function appendSuccess(e) {
function appendError(e) {
ok(false, "appendError was called.");
devicestorage_cleanup();
SimpleTest.finish();
}
function addSuccess(e) {
@ -83,8 +83,9 @@ ok(navigator.getDeviceStorage, "Should have getDeviceStorage");
ok(gStorage, "Should get storage from sdcard");
runtest();
});
</script>
</pre>
</body>
</html>

View File

@ -21,7 +21,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=910412
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup();
devicestorage_setup(function () {
var gFileName = randomFilename(12);
@ -46,12 +46,12 @@ function createDirectorySuccess(d) {
function getSuccess(d) {
ok(d.name === gFileName, "Should get directory - " + gFileName + ".");
devicestorage_cleanup();
SimpleTest.finish();
}
function cbError(e) {
ok(false, "Should not arrive here! Error: " + e.name);
devicestorage_cleanup();
SimpleTest.finish();
}
ok(navigator.getDeviceStorage, "Should have getDeviceStorage");
@ -63,8 +63,10 @@ var promise = storage.getRoot();
ok(promise, "Should have a non-null promise");
promise.then(getRootSuccess, cbError);
});
</script>
</pre>
</body>
</html>

View File

@ -21,7 +21,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=910412
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup();
devicestorage_setup(function () {
// The root directory object.
var gRoot;
@ -59,7 +59,7 @@ function getSuccess(d) {
// Create directory with an existing path.
gRoot.createDirectory(gPath).then(function(what) {
ok(false, "Should not overwrite an existing directory.");
devicestorage_cleanup();
SimpleTest.finish();
}, function(e) {
ok(true, "Creating directory should fail if it already exists.");
@ -73,10 +73,10 @@ function getSuccess(d) {
// Create the parent directory.
d.createDirectory('..').then(function(what) {
ok(false, "Should not overwrite an existing directory.");
devicestorage_cleanup();
SimpleTest.finish();
}, function(e) {
ok(true, "Accessing parent directory with '..' is not allowed.");
devicestorage_cleanup();
SimpleTest.finish();
});
break;
}
@ -85,7 +85,7 @@ function getSuccess(d) {
function cbError(e) {
ok(false, e.name + " error should not arrive here!");
devicestorage_cleanup();
SimpleTest.finish();
}
ok(navigator.getDeviceStorage, "Should have getDeviceStorage.");
@ -98,8 +98,10 @@ ok(promise, "Should have a non-null promise for getRoot.");
gName = storage.storageName;
promise.then(getSuccess, cbError);
});
</script>
</pre>
</body>
</html>

View File

@ -21,7 +21,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=910412
<pre id="test">
<script class="testbody" type="application/javascript;version=1.7">
devicestorage_setup();
devicestorage_setup(function () {
let gTestCount = 0;
let gFileReader = new FileReader();
@ -84,7 +84,7 @@ let gTestCases = [
function next() {
if (gTestCount >= gTestCases.length) {
devicestorage_cleanup();
SimpleTest.finish();
return;
}
let c = gTestCases[gTestCount++];
@ -122,11 +122,12 @@ storage.getRoot().then(function(dir) {
next();
}, function(e) {
ok(false, e.name + " error should not arrive here!");
devicestorage_cleanup();
SimpleTest.finish();
});
});
</script>
</pre>
</body>
</html>

View File

@ -21,7 +21,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=910412
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup();
devicestorage_setup(function () {
SimpleTest.requestCompleteLog();
// The root directory object.
@ -77,7 +78,7 @@ function getSuccess(r) {
break;
default:
ok(false, "Should not arrive at getSuccess!");
devicestorage_cleanup();
SimpleTest.finish();
break;
}
gTestCount++;
@ -137,11 +138,11 @@ function getFailure(e) {
testGetFailure(gRoot, "sub1//sub2");
break;
case 17:
devicestorage_cleanup();
SimpleTest.finish();
break;
default:
ok(false, "Should not arrive here!");
devicestorage_cleanup();
SimpleTest.finish();
break;
}
gTestCount++;
@ -149,12 +150,12 @@ function getFailure(e) {
function cbError(e) {
ok(false, "Should not arrive at cbError! Error: " + e.name);
devicestorage_cleanup();
SimpleTest.finish();
}
function cbSuccess(e) {
ok(false, "Should not arrive at cbSuccess!");
devicestorage_cleanup();
SimpleTest.finish();
}
ok(navigator.getDeviceStorage, "Should have getDeviceStorage.");
@ -173,7 +174,7 @@ function createTestFile(path, callback) {
req.onerror = function(e) {
ok(false, "Failed to create " + path + ": " + e.target.error.name);
devicestorage_cleanup();
SimpleTest.finish();
};
}
@ -197,8 +198,9 @@ createTestFile("sub1/sub2/test.png", function() {
promise.then(getSuccess, cbError);
});
});
</script>
</pre>
</body>
</html>

View File

@ -21,7 +21,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=XXX
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup();
devicestorage_setup(function () {
SimpleTest.requestCompleteLog();
// The root directory object.
@ -62,12 +62,12 @@ function checkContents1(contents) {
function checkContents2(contents) {
is(contents[0].name, "c.png", "'sub2' should contain 'c.png'");
devicestorage_cleanup();
SimpleTest.finish();
}
function handleError(e) {
ok(false, "Should not arrive at handleError! Error: " + e.name);
devicestorage_cleanup();
SimpleTest.finish();
}
var gStorage = navigator.getDeviceStorage("pictures");
@ -87,11 +87,12 @@ createTestFiles(gStorage, ["sub/a.png", "sub/b.png", "sub/sub2/c.png", "sub/sub3
runTests();
}, function() {
ok(false, "Failed to created test files.");
devicestorage_cleanup();
SimpleTest.finish();
});
});
</script>
</pre>
</body>
</html>

View File

@ -21,7 +21,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=934368
<pre id="test">
<script class="testbody" type="application/javascript;version=1.7">
devicestorage_setup();
devicestorage_setup(function () {
let gStorage = null;
let gTestCount = 0;
@ -93,7 +93,7 @@ function runNextTests() {
function runTests() {
function cbError(e) {
ok(false, "Should not arrive at cbError! Error: " + e.name);
devicestorage_cleanup();
SimpleTest.finish();
}
function cbSuccess(r) {
@ -116,7 +116,7 @@ function runNextTests() {
testNextRemove();
}, function() {
ok(false, "Failed to get test files.");
devicestorage_cleanup();
SimpleTest.finish();
});
}, cbError);
};
@ -124,7 +124,7 @@ function runNextTests() {
runTests();
}, function() {
ok(false, "Failed to created test files.");
devicestorage_cleanup();
SimpleTest.finish();
});
}
@ -156,7 +156,7 @@ function testNextRemove() {
return;
}
devicestorage_cleanup();
SimpleTest.finish();
}
ok(navigator.getDeviceStorage, "Should have getDeviceStorage.");
@ -168,8 +168,9 @@ ok(gStorage, "Should have gotten a storage.");
gRemoveDeep = true;
runNextTests();
});
</script>
</pre>
</body>
</html>

View File

@ -17,13 +17,14 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=717103
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=717103">Mozilla Bug 717103</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
SimpleTest.requestFlakyTimeout("untriaged");
devicestorage_setup();
devicestorage_setup(function () {
// We put the old files in 2 levels deep. When you add a file to a directory
// it will modify the parents last modification time, but not the parents
// parents. So we want to make sure that even though x's timestamp is earlier
@ -44,7 +45,7 @@ function verifyAndDelete(prefix, files, e) {
ok(files.length == 0, "when the enumeration is done, we shouldn't have any files in this array")
dump("We still have length = " + files.length + "\n");
dump(files + "\n");
devicestorage_cleanup();
SimpleTest.finish();
return;
}
@ -86,12 +87,12 @@ function addFile(filename, callback) {
}
getReq.onerror = function(e) {
ok(false, "getError was called : " + e.target.error.name);
devicestorage_cleanup();
SimpleTest.finish();
};
}
addReq.onerror = function(e) {
ok(false, "addError was called : " + e.target.error.name);
devicestorage_cleanup();
SimpleTest.finish();
}
}
@ -115,7 +116,7 @@ function delFile(filename, callback) {
};
req.onerror = function(e) {
ok(false, "delError was called : " + e.target.error.name);
devicestorage_cleanup();
SimpleTest.finish();
};
}
@ -129,7 +130,7 @@ function afterNewFiles() {
};
cursor.onerror = function (e) {
ok(false, "handleError was called : " + e.target.error.name);
devicestorage_cleanup();
SimpleTest.finish();
};
}
@ -167,8 +168,9 @@ function addOldFiles() {
addOldFiles();
});
</script>
</pre>
</body>
</html>

Some files were not shown because too many files have changed in this diff Show More