Merge remote-tracking branch 'origin/master' into media-works

This commit is contained in:
2021-11-04 09:24:03 +08:00
695 changed files with 357626 additions and 9470 deletions
+4 -5
View File
@@ -366,11 +366,6 @@ pref("security.apps.certified.CSP.default", "default-src * data: blob:; script-s
// Default Content Security Policy to apply to trusted apps.
pref("security.apps.trusted.CSP.default", "default-src * data: blob:; object-src 'none'; frame-src 'none'");
// Temporarily force-enable GL compositing. This is default-disabled
// deep within the bowels of the widgetry system. Remove me when GL
// compositing isn't default disabled in widget/android.
pref("layers.acceleration.force-enabled", true);
// handle links targeting new windows
// 1=current window/tab, 2=new window, 3=new tab in most recent window
pref("browser.link.open_newwindow", 3);
@@ -939,6 +934,10 @@ pref("network.proxy.browsing.app_origins", "app://system.gaiamobile.org");
// Enable Web Speech synthesis API
pref("media.webspeech.synth.enabled", true);
// Enable Web Speech recognition API
pref("media.webspeech.recognition.enable", true);
pref("media.webspeech.service.default", "pocketsphinx");
// Downloads API
pref("dom.mozDownloads.enabled", true);
pref("dom.downloads.max_retention_days", 7);
+11
View File
@@ -28,6 +28,17 @@ NSS_DISABLE_DBM=1
MOZ_NO_EV_CERTS=1
MOZ_DISABLE_EXPORT_JS=1
# Bug 1171082 - Broken on Windows B2G Desktop
if test "$OS_TARGET" != "WINNT"; then
MOZ_WEBSPEECH=1
if test -n "$NIGHTLY_BUILD"; then
MOZ_WEBSPEECH_MODELS=1
MOZ_WEBSPEECH_POCKETSPHINX=1
fi # NIGHTLY_BUILD
MOZ_WEBSPEECH_TEST_BACKEND=1
fi # !WINNT
if test "$OS_TARGET" = "Android"; then
MOZ_CAPTURE=1
MOZ_RAW=1
+3
View File
@@ -137,6 +137,9 @@
@RESPATH@/run-mozilla.sh
#endif
#endif
#ifdef MOZ_WEBSPEECH_MODELS
@BINPATH@/models/
#endif
; [Components]
@RESPATH@/components/components.manifest
+1 -1
View File
@@ -857,7 +857,7 @@ function onBlockImage()
if (checkbox.checked)
permissionManager.add(uri, "image", nsIPermissionManager.DENY_ACTION);
else
permissionManager.remove(uri.host, "image");
permissionManager.remove(uri, "image");
}
function onImageSelect()
@@ -0,0 +1,192 @@
let gHttpTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
let gPageInfo = null;
let gNextTest = null;
let gTestBrowser = null;
let gPluginHost = Components.classes["@mozilla.org/plugin/host;1"]
.getService(Components.interfaces.nsIPluginHost);
let gPermissionManager = Components.classes["@mozilla.org/permissionmanager;1"]
.getService(Components.interfaces.nsIPermissionManager);
let gTestPermissionString = gPluginHost.getPermissionStringForType("application/x-test");
let gSecondTestPermissionString = gPluginHost.getPermissionStringForType("application/x-second-test");
function doOnPageLoad(url, continuation) {
gNextTest = continuation;
gTestBrowser.addEventListener("load", pageLoad, true);
gTestBrowser.contentWindow.location = url;
}
function pageLoad() {
gTestBrowser.removeEventListener("load", pageLoad);
// The plugin events are async dispatched and can come after the load event
// This just allows the events to fire before we then go on to test the states
executeSoon(gNextTest);
}
function doOnOpenPageInfo(continuation) {
Services.obs.addObserver(pageInfoObserve, "page-info-dialog-loaded", false);
gNextTest = continuation;
// An explanation: it looks like the test harness complains about leaked
// windows if we don't keep a reference to every window we've opened.
// So, don't reuse pointers to opened Page Info windows - simply append
// to this list.
gPageInfo = BrowserPageInfo(null, "permTab");
}
function pageInfoObserve(win, topic, data) {
Services.obs.removeObserver(pageInfoObserve, "page-info-dialog-loaded");
executeSoon(gNextTest);
}
function finishTest() {
gPermissionManager.remove(makeURI("http://127.0.0.1:8888/"), gTestPermissionString);
gPermissionManager.remove(makeURI("http://127.0.0.1:8888/"), gSecondTestPermissionString);
Services.prefs.clearUserPref("plugins.click_to_play");
gBrowser.removeCurrentTab();
gPageInfo = null;
gNextTest = null;
gTestBrowser = null;
gPluginHost = null;
gPermissionManager = null;
executeSoon(finish);
}
function test() {
waitForExplicitFinish();
Services.prefs.setBoolPref("plugins.click_to_play", true);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
gBrowser.selectedTab = gBrowser.addTab();
gTestBrowser = gBrowser.selectedBrowser;
gPermissionManager.remove(makeURI("http://127.0.0.1:8888/"), gTestPermissionString);
gPermissionManager.remove(makeURI("http://127.0.0.1:8888/"), gSecondTestPermissionString);
doOnPageLoad(gHttpTestRoot + "plugin_two_types.html", testPart1a);
}
// The first test plugin is CtP and the second test plugin is enabled.
function testPart1a() {
let test = gTestBrowser.contentDocument.getElementById("test");
let objLoadingContent = test.QueryInterface(Ci.nsIObjectLoadingContent);
ok(!objLoadingContent.activated, "part 1a: Test plugin should not be activated");
let secondtest = gTestBrowser.contentDocument.getElementById("secondtestA");
objLoadingContent = secondtest.QueryInterface(Ci.nsIObjectLoadingContent);
ok(objLoadingContent.activated, "part 1a: Second Test plugin should be activated");
doOnOpenPageInfo(testPart1b);
}
function testPart1b() {
let testRadioGroup = gPageInfo.document.getElementById(gTestPermissionString + "RadioGroup");
let testRadioDefault = gPageInfo.document.getElementById(gTestPermissionString + "#0");
var qString = "#" + gTestPermissionString.replace(':', '\\:') + "\\#0";
is(testRadioGroup.selectedItem, testRadioDefault, "part 1b: Test radio group should be set to 'Default'");
let testRadioAllow = gPageInfo.document.getElementById(gTestPermissionString + "#1");
testRadioGroup.selectedItem = testRadioAllow;
testRadioAllow.doCommand();
let secondtestRadioGroup = gPageInfo.document.getElementById(gSecondTestPermissionString + "RadioGroup");
let secondtestRadioDefault = gPageInfo.document.getElementById(gSecondTestPermissionString + "#0");
is(secondtestRadioGroup.selectedItem, secondtestRadioDefault, "part 1b: Second Test radio group should be set to 'Default'");
let secondtestRadioAsk = gPageInfo.document.getElementById(gSecondTestPermissionString + "#3");
secondtestRadioGroup.selectedItem = secondtestRadioAsk;
secondtestRadioAsk.doCommand();
doOnPageLoad(gHttpTestRoot + "plugin_two_types.html", testPart2);
}
// Now, the Test plugin should be allowed, and the Test2 plugin should be CtP
function testPart2() {
let test = gTestBrowser.contentDocument.getElementById("test").
QueryInterface(Ci.nsIObjectLoadingContent);
ok(test.activated, "part 2: Test plugin should be activated");
let secondtest = gTestBrowser.contentDocument.getElementById("secondtestA").
QueryInterface(Ci.nsIObjectLoadingContent);
ok(!secondtest.activated, "part 2: Second Test plugin should not be activated");
is(secondtest.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY,
"part 2: Second test plugin should be click-to-play.");
let testRadioGroup = gPageInfo.document.getElementById(gTestPermissionString + "RadioGroup");
let testRadioAllow = gPageInfo.document.getElementById(gTestPermissionString + "#1");
is(testRadioGroup.selectedItem, testRadioAllow, "part 2: Test radio group should be set to 'Allow'");
let testRadioBlock = gPageInfo.document.getElementById(gTestPermissionString + "#2");
testRadioGroup.selectedItem = testRadioBlock;
testRadioBlock.doCommand();
let secondtestRadioGroup = gPageInfo.document.getElementById(gSecondTestPermissionString + "RadioGroup");
let secondtestRadioAsk = gPageInfo.document.getElementById(gSecondTestPermissionString + "#3");
is(secondtestRadioGroup.selectedItem, secondtestRadioAsk, "part 2: Second Test radio group should be set to 'Always Ask'");
let secondtestRadioBlock = gPageInfo.document.getElementById(gSecondTestPermissionString + "#2");
secondtestRadioGroup.selectedItem = secondtestRadioBlock;
secondtestRadioBlock.doCommand();
doOnPageLoad(gHttpTestRoot + "plugin_two_types.html", testPart3);
}
// Now, all the things should be blocked
function testPart3() {
let test = gTestBrowser.contentDocument.getElementById("test").
QueryInterface(Ci.nsIObjectLoadingContent);
ok(!test.activated, "part 3: Test plugin should not be activated");
is(test.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_DISABLED,
"part 3: Test plugin should be marked as PLUGIN_DISABLED");
let secondtest = gTestBrowser.contentDocument.getElementById("secondtestA").
QueryInterface(Ci.nsIObjectLoadingContent);
ok(!secondtest.activated, "part 3: Second Test plugin should not be activated");
is(secondtest.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_DISABLED,
"part 3: Second test plugin should be marked as PLUGIN_DISABLED");
// reset permissions
gPermissionManager.remove(makeURI("http://127.0.0.1:8888/"), gTestPermissionString);
gPermissionManager.remove(makeURI("http://127.0.0.1:8888/"), gSecondTestPermissionString);
// check that changing the permissions affects the radio state in the
// open Page Info window
let testRadioGroup = gPageInfo.document.getElementById(gTestPermissionString + "RadioGroup");
let testRadioDefault = gPageInfo.document.getElementById(gTestPermissionString + "#0");
is(testRadioGroup.selectedItem, testRadioDefault, "part 3: Test radio group should be set to 'Default'");
let secondtestRadioGroup = gPageInfo.document.getElementById(gSecondTestPermissionString + "RadioGroup");
let secondtestRadioDefault = gPageInfo.document.getElementById(gSecondTestPermissionString + "#0");
is(secondtestRadioGroup.selectedItem, secondtestRadioDefault, "part 3: Second Test radio group should be set to 'Default'");
doOnPageLoad(gHttpTestRoot + "plugin_two_types.html", testPart4a);
}
// Now test that setting permission directly (as from the popup notification)
// immediately influences Page Info.
function testPart4a() {
// simulate "allow" from the doorhanger
gPermissionManager.add(gTestBrowser.currentURI, gTestPermissionString, Ci.nsIPermissionManager.ALLOW_ACTION);
gPermissionManager.add(gTestBrowser.currentURI, gSecondTestPermissionString, Ci.nsIPermissionManager.ALLOW_ACTION);
// check (again) that changing the permissions affects the radio state in the
// open Page Info window
let testRadioGroup = gPageInfo.document.getElementById(gTestPermissionString + "RadioGroup");
let testRadioAllow = gPageInfo.document.getElementById(gTestPermissionString + "#1");
is(testRadioGroup.selectedItem, testRadioAllow, "part 4a: Test radio group should be set to 'Allow'");
let secondtestRadioGroup = gPageInfo.document.getElementById(gSecondTestPermissionString + "RadioGroup");
let secondtestRadioAllow = gPageInfo.document.getElementById(gSecondTestPermissionString + "#1");
is(secondtestRadioGroup.selectedItem, secondtestRadioAllow, "part 4a: Second Test radio group should be set to 'Always Allow'");
// now close Page Info and see that it opens with the right settings
gPageInfo.close();
doOnOpenPageInfo(testPart4b);
}
// check that "always allow" resulted in the radio buttons getting set to allow
function testPart4b() {
let testRadioGroup = gPageInfo.document.getElementById(gTestPermissionString + "RadioGroup");
let testRadioAllow = gPageInfo.document.getElementById(gTestPermissionString + "#1");
is(testRadioGroup.selectedItem, testRadioAllow, "part 4b: Test radio group should be set to 'Allow'");
let secondtestRadioGroup = gPageInfo.document.getElementById(gSecondTestPermissionString + "RadioGroup");
let secondtestRadioAllow = gPageInfo.document.getElementById(gSecondTestPermissionString + "#1");
is(secondtestRadioGroup.selectedItem, secondtestRadioAllow, "part 4b: Second Test radio group should be set to 'Allow'");
Services.prefs.setBoolPref("plugins.click_to_play", false);
gPageInfo.close();
finishTest();
}
@@ -200,7 +200,7 @@ Site.prototype = {
* e.g. "cookie", "geo", "indexedDB", "popup", "image"
*/
clearPermission: function Site_clearPermission(aType) {
Services.perms.remove(this.host, aType);
Services.perms.remove(this.httpURI, aType);
},
/**
+13 -8
View File
@@ -377,7 +377,7 @@ var gAdvancedPane = {
},
// XXX: duplicated in browser.js
_getOfflineAppUsage: function (host, groups)
_getOfflineAppUsage: function (perm, groups)
{
var cacheService = Components.classes["@mozilla.org/network/application-cache-service;1"].
getService(Components.interfaces.nsIApplicationCacheService);
@@ -390,7 +390,7 @@ var gAdvancedPane = {
var usage = 0;
for (var i = 0; i < groups.length; i++) {
var uri = ios.newURI(groups[i], null, null);
if (uri.asciiHost == host) {
if (uri.asciiHost == perm.host) {
var cache = cacheService.getActiveCache(groups[i]);
usage += cache.usage;
}
@@ -429,7 +429,7 @@ var gAdvancedPane = {
row.className = "offlineapp";
row.setAttribute("host", perm.host);
var converted = DownloadUtils.
convertByteUnits(this._getOfflineAppUsage(perm.host, groups));
convertByteUnits(this._getOfflineAppUsage(perm, groups));
row.setAttribute("usage",
bundle.getFormattedString("offlineAppUsage",
converted));
@@ -476,7 +476,7 @@ var gAdvancedPane = {
getService(Components.interfaces.nsIIOService);
var groups = cacheService.getGroups();
for (var i = 0; i < groups.length; i++) {
var uri = ios.newURI(groups[i], null, null);
let uri = ios.newURI(groups[i], null, null);
if (uri.asciiHost == host) {
var cache = cacheService.getActiveCache(groups[i]);
cache.discard();
@@ -486,10 +486,15 @@ var gAdvancedPane = {
// remove the permission
var pm = Components.classes["@mozilla.org/permissionmanager;1"]
.getService(Components.interfaces.nsIPermissionManager);
pm.remove(host, "offline-app",
Components.interfaces.nsIPermissionManager.ALLOW_ACTION);
pm.remove(host, "offline-app",
Components.interfaces.nsIOfflineCacheUpdateService.ALLOW_NO_WARN);
let uri;
try {
// file:// URIs are stored with their scheme. We try to parse them first, as
// URIs like http://file:///foo/bar/baz.html will parse as HTTP URIs.
uri = ios.newURI(host, null, null);
} catch (e) {
uri = ios.newURI("http://" + host, null, null);
}
pm.remove(uri, "offline-app");
list.removeChild(item);
gAdvancedPane.offlineAppSelected();
@@ -3,6 +3,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
Components.utils.import("resource://gre/modules/NetUtil.jsm");
const nsIPermissionManager = Components.interfaces.nsIPermissionManager;
const nsICookiePermission = Components.interfaces.nsICookiePermission;
@@ -83,9 +85,7 @@ var gPermissionManager = {
var textbox = document.getElementById("url");
var host = textbox.value.replace(/^\s*([-\w]*:\/+)?/, ""); // trim any leading space and scheme
try {
var ioService = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
var uri = ioService.newURI("http://"+host, null, null);
var uri = NetUtil.newURI("http://" + host);
host = uri.host;
} catch(ex) {
var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
@@ -112,7 +112,7 @@ var gPermissionManager = {
if (!exists) {
host = (host.charAt(0) == ".") ? host.substring(1,host.length) : host;
var uri = ioService.newURI("http://" + host, null, null);
var uri = NetUtil.newURI("http://" + host);
this._pm.add(uri, this._type, aCapability);
}
textbox.value = "";
@@ -257,7 +257,8 @@ var gPermissionManager = {
gTreeUtils.deleteSelectedItems(this._tree, this._view, this._permissions, removedPermissions);
for (var i = 0; i < removedPermissions.length; ++i) {
var p = removedPermissions[i];
this._pm.remove(p.host, p.type);
let uri = NetUtil.newURI("http://" + p.host);
this._pm.remove(uri, p.type);
}
document.getElementById("removePermission").disabled = !this._permissions.length;
document.getElementById("removeAllPermissions").disabled = !this._permissions.length;
@@ -0,0 +1,137 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
Components.utils.import("resource://gre/modules/NetUtil.jsm");
Components.utils.import("resource://gre/modules/ForgetAboutSite.jsm");
const ABOUT_PERMISSIONS_SPEC = "about:permissions";
const TEST_URI_1 = NetUtil.newURI("http://mozilla.com/");
const TEST_URI_2 = NetUtil.newURI("http://mozilla.org/");
const TEST_URI_3 = NetUtil.newURI("http://wikipedia.org/");
// values from DefaultPermissions object
const PERM_UNKNOWN = 0;
const PERM_ALLOW = 1;
const PERM_DENY = 2;
// used to set permissions on test sites
const TEST_PERMS = {
"password": PERM_ALLOW,
"cookie": PERM_ALLOW,
"geo": PERM_UNKNOWN,
"indexedDB": PERM_UNKNOWN,
"popup": PERM_DENY
};
function test() {
waitForExplicitFinish();
registerCleanupFunction(cleanUp);
setup(function() {
runNextTest();
});
}
function setup(aCallback) {
// add test history visit
PlacesTestUtils.addVisits(TEST_URI_1).then(() => {
// set permissions ourselves to avoid problems with different defaults
// from test harness configuration
for (let type in TEST_PERMS) {
if (type == "password") {
Services.logins.setLoginSavingEnabled(TEST_URI_2.prePath, true);
} else {
// set permissions on a site without history visits to test enumerateServices
Services.perms.add(TEST_URI_2, type, TEST_PERMS[type]);
}
}
Services.perms.add(TEST_URI_3, "popup", TEST_PERMS["popup"]);
aCallback();
});
}
function cleanUp() {
for (let type in TEST_PERMS) {
if (type != "password") {
Services.perms.remove(TEST_URI_1, type);
Services.perms.remove(TEST_URI_2, type);
Services.perms.remove(TEST_URI_3, type);
}
}
}
function runNextTest() {
if (gTestIndex == tests.length) {
PlacesTestUtils.clearHistory().then(finish);
return;
}
let nextTest = tests[gTestIndex++];
info(nextTest.desc);
function preinit_observer() {
Services.obs.removeObserver(preinit_observer, "browser-permissions-preinit");
nextTest.preInit();
}
Services.obs.addObserver(preinit_observer, "browser-permissions-preinit", false);
function init_observer() {
Services.obs.removeObserver(init_observer, "browser-permissions-initialized");
nextTest.run();
}
Services.obs.addObserver(init_observer, "browser-permissions-initialized", false);
// open about:permissions
let tab = gBrowser.selectedTab = gBrowser.addTab("about:permissions");
registerCleanupFunction(function() {
gBrowser.removeTab(tab);
});
}
var gSitesList;
var gTestIndex = 0;
var tests = [
// 'preInit' occurs after opening about:permissions, before sites-list is populated
// 'run' occurs after sites-list is populated
{
desc: "test filtering before sites-list is fully constructed.",
preInit: function() {
let sitesFilter = gBrowser.contentDocument.getElementById("sites-filter");
sitesFilter.value = TEST_URI_2.host;
sitesFilter.doCommand();
},
run: function() {
let testSite1 = getSiteItem(TEST_URI_1.host);
ok(testSite1.collapsed, "test site 1 is collapsed after early filtering");
let testSite2 = getSiteItem(TEST_URI_2.host);
ok(!testSite2.collapsed, "test site 2 is not collapsed after early filtering");
let testSite3 = getSiteItem(TEST_URI_3.host);
ok(testSite3.collapsed, "test site 3 is collapsed after early filtering");
runNextTest();
}
},
{
desc: "test removing from sites-list before it is fully constructed.",
preInit: function() {
ForgetAboutSite.removeDataFromDomain(TEST_URI_2.host);
},
run: function() {
let testSite1 = getSiteItem(TEST_URI_1.host);
ok(testSite1, "test site 1 was not removed from sites list");
let testSite2 = getSiteItem(TEST_URI_2.host);
ok(!testSite2, "test site 2 was pre-removed from sites list");
let testSite3 = getSiteItem(TEST_URI_3.host);
ok(testSite3, "test site 3 was not removed from sites list");
runNextTest();
}
}
];
function getSiteItem(aHost) {
return gBrowser.contentDocument.
querySelector(".site[value='" + aHost + "']");
}
@@ -0,0 +1,201 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
waitForExplicitFinish();
testRunner.runTests();
}
var testRunner = {
tests:
[
{
test: function(params) {
params.url.value = "test.com";
params.btnAllow.doCommand();
is(params.tree.view.rowCount, 1, "added exception shows up in treeview");
is(params.tree.view.getCellText(0, params.statusCol), params.allowText,
"permission text should be set correctly");
params.btnApplyChanges.doCommand();
},
observances: [{ type: "cookie", host: "test.com", data: "added",
capability: Ci.nsIPermissionManager.ALLOW_ACTION }],
},
{
test: function(params) {
params.url.value = "test.com";
params.btnBlock.doCommand();
is(params.tree.view.getCellText(0, params.statusCol), params.denyText,
"permission should change to deny in UI");
params.btnApplyChanges.doCommand();
},
observances: [{ type: "cookie", host: "test.com", data: "changed",
capability: Ci.nsIPermissionManager.DENY_ACTION }],
},
{
test: function(params) {
params.url.value = "test.com";
params.btnAllow.doCommand();
is(params.tree.view.getCellText(0, params.statusCol), params.allowText,
"permission should revert back to allow");
params.btnApplyChanges.doCommand();
},
observances: [{ type: "cookie", host: "test.com", data: "changed",
capability: Ci.nsIPermissionManager.ALLOW_ACTION }],
},
{
test: function(params) {
params.url.value = "test.com";
params.btnRemove.doCommand();
is(params.tree.view.rowCount, 0, "exception should be removed");
params.btnApplyChanges.doCommand();
},
observances: [{ type: "cookie", host: "test.com", data: "deleted" }],
},
{
test: function(params) {
let uri = params.ioService.newURI("http://test.com", null, null);
params.pm.add(uri, "popup", Ci.nsIPermissionManager.DENY_ACTION);
is(params.tree.view.rowCount, 0, "adding unrelated permission should not change display");
params.btnApplyChanges.doCommand();
},
observances: [{ type: "popup", host: "test.com", data: "added",
capability: Ci.nsIPermissionManager.DENY_ACTION }],
cleanUp: function(params) {
let uri = params.ioService.newURI("http://test.com", null, null);
params.pm.remove(uri, "popup");
},
},
],
_currentTest: -1,
runTests: function() {
this._currentTest++;
info("Running test #" + (this._currentTest + 1) + "\n");
let that = this;
let p = this.runCurrentTest();
p.then(function() {
if (that._currentTest == that.tests.length - 1) {
finish();
}
else {
that.runTests();
}
});
},
runCurrentTest: function() {
return new Promise(function(resolve, reject) {
let helperFunctions = {
prefWindowObserver: function(subject, topic, data) {
if (topic != "domwindowopened")
return;
Services.ww.unregisterNotification(helperFunctions.prefWindowObserver);
let win = subject.QueryInterface(Ci.nsIDOMEventTarget);
win.addEventListener("load", function(event) {
let historyMode = event.target.getElementById("historyMode");
historyMode.value = "custom";
historyMode.doCommand();
Services.ww.registerNotification(helperFunctions.cookiesWindowObserver);
event.target.getElementById("cookieExceptions").doCommand();
}, false);
},
cookiesWindowObserver: function(subject, topic, data) {
if (topic != "domwindowopened")
return;
Services.ww.unregisterNotification(helperFunctions.cookiesWindowObserver);
let win = subject.QueryInterface(Ci.nsIDOMEventTarget);
win.addEventListener("load", function(event) {
SimpleTest.executeSoon(function() helperFunctions.windowLoad(event, win));
}, false);
},
windowLoad: function(event, win) {
let params = {
doc: event.target,
tree: event.target.getElementById("permissionsTree"),
statusCol: event.target.getElementById("permissionsTree").treeBoxObject.columns.getColumnAt(1),
url: event.target.getElementById("url"),
btnAllow: event.target.getElementById("btnAllow"),
btnBlock: event.target.getElementById("btnBlock"),
btnApplyChanges: event.target.getElementById("btnApplyChanges"),
btnRemove: event.target.getElementById("removePermission"),
pm: Cc["@mozilla.org/permissionmanager;1"]
.getService(Ci.nsIPermissionManager),
ioService: Cc["@mozilla.org/network/io-service;1"]
.getService(Ci.nsIIOService),
allowText: win.gPermissionManager._getCapabilityString(
Ci.nsIPermissionManager.ALLOW_ACTION),
denyText: win.gPermissionManager._getCapabilityString(
Ci.nsIPermissionManager.DENY_ACTION),
allow: Ci.nsIPermissionManager.ALLOW_ACTION,
deny: Ci.nsIPermissionManager.DENY_ACTION,
};
let permObserver = {
observe: function(aSubject, aTopic, aData) {
if (aTopic != "perm-changed")
return;
if (testRunner.tests[testRunner._currentTest].observances.length == 0) {
// Should fail here as we are not expecting a notification, but we don't.
// See bug 1063410.
return;
}
let permission = aSubject.QueryInterface(Ci.nsIPermission);
let expected = testRunner.tests[testRunner._currentTest].observances.shift();
is(aData, expected.data, "type of message should be the same");
for each (let prop in ["type", "host", "capability"]) {
if (expected[prop])
is(permission[prop], expected[prop],
"property: \"" + prop + "\" should be equal");
}
os.removeObserver(permObserver, "perm-changed");
if (testRunner.tests[testRunner._currentTest].cleanup) {
testRunner.tests[testRunner._currentTest].cleanup();
}
testRunner.dialog.close(params);
win.close();
resolve();
},
};
let os = Cc["@mozilla.org/observer-service;1"]
.getService(Ci.nsIObserverService);
os.addObserver(permObserver, "perm-changed", false);
if (testRunner._currentTest == 0) {
is(params.tree.view.rowCount, 0, "no cookie exceptions");
}
testRunner.tests[testRunner._currentTest].test(params);
},
};
Services.ww.registerNotification(helperFunctions.prefWindowObserver);
testRunner.dialog = openDialog("chrome://browser/content/preferences/preferences.xul",
"Preferences", "chrome,titlebar,toolbar,centerscreen,dialog=no",
"panePrivacy");
});
},
};
@@ -0,0 +1,313 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// tests the translation infobar, using a fake 'Translation' implementation.
let tmp = {};
Cu.import("resource:///modules/translation/Translation.jsm", tmp);
Cu.import("resource://gre/modules/Promise.jsm", tmp);
let {Translation, Promise} = tmp;
const kLanguagesPref = "browser.translation.neverForLanguages";
const kShowUIPref = "browser.translation.ui.show";
function test() {
waitForExplicitFinish();
Services.prefs.setBoolPref(kShowUIPref, true);
let tab = gBrowser.addTab();
gBrowser.selectedTab = tab;
registerCleanupFunction(function () {
gBrowser.removeTab(tab);
Services.prefs.clearUserPref(kShowUIPref);
});
tab.linkedBrowser.addEventListener("load", function onload() {
tab.linkedBrowser.removeEventListener("load", onload, true);
Task.spawn(function* () {
for (let test of gTests) {
info(test.desc);
yield test.run();
}
}).then(finish, ex => {
ok(false, "Unexpected Exception: " + ex);
finish();
});
}, true);
content.location = "http://example.com/";
}
function getLanguageExceptions() {
let langs = Services.prefs.getCharPref(kLanguagesPref);
return langs ? langs.split(",") : [];
}
function getDomainExceptions() {
let results = [];
let enumerator = Services.perms.enumerator;
while (enumerator.hasMoreElements()) {
let perm = enumerator.getNext().QueryInterface(Ci.nsIPermission);
if (perm.type == "translate" &&
perm.capability == Services.perms.DENY_ACTION)
results.push(perm.host);
}
return results;
}
function getInfoBar() {
return gBrowser.getNotificationBox().getNotificationWithValue("translation");
}
function openPopup(aPopup) {
let deferred = Promise.defer();
aPopup.addEventListener("popupshown", function popupShown() {
aPopup.removeEventListener("popupshown", popupShown);
deferred.resolve();
});
aPopup.focus();
// One down event to open the popup.
EventUtils.synthesizeKey("VK_DOWN",
{ altKey: !navigator.platform.includes("Mac") });
return deferred.promise;
}
function waitForWindowLoad(aWin) {
let deferred = Promise.defer();
aWin.addEventListener("load", function onload() {
aWin.removeEventListener("load", onload, true);
deferred.resolve();
}, true);
return deferred.promise;
}
let gTests = [
{
desc: "clean exception lists at startup",
run: function checkNeverForLanguage() {
is(getLanguageExceptions().length, 0,
"we start with an empty list of languages to never translate");
is(getDomainExceptions().length, 0,
"we start with an empty list of sites to never translate");
}
},
{
desc: "never for language",
run: function* checkNeverForLanguage() {
// Show the infobar for example.com and fr.
Translation.documentStateReceived(gBrowser.selectedBrowser,
{state: Translation.STATE_OFFER,
originalShown: true,
detectedLanguage: "fr"});
let notif = getInfoBar();
ok(notif, "the infobar is visible");
let ui = gBrowser.selectedBrowser.translationUI;
let uri = gBrowser.selectedBrowser.currentURI;
ok(ui.shouldShowInfoBar(uri, "fr"),
"check shouldShowInfoBar initially returns true");
// Open the "options" drop down.
yield openPopup(notif._getAnonElt("options"));
ok(notif._getAnonElt("options").getAttribute("open"),
"the options menu is open");
// Check that the item is not disabled.
ok(!notif._getAnonElt("neverForLanguage").disabled,
"The 'Never translate <language>' item isn't disabled");
// Click the 'Never for French' item.
notif._getAnonElt("neverForLanguage").click();
ok(!getInfoBar(), "infobar hidden");
// Check this has been saved to the exceptions list.
let langs = getLanguageExceptions();
is(langs.length, 1, "one language in the exception list");
is(langs[0], "fr", "correct language in the exception list");
ok(!ui.shouldShowInfoBar(uri, "fr"),
"the infobar wouldn't be shown anymore");
// Reopen the infobar.
PopupNotifications.getNotification("translate").anchorElement.click();
notif = getInfoBar();
// Open the "options" drop down.
yield openPopup(notif._getAnonElt("options"));
ok(notif._getAnonElt("neverForLanguage").disabled,
"The 'Never translate French' item is disabled");
// Cleanup.
Services.prefs.setCharPref(kLanguagesPref, "");
notif.close();
}
},
{
desc: "never for site",
run: function* checkNeverForSite() {
// Show the infobar for example.com and fr.
Translation.documentStateReceived(gBrowser.selectedBrowser,
{state: Translation.STATE_OFFER,
originalShown: true,
detectedLanguage: "fr"});
let notif = getInfoBar();
ok(notif, "the infobar is visible");
let ui = gBrowser.selectedBrowser.translationUI;
let uri = gBrowser.selectedBrowser.currentURI;
ok(ui.shouldShowInfoBar(uri, "fr"),
"check shouldShowInfoBar initially returns true");
// Open the "options" drop down.
yield openPopup(notif._getAnonElt("options"));
ok(notif._getAnonElt("options").getAttribute("open"),
"the options menu is open");
// Check that the item is not disabled.
ok(!notif._getAnonElt("neverForSite").disabled,
"The 'Never translate site' item isn't disabled");
// Click the 'Never for French' item.
notif._getAnonElt("neverForSite").click();
ok(!getInfoBar(), "infobar hidden");
// Check this has been saved to the exceptions list.
let sites = getDomainExceptions();
is(sites.length, 1, "one site in the exception list");
is(sites[0], "example.com", "correct site in the exception list");
ok(!ui.shouldShowInfoBar(uri, "fr"),
"the infobar wouldn't be shown anymore");
// Reopen the infobar.
PopupNotifications.getNotification("translate").anchorElement.click();
notif = getInfoBar();
// Open the "options" drop down.
yield openPopup(notif._getAnonElt("options"));
ok(notif._getAnonElt("neverForSite").disabled,
"The 'Never translate French' item is disabled");
// Cleanup.
Services.perms.remove(makeURI("http://example.com"), "translate");
notif.close();
}
},
{
desc: "language exception list",
run: function* checkLanguageExceptions() {
// Put 2 languages in the pref before opening the window to check
// the list is displayed on load.
Services.prefs.setCharPref(kLanguagesPref, "fr,de");
// Open the translation exceptions dialog.
let win = openDialog("chrome://browser/content/preferences/translation.xul",
"Browser:TranslationExceptions",
"", null);
yield waitForWindowLoad(win);
// Check that the list of language exceptions is loaded.
let getById = win.document.getElementById.bind(win.document);
let tree = getById("languagesTree");
let remove = getById("removeLanguage");
let removeAll = getById("removeAllLanguages");
is(tree.view.rowCount, 2, "The language exceptions list has 2 items");
ok(remove.disabled, "The 'Remove Language' button is disabled");
ok(!removeAll.disabled, "The 'Remove All Languages' button is enabled");
// Select the first item.
tree.view.selection.select(0);
ok(!remove.disabled, "The 'Remove Language' button is enabled");
// Click the 'Remove' button.
remove.click();
is(tree.view.rowCount, 1, "The language exceptions now contains 1 item");
is(getLanguageExceptions().length, 1, "One exception in the pref");
// Clear the pref, and check the last item is removed from the display.
Services.prefs.setCharPref(kLanguagesPref, "");
is(tree.view.rowCount, 0, "The language exceptions list is empty");
ok(remove.disabled, "The 'Remove Language' button is disabled");
ok(removeAll.disabled, "The 'Remove All Languages' button is disabled");
// Add an item and check it appears.
Services.prefs.setCharPref(kLanguagesPref, "fr");
is(tree.view.rowCount, 1, "The language exceptions list has 1 item");
ok(remove.disabled, "The 'Remove Language' button is disabled");
ok(!removeAll.disabled, "The 'Remove All Languages' button is enabled");
// Click the 'Remove All' button.
removeAll.click();
is(tree.view.rowCount, 0, "The language exceptions list is empty");
ok(remove.disabled, "The 'Remove Language' button is disabled");
ok(removeAll.disabled, "The 'Remove All Languages' button is disabled");
is(Services.prefs.getCharPref(kLanguagesPref), "", "The pref is empty");
win.close();
}
},
{
desc: "domains exception list",
run: function* checkDomainExceptions() {
// Put 2 exceptions before opening the window to check the list is
// displayed on load.
let perms = Services.perms;
perms.add(makeURI("http://example.org"), "translate", perms.DENY_ACTION);
perms.add(makeURI("http://example.com"), "translate", perms.DENY_ACTION);
// Open the translation exceptions dialog.
let win = openDialog("chrome://browser/content/preferences/translation.xul",
"Browser:TranslationExceptions",
"", null);
yield waitForWindowLoad(win);
// Check that the list of language exceptions is loaded.
let getById = win.document.getElementById.bind(win.document);
let tree = getById("sitesTree");
let remove = getById("removeSite");
let removeAll = getById("removeAllSites");
is(tree.view.rowCount, 2, "The sites exceptions list has 2 items");
ok(remove.disabled, "The 'Remove Site' button is disabled");
ok(!removeAll.disabled, "The 'Remove All Sites' button is enabled");
// Select the first item.
tree.view.selection.select(0);
ok(!remove.disabled, "The 'Remove Site' button is enabled");
// Click the 'Remove' button.
remove.click();
is(tree.view.rowCount, 1, "The site exceptions now contains 1 item");
is(getDomainExceptions().length, 1, "One exception in the permissions");
// Clear the permissions, and check the last item is removed from the display.
perms.remove(makeURI("http://example.org"), "translate");
perms.remove(makeURI("http://example.com"), "translate");
is(tree.view.rowCount, 0, "The site exceptions list is empty");
ok(remove.disabled, "The 'Remove Site' button is disabled");
ok(removeAll.disabled, "The 'Remove All Site' button is disabled");
// Add an item and check it appears.
perms.add(makeURI("http://example.com"), "translate", perms.DENY_ACTION);
is(tree.view.rowCount, 1, "The site exceptions list has 1 item");
ok(remove.disabled, "The 'Remove Site' button is disabled");
ok(!removeAll.disabled, "The 'Remove All Sites' button is enabled");
// Click the 'Remove All' button.
removeAll.click();
is(tree.view.rowCount, 0, "The site exceptions list is empty");
ok(remove.disabled, "The 'Remove Site' button is disabled");
ok(removeAll.disabled, "The 'Remove All Sites' button is disabled");
is(getDomainExceptions().length, 0, "No exceptions in the permissions");
win.close();
}
}
];
+2 -2
View File
@@ -93,7 +93,7 @@ this.SitePermissions = {
if (!this.isSupportedURI(aURI))
return;
Services.perms.remove(aURI.host, aPermissionID);
Services.perms.remove(aURI, aPermissionID);
if (aPermissionID in gPermissionObject &&
gPermissionObject[aPermissionID].onChange)
@@ -216,7 +216,7 @@ let gPermissionObject = {
},
onChange: function (aURI, aState) {
if (aState == SitePermissions.ALLOW || aState == SitePermissions.BLOCK)
Services.perms.remove(aURI.host, "indexedDB-unlimited");
Services.perms.remove(aURI, "indexedDB-unlimited");
}
},
+3 -9
View File
@@ -863,18 +863,12 @@ nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal,
}
}
// resource: and chrome: are equivalent, securitywise
// That's bogus!! Fix this. But watch out for
// the view-source stylesheet?
bool sourceIsChrome;
rv = NS_URIChainHasFlags(sourceURI,
nsIProtocolHandler::URI_IS_UI_RESOURCE,
&sourceIsChrome);
NS_ENSURE_SUCCESS(rv, rv);
if (sourceIsChrome) {
// Allow chrome://
if (sourceScheme.EqualsLiteral("chrome")) {
return NS_OK;
}
// Nothing else.
if (reportErrors) {
ReportError(nullptr, errorTag, sourceURI, aTargetURI);
}
+6
View File
@@ -48,6 +48,12 @@ if CONFIG['MOZ_JXR']:
if CONFIG['CPU_ARCH'] == 'arm':
external_dirs += ['media/openmax_dl']
if CONFIG['MOZ_WEBSPEECH_POCKETSPHINX']:
external_dirs += [
'media/sphinxbase',
'media/pocketsphinx',
]
external_dirs += [
'media/kiss_fft',
'media/libcubeb',
+43
View File
@@ -3793,6 +3793,9 @@ MOZ_NATIVE_LIBWEBP=
MOZ_VPX=
MOZ_VPX_ERROR_CONCEALMENT=
MOZ_WEBSPEECH=1
MOZ_WEBSPEECH_MODELS=
MOZ_WEBSPEECH_POCKETSPHINX=
MOZ_WEBSPEECH_TEST_BACKEND=1
MOZ_JXR=1
VPX_AS=
VPX_ASFLAGS=
@@ -4996,6 +4999,15 @@ else
AC_SUBST(MOZ_SAMPLE_TYPE_FLOAT32)
fi
dnl ========================================================
dnl = Disable Speech API pocketsphinx backend
dnl ========================================================
if test -n "$MOZ_WEBSPEECH_POCKETSPHINX"; then
AC_DEFINE(MOZ_WEBSPEECH_POCKETSPHINX)
fi
AC_SUBST(MOZ_WEBSPEECH_POCKETSPHINX)
dnl ========================================================
dnl = Disable Speech API code
dnl ========================================================
@@ -5010,6 +5022,37 @@ fi
AC_SUBST(MOZ_WEBSPEECH)
dnl ========================================================
dnl = Disable Speech API test backend
dnl ========================================================
MOZ_ARG_DISABLE_BOOL(webspeechtestbackend,
[ --disable-webspeechtestbackend Disable support for HTML Speech API Test Backend],
MOZ_WEBSPEECH_TEST_BACKEND=,
MOZ_WEBSPEECH_TEST_BACKEND=1)
if test -z "$MOZ_WEBSPEECH"; then
MOZ_WEBSPEECH_TEST_BACKEND=
fi
if test -n "$MOZ_WEBSPEECH_TEST_BACKEND"; then
AC_DEFINE(MOZ_WEBSPEECH_TEST_BACKEND)
fi
AC_SUBST(MOZ_WEBSPEECH_TEST_BACKEND)
dnl ========================================================
dnl = Disable Speech API models
dnl ========================================================
if test -z "$MOZ_WEBSPEECH"; then
MOZ_WEBSPEECH_MODELS=
fi
if test -n "$MOZ_WEBSPEECH_MODELS"; then
AC_DEFINE(MOZ_WEBSPEECH_MODELS)
fi
AC_SUBST(MOZ_WEBSPEECH_MODELS)
dnl ========================================================
dnl = Disable JPEG-XR (JXR) decoder support
dnl ========================================================
+51 -1
View File
@@ -6,6 +6,7 @@
/* static functions */
const DEBUG = false;
const REQUEST_CPU_LOCK_TIMEOUT = 10 * 1000; // 10 seconds.
function debug(aStr) {
if (DEBUG)
@@ -18,8 +19,15 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "gPowerManagerService",
"@mozilla.org/power/powermanagerservice;1",
"nsIPowerManagerService");
function AlarmsManager() {
debug("Constructor");
// A <requestId, {cpuLock, timer}> map.
this._cpuLockDict = new Map();
}
AlarmsManager.prototype = {
@@ -71,8 +79,10 @@ AlarmsManager.prototype = {
data = JSON.parse(Cu.evalInSandbox("JSON.stringify(data)", sandbox));
}
let request = this.createRequest();
let requestId = this.getRequestId(request);
this._lockCpuForRequest(requestId);
this._cpmm.sendAsyncMessage("AlarmsManager:Add",
{ requestId: this.getRequestId(request),
{ requestId: requestId,
date: aDate,
ignoreTimezone: isIgnoreTimezone,
data: data,
@@ -111,6 +121,7 @@ AlarmsManager.prototype = {
switch (aMessage.name) {
case "AlarmsManager:Add:Return:OK":
this._unlockCpuForRequest(json.requestId);
Services.DOMRequest.fireSuccess(request, json.id);
break;
@@ -131,6 +142,7 @@ AlarmsManager.prototype = {
break;
case "AlarmsManager:Add:Return:KO":
this._unlockCpuForRequest(json.requestId);
Services.DOMRequest.fireError(request, json.errorMsg);
break;
@@ -172,6 +184,44 @@ AlarmsManager.prototype = {
uninit: function uninit() {
debug("uninit()");
},
_lockCpuForRequest: function (aRequestId) {
if (this._cpuLockDict.has(aRequestId)) {
debug('Cpu wakelock for request ' + aRequestId + ' has been acquired. ' +
'You may call this function repeatedly or requestId is collision.');
return;
}
// Acquire a lock for given request and save for lookup lately.
debug('Acquire cpu lock for request ' + aRequestId);
let cpuLockInfo = {
cpuLock: gPowerManagerService.newWakeLock("cpu"),
timer: Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer)
};
this._cpuLockDict.set(aRequestId, cpuLockInfo);
// Start a timer to prevent from non-responding request.
cpuLockInfo.timer.initWithCallback(() => {
debug('Request timeout! Release the cpu lock');
this._unlockCpuForRequest(aRequestId);
}, REQUEST_CPU_LOCK_TIMEOUT, Ci.nsITimer.TYPE_ONE_SHOT);
},
_unlockCpuForRequest: function(aRequestId) {
let cpuLockInfo = this._cpuLockDict.get(aRequestId);
if (!cpuLockInfo) {
debug('The cpu lock for requestId ' + aRequestId + ' is either invalid ' +
'or has been released.');
return;
}
// Release the cpu lock and cancel the timer.
debug('Release the cpu lock for ' + aRequestId);
cpuLockInfo.cpuLock.unlock();
cpuLockInfo.timer.cancel();
this._cpuLockDict.delete(aRequestId);
},
}
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([AlarmsManager])
+4 -2
View File
@@ -69,6 +69,7 @@ EventSource::EventSource(nsPIDOMWindow* aOwnerWindow) :
mLastConvertionResult(NS_OK),
mReadyState(CONNECTING),
mScriptLine(0),
mScriptColumn(0),
mInnerWindowID(0)
{
}
@@ -205,7 +206,8 @@ EventSource::Init(nsISupports* aOwner,
// The conditional here is historical and not necessarily sane.
if (JSContext *cx = nsContentUtils::GetCurrentJSContext()) {
nsJSUtils::GetCallingLocation(cx, mScriptFile, &mScriptLine);
nsJSUtils::GetCallingLocation(cx, mScriptFile, &mScriptLine,
&mScriptColumn);
mInnerWindowID = nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(cx);
}
@@ -997,7 +999,7 @@ EventSource::PrintErrorOnConsole(const char *aBundleURI,
rv = errObj->InitWithWindowID(message,
mScriptFile,
EmptyString(),
mScriptLine, 0,
mScriptLine, mScriptColumn,
nsIScriptError::errorFlag,
"Event Source", mInnerWindowID);
NS_ENSURE_SUCCESS(rv, rv);
+3 -1
View File
@@ -255,12 +255,14 @@ protected:
// Event Source owner information:
// - the script file name
// - source code line number where the Event Source object was constructed.
// - source code line number and column number where the Event Source object
// was constructed.
// - the ID of the inner window where the script lives. Note that this may not
// be the same as the Event Source owner window.
// These attributes are used for error reporting.
nsString mScriptFile;
uint32_t mScriptLine;
uint32_t mScriptColumn;
uint64_t mInnerWindowID;
private:
+23 -11
View File
@@ -94,6 +94,7 @@ public:
, mCloseEventWasClean(false)
, mCloseEventCode(nsIWebSocketChannel::CLOSE_ABNORMAL)
, mScriptLine(0)
, mScriptColumn(0)
, mInnerWindowID(0)
, mWorkerPrivate(nullptr)
#ifdef DEBUG
@@ -123,6 +124,7 @@ public:
nsTArray<nsString>& aProtocolArray,
const nsACString& aScriptFile,
uint32_t aScriptLine,
uint32_t aScriptColumn,
ErrorResult& aRv,
bool* aConnectionFailed);
@@ -200,12 +202,14 @@ public:
// Web Socket owner information:
// - the script file name, UTF8 encoded.
// - source code line number where the Web Socket object was constructed.
// - source code line number and column number where the Web Socket object
// was constructed.
// - the ID of the inner window where the script lives. Note that this may not
// be the same as the Web Socket owner window.
// These attributes are used for error reporting.
nsCString mScriptFile;
uint32_t mScriptLine;
uint32_t mScriptColumn;
uint64_t mInnerWindowID;
WorkerPrivate* mWorkerPrivate;
@@ -373,13 +377,14 @@ WebSocketImpl::PrintErrorOnConsole(const char *aBundleURI,
if (mInnerWindowID) {
rv = errorObject->InitWithWindowID(message,
NS_ConvertUTF8toUTF16(mScriptFile),
EmptyString(), mScriptLine, 0,
EmptyString(), mScriptLine,
mScriptColumn,
nsIScriptError::errorFlag, "Web Socket",
mInnerWindowID);
} else {
rv = errorObject->Init(message,
NS_ConvertUTF8toUTF16(mScriptFile),
EmptyString(), mScriptLine, 0,
EmptyString(), mScriptLine, mScriptColumn,
nsIScriptError::errorFlag, "Web Socket");
}
@@ -1080,6 +1085,7 @@ public:
InitRunnable(WebSocketImpl* aImpl, const nsAString& aURL,
nsTArray<nsString>& aProtocolArray,
const nsACString& aScriptFile, uint32_t aScriptLine,
uint32_t aScriptColumn,
ErrorResult& aRv, bool* aConnectionFailed)
: WebSocketMainThreadRunnable(aImpl->mWorkerPrivate)
, mImpl(aImpl)
@@ -1087,6 +1093,7 @@ public:
, mProtocolArray(aProtocolArray)
, mScriptFile(aScriptFile)
, mScriptLine(aScriptLine)
, mScriptColumn(aScriptColumn)
, mRv(aRv)
, mConnectionFailed(aConnectionFailed)
{
@@ -1118,7 +1125,7 @@ protected:
}
mImpl->Init(jsapi.cx(), principal, mURL, mProtocolArray, mScriptFile,
mScriptLine, mRv, mConnectionFailed);
mScriptLine, mScriptColumn, mRv, mConnectionFailed);
return true;
}
@@ -1128,7 +1135,7 @@ protected:
MOZ_ASSERT(aTopLevelWorkerPrivate && !aTopLevelWorkerPrivate->GetWindow());
mImpl->Init(nullptr, aTopLevelWorkerPrivate->GetPrincipal(), mURL,
mProtocolArray, mScriptFile, mScriptLine, mRv,
mProtocolArray, mScriptFile, mScriptLine, mScriptColumn, mRv,
mConnectionFailed);
return true;
}
@@ -1140,6 +1147,7 @@ protected:
nsTArray<nsString>& mProtocolArray;
nsCString mScriptFile;
uint32_t mScriptLine;
uint32_t mScriptColumn;
ErrorResult& mRv;
bool* mConnectionFailed;
};
@@ -1261,7 +1269,7 @@ WebSocket::Constructor(const GlobalObject& aGlobal,
if (NS_IsMainThread()) {
webSocket->mImpl->Init(aGlobal.Context(), principal, aUrl, protocolArray,
EmptyCString(), 0, aRv, &connectionFailed);
EmptyCString(), 0, 0, aRv, &connectionFailed);
} else {
// In workers we have to keep the worker alive using a feature in order to
// dispatch messages correctly.
@@ -1270,15 +1278,16 @@ WebSocket::Constructor(const GlobalObject& aGlobal,
return nullptr;
}
unsigned lineno;
unsigned lineno, column;
JS::AutoFilename file;
if (!JS::DescribeScriptedCaller(aGlobal.Context(), &file, &lineno)) {
if (!JS::DescribeScriptedCaller(aGlobal.Context(), &file, &lineno,
&column)) {
NS_WARNING("Failed to get line number and filename in workers.");
}
nsRefPtr<InitRunnable> runnable =
new InitRunnable(webSocket->mImpl, aUrl, protocolArray,
nsAutoCString(file.get()), lineno, aRv,
nsAutoCString(file.get()), lineno, column, aRv,
&connectionFailed);
runnable->Dispatch(aGlobal.Context());
}
@@ -1439,6 +1448,7 @@ WebSocketImpl::Init(JSContext* aCx,
nsTArray<nsString>& aProtocolArray,
const nsACString& aScriptFile,
uint32_t aScriptLine,
uint32_t aScriptColumn,
ErrorResult& aRv,
bool* aConnectionFailed)
{
@@ -1478,14 +1488,16 @@ WebSocketImpl::Init(JSContext* aCx,
if (mWorkerPrivate) {
mScriptFile = aScriptFile;
mScriptLine = aScriptLine;
mScriptColumn = aScriptColumn;
} else {
MOZ_ASSERT(aCx);
unsigned lineno;
unsigned lineno, column;
JS::AutoFilename file;
if (JS::DescribeScriptedCaller(aCx, &file, &lineno)) {
if (JS::DescribeScriptedCaller(aCx, &file, &lineno, &column)) {
mScriptFile = file.get();
mScriptLine = lineno;
mScriptColumn = column;
}
}
+1 -1
View File
@@ -3492,7 +3492,7 @@ nsContentUtils::ReportToConsoleNonLocalized(const nsAString& aErrorText,
if (!aLineNumber) {
JSContext *cx = GetCurrentJSContext();
if (cx) {
nsJSUtils::GetCallingLocation(cx, spec, &aLineNumber);
nsJSUtils::GetCallingLocation(cx, spec, &aLineNumber, &aColumnNumber);
}
}
if (spec.IsEmpty() && aURI)
+6 -2
View File
@@ -155,7 +155,6 @@ nsFrameLoader::nsFrameLoader(Element* aOwner, bool aNetworkCreated)
, mObservingOwnerContent(false)
, mVisible(true)
{
ResetPermissionManagerStatus();
mRemoteFrame = ShouldUseRemoteProcess();
}
@@ -395,6 +394,9 @@ nsFrameLoader::ReallyStartLoadingInternal()
mURIToLoad = nullptr;
NS_ENSURE_SUCCESS(rv, rv);
// Track the appId's reference count if this frame is in-process
ResetPermissionManagerStatus();
return NS_OK;
}
@@ -2663,7 +2665,9 @@ nsFrameLoader::ResetPermissionManagerStatus()
{
// The resetting of the permissions status can run only
// in the main process.
if (XRE_IsContentProcess()) {
// only in-main-process && in-process frame is handled here and all other
// cases are handled by ContentParent.
if (XRE_IsContentProcess() || mRemoteFrame) {
return;
}
+15 -2
View File
@@ -643,16 +643,29 @@ JSONCreator(const char16_t* aBuf, uint32_t aLen, void* aData)
static bool
GetParamsForMessage(JSContext* aCx,
const JS::Value& aJSON,
const JS::Value& aData,
JSAutoStructuredCloneBuffer& aBuffer,
StructuredCloneClosure& aClosure)
{
JS::Rooted<JS::Value> v(aCx, aJSON);
// First try to use structured clone on the whole thing.
JS::RootedValue v(aCx, aData);
if (WriteStructuredClone(aCx, v, aBuffer, aClosure)) {
return true;
}
JS_ClearPendingException(aCx);
nsCOMPtr<nsIConsoleService> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
if (console) {
nsAutoString filename;
uint32_t lineno = 0, column = 0;
nsJSUtils::GetCallingLocation(aCx, filename, &lineno, &column);
nsCOMPtr<nsIScriptError> error(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
error->Init(NS_LITERAL_STRING("Sending message that cannot be cloned. Are you trying to send an XPCOM object?"),
filename, EmptyString(), lineno, column,
nsIScriptError::warningFlag, "chrome javascript");
console->LogMessage(error);
}
// Not clonable, try JSON
//XXX This is ugly but currently structured cloning doesn't handle
// properly cases when interface is implemented in JS and used
+20 -13
View File
@@ -2378,6 +2378,17 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
jsapi.Init();
JSContext *cx = jsapi.cx();
// Check if we're anywhere near the stack limit before we reach the
// transplanting code, since it has no good way to handle errors. This uses
// the untrusted script limit, which is not strictly necessary since no
// actual script should run.
bool overrecursed = false;
JS_CHECK_RECURSION_CONSERVATIVE_DONT_REPORT(cx, overrecursed = true);
if (overrecursed) {
NS_WARNING("Overrecursion in SetNewDocument");
return NS_ERROR_FAILURE;
}
if (!mDoc) {
// First document load.
@@ -2434,12 +2445,6 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
bool thisChrome = IsChromeWindow();
// Check if we're anywhere near the stack limit before we reach the
// transplanting code, since it has no good way to handle errors. This uses
// the untrusted script limit, which is not strictly necessary since no
// actual script should run.
JS_CHECK_RECURSION_CONSERVATIVE(cx, return NS_ERROR_FAILURE);
nsCOMPtr<WindowStateHolder> wsh = do_QueryInterface(aState);
NS_ASSERTION(!aState || wsh, "What kind of weird state are you giving me here?");
@@ -12109,7 +12114,8 @@ nsGlobalWindow::SetTimeout(JSContext* aCx, Function& aFunction,
const Sequence<JS::Value>& aArguments,
ErrorResult& aError)
{
return SetTimeoutOrInterval(aFunction, aTimeout, aArguments, false, aError);
return SetTimeoutOrInterval(aCx, aFunction, aTimeout, aArguments, false,
aError);
}
int32_t
@@ -12143,7 +12149,7 @@ nsGlobalWindow::SetInterval(JSContext* aCx, Function& aFunction,
{
int32_t timeout;
bool isInterval = IsInterval(aTimeout, timeout);
return SetTimeoutOrInterval(aFunction, timeout, aArguments, isInterval,
return SetTimeoutOrInterval(aCx, aFunction, timeout, aArguments, isInterval,
aError);
}
@@ -12285,7 +12291,8 @@ nsGlobalWindow::SetTimeoutOrInterval(nsIScriptTimeoutHandler *aHandler,
}
int32_t
nsGlobalWindow::SetTimeoutOrInterval(Function& aFunction, int32_t aTimeout,
nsGlobalWindow::SetTimeoutOrInterval(JSContext *aCx, Function& aFunction,
int32_t aTimeout,
const Sequence<JS::Value>& aArguments,
bool aIsInterval, ErrorResult& aError)
{
@@ -12295,12 +12302,12 @@ nsGlobalWindow::SetTimeoutOrInterval(Function& aFunction, int32_t aTimeout,
}
if (inner != this) {
return inner->SetTimeoutOrInterval(aFunction, aTimeout, aArguments,
return inner->SetTimeoutOrInterval(aCx, aFunction, aTimeout, aArguments,
aIsInterval, aError);
}
nsCOMPtr<nsIScriptTimeoutHandler> handler =
NS_CreateJSTimeoutHandler(this, aFunction, aArguments, aError);
NS_CreateJSTimeoutHandler(aCx, this, aFunction, aArguments, aError);
if (!handler) {
return 0;
}
@@ -12382,8 +12389,8 @@ nsGlobalWindow::RunTimeoutHandler(nsTimeout* aTimeout,
NS_ASSERTION(script, "timeout has no script nor handler text!");
const char* filename = nullptr;
uint32_t lineNo = 0;
handler->GetLocation(&filename, &lineNo);
uint32_t lineNo = 0, dummyColumn = 0;
handler->GetLocation(&filename, &lineNo, &dummyColumn);
// New script entry point required, due to the "Create a script" sub-step of
// http://www.whatwg.org/specs/web-apps/current-work/#timer-initialisation-steps
+3 -2
View File
@@ -130,7 +130,7 @@ class VRHMDInfo;
} // namespace mozilla
extern already_AddRefed<nsIScriptTimeoutHandler>
NS_CreateJSTimeoutHandler(nsGlobalWindow *aWindow,
NS_CreateJSTimeoutHandler(JSContext* aCx, nsGlobalWindow *aWindow,
mozilla::dom::Function& aFunction,
const mozilla::dom::Sequence<JS::Value>& aArguments,
mozilla::ErrorResult& aError);
@@ -1390,7 +1390,8 @@ public:
nsresult SetTimeoutOrInterval(nsIScriptTimeoutHandler *aHandler,
int32_t interval,
bool aIsInterval, int32_t* aReturn) override;
int32_t SetTimeoutOrInterval(mozilla::dom::Function& aFunction,
int32_t SetTimeoutOrInterval(JSContext* aCx,
mozilla::dom::Function& aFunction,
int32_t aTimeout,
const mozilla::dom::Sequence<JS::Value>& aArguments,
bool aIsInterval, mozilla::ErrorResult& aError);
+2 -1
View File
@@ -39,7 +39,8 @@ public:
// Get the location of the script.
// Note: The memory pointed to by aFileName is owned by the
// nsIScriptTimeoutHandler and should not be freed by the caller.
virtual void GetLocation(const char **aFileName, uint32_t *aLineNo) = 0;
virtual void GetLocation(const char **aFileName, uint32_t *aLineNo,
uint32_t *aColumn) = 0;
// If we have a Function, get the arguments for passing to it.
virtual const nsTArray<JS::Value>& GetArgs() = 0;
+28 -14
View File
@@ -35,7 +35,8 @@ public:
nsJSScriptTimeoutHandler();
// This will call SwapElements on aArguments with an empty array.
nsJSScriptTimeoutHandler(nsGlobalWindow *aWindow, Function& aFunction,
nsJSScriptTimeoutHandler(JSContext* aCx, nsGlobalWindow *aWindow,
Function& aFunction,
FallibleTArray<JS::Heap<JS::Value> >& aArguments,
ErrorResult& aError);
nsJSScriptTimeoutHandler(JSContext* aCx, nsGlobalWindow *aWindow,
@@ -47,10 +48,12 @@ public:
{
return mFunction;
}
virtual void GetLocation(const char** aFileName, uint32_t* aLineNo) override
virtual void GetLocation(const char** aFileName, uint32_t* aLineNo,
uint32_t* aColumn) override
{
*aFileName = mFileName.get();
*aLineNo = mLineNo;
*aColumn = mColumn;
}
virtual const nsTArray<JS::Value>& GetArgs() override
@@ -67,6 +70,7 @@ private:
// caller of setTimeout()
nsCString mFileName;
uint32_t mLineNo;
uint32_t mColumn;
nsTArray<JS::Heap<JS::Value> > mArgs;
// The expression to evaluate or function to call. If mFunction is non-null
@@ -106,6 +110,8 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsJSScriptTimeoutHandler)
name.Append(tmp->mFileName);
name.Append(':');
name.AppendInt(tmp->mLineNo);
name.Append(':');
name.AppendInt(tmp->mColumn);
name.Append(']');
}
cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name.get());
@@ -183,17 +189,20 @@ CheckCSPForEval(JSContext* aCx, nsGlobalWindow* aWindow, ErrorResult& aError)
return allowsEval;
}
nsJSScriptTimeoutHandler::nsJSScriptTimeoutHandler() :
mLineNo(0)
nsJSScriptTimeoutHandler::nsJSScriptTimeoutHandler()
: mLineNo(0)
, mColumn(0)
{
}
nsJSScriptTimeoutHandler::nsJSScriptTimeoutHandler(nsGlobalWindow *aWindow,
nsJSScriptTimeoutHandler::nsJSScriptTimeoutHandler(JSContext* aCx,
nsGlobalWindow *aWindow,
Function& aFunction,
FallibleTArray<JS::Heap<JS::Value> >& aArguments,
ErrorResult& aError) :
mLineNo(0),
mFunction(&aFunction)
ErrorResult& aError)
: mLineNo(0)
, mColumn(0)
, mFunction(&aFunction)
{
if (!aWindow->GetContextInternal() || !aWindow->FastGetGlobalJSObject()) {
// This window was already closed, or never properly initialized,
@@ -204,15 +213,19 @@ nsJSScriptTimeoutHandler::nsJSScriptTimeoutHandler(nsGlobalWindow *aWindow,
mozilla::HoldJSObjects(this);
mArgs.SwapElements(aArguments);
// Get the calling location.
nsJSUtils::GetCallingLocation(aCx, mFileName, &mLineNo, &mColumn);
}
nsJSScriptTimeoutHandler::nsJSScriptTimeoutHandler(JSContext* aCx,
nsGlobalWindow *aWindow,
const nsAString& aExpression,
bool* aAllowEval,
ErrorResult& aError) :
mLineNo(0),
mExpr(aExpression)
ErrorResult& aError)
: mLineNo(0)
, mColumn(0)
, mExpr(aExpression)
{
if (!aWindow->GetContextInternal() || !aWindow->FastGetGlobalJSObject()) {
// This window was already closed, or never properly initialized,
@@ -227,7 +240,7 @@ nsJSScriptTimeoutHandler::nsJSScriptTimeoutHandler(JSContext* aCx,
}
// Get the calling location.
nsJSUtils::GetCallingLocation(aCx, mFileName, &mLineNo);
nsJSUtils::GetCallingLocation(aCx, mFileName, &mLineNo, &mColumn);
}
nsJSScriptTimeoutHandler::~nsJSScriptTimeoutHandler()
@@ -253,7 +266,8 @@ nsJSScriptTimeoutHandler::GetHandlerText()
}
already_AddRefed<nsIScriptTimeoutHandler>
NS_CreateJSTimeoutHandler(nsGlobalWindow *aWindow, Function& aFunction,
NS_CreateJSTimeoutHandler(JSContext *aCx, nsGlobalWindow *aWindow,
Function& aFunction,
const Sequence<JS::Value>& aArguments,
ErrorResult& aError)
{
@@ -264,7 +278,7 @@ NS_CreateJSTimeoutHandler(nsGlobalWindow *aWindow, Function& aFunction,
}
nsRefPtr<nsJSScriptTimeoutHandler> handler =
new nsJSScriptTimeoutHandler(aWindow, aFunction, args, aError);
new nsJSScriptTimeoutHandler(aCx, aWindow, aFunction, args, aError);
return aError.Failed() ? nullptr : handler.forget();
}
+4 -4
View File
@@ -35,10 +35,10 @@ using namespace mozilla::dom;
bool
nsJSUtils::GetCallingLocation(JSContext* aContext, nsACString& aFilename,
uint32_t* aLineno)
uint32_t* aLineno, uint32_t* aColumn)
{
JS::AutoFilename filename;
if (!JS::DescribeScriptedCaller(aContext, &filename, aLineno)) {
if (!JS::DescribeScriptedCaller(aContext, &filename, aLineno, aColumn)) {
return false;
}
@@ -48,10 +48,10 @@ nsJSUtils::GetCallingLocation(JSContext* aContext, nsACString& aFilename,
bool
nsJSUtils::GetCallingLocation(JSContext* aContext, nsAString& aFilename,
uint32_t* aLineno)
uint32_t* aLineno, uint32_t* aColumn)
{
JS::AutoFilename filename;
if (!JS::DescribeScriptedCaller(aContext, &filename, aLineno)) {
if (!JS::DescribeScriptedCaller(aContext, &filename, aLineno, aColumn)) {
return false;
}
+4 -2
View File
@@ -35,9 +35,11 @@ class nsJSUtils
{
public:
static bool GetCallingLocation(JSContext* aContext, nsACString& aFilename,
uint32_t* aLineno);
uint32_t* aLineno = nullptr,
uint32_t* aColumn = nullptr);
static bool GetCallingLocation(JSContext* aContext, nsAString& aFilename,
uint32_t* aLineno);
uint32_t* aLineno = nullptr,
uint32_t* aColumn = nullptr);
static nsIScriptGlobalObject *GetStaticScriptGlobal(JSObject* aObj);
+18 -32
View File
@@ -9,11 +9,13 @@
#include "mozilla/dom/MimeTypeArrayBinding.h"
#include "mozilla/dom/MimeTypeBinding.h"
#include "nsIDOMNavigator.h"
#include "nsPIDOMWindow.h"
#include "nsPluginArray.h"
#include "nsIMIMEService.h"
#include "nsIMIMEInfo.h"
#include "Navigator.h"
#include "nsServiceManagerUtils.h"
#include "nsPluginTags.h"
using namespace mozilla;
using namespace mozilla::dom;
@@ -27,8 +29,7 @@ NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsMimeTypeArray,
mWindow,
mMimeTypes,
mHiddenMimeTypes)
mMimeTypes)
nsMimeTypeArray::nsMimeTypeArray(nsPIDOMWindow* aWindow)
: mWindow(aWindow)
@@ -49,7 +50,6 @@ void
nsMimeTypeArray::Refresh()
{
mMimeTypes.Clear();
mHiddenMimeTypes.Clear();
}
nsPIDOMWindow*
@@ -114,10 +114,6 @@ nsMimeTypeArray::NamedGetter(const nsAString& aName, bool &aFound)
ToLowerCase(lowerName);
nsMimeType* mimeType = FindMimeType(mMimeTypes, lowerName);
if (!mimeType) {
mimeType = FindMimeType(mHiddenMimeTypes, lowerName);
}
if (mimeType) {
aFound = true;
return mimeType;
@@ -164,11 +160,8 @@ nsMimeTypeArray::NamedGetter(const nsAString& aName, bool &aFound)
// If we got here, we support this type! Say so.
aFound = true;
// We don't want navigator.mimeTypes enumeration to expose MIME types with
// application handlers, so add them to the list of hidden MIME types.
nsMimeType *mt = new nsMimeType(mWindow, lowerName);
mHiddenMimeTypes.AppendElement(mt);
mMimeTypes.AppendElement(mt);
return mt;
}
@@ -199,7 +192,7 @@ nsMimeTypeArray::GetSupportedNames(unsigned, nsTArray< nsString >& aRetval)
void
nsMimeTypeArray::EnsurePluginMimeTypes()
{
if (!mMimeTypes.IsEmpty() || !mHiddenMimeTypes.IsEmpty() || !mWindow) {
if (!mMimeTypes.IsEmpty() || !mWindow) {
return;
}
@@ -217,7 +210,7 @@ nsMimeTypeArray::EnsurePluginMimeTypes()
return;
}
pluginArray->GetMimeTypes(mMimeTypes, mHiddenMimeTypes);
pluginArray->GetMimeTypes(mMimeTypes);
}
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsMimeType, AddRef)
@@ -225,19 +218,22 @@ NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsMimeType, Release)
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsMimeType, mWindow, mPluginElement)
nsMimeType::nsMimeType(nsPIDOMWindow* aWindow, nsPluginElement* aPluginElement,
uint32_t aPluginTagMimeIndex, const nsAString& aType)
nsMimeType::nsMimeType(nsPIDOMWindow* aWindow,
nsPluginElement* aPluginElement,
const nsAString& aType,
const nsAString& aDescription,
const nsAString& aExtension)
: mWindow(aWindow),
mPluginElement(aPluginElement),
mPluginTagMimeIndex(aPluginTagMimeIndex),
mType(aType)
mType(aType),
mDescription(aDescription),
mExtension(aExtension)
{
}
nsMimeType::nsMimeType(nsPIDOMWindow* aWindow, const nsAString& aType)
: mWindow(aWindow),
mPluginElement(nullptr),
mPluginTagMimeIndex(0),
mType(aType)
{
}
@@ -260,14 +256,9 @@ nsMimeType::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
}
void
nsMimeType::GetDescription(nsString& retval) const
nsMimeType::GetDescription(nsString& aRetval) const
{
retval.Truncate();
if (mPluginElement) {
CopyUTF8toUTF16(mPluginElement->PluginTag()->
mMimeDescriptions[mPluginTagMimeIndex], retval);
}
aRetval = mDescription;
}
nsPluginElement*
@@ -280,14 +271,9 @@ nsMimeType::GetEnabledPlugin() const
}
void
nsMimeType::GetSuffixes(nsString& retval) const
nsMimeType::GetSuffixes(nsString& aRetval) const
{
retval.Truncate();
if (mPluginElement) {
CopyUTF8toUTF16(mPluginElement->PluginTag()->
mExtensions[mPluginTagMimeIndex], retval);
}
aRetval = mExtension;
}
void
+9 -12
View File
@@ -47,16 +47,9 @@ protected:
nsCOMPtr<nsPIDOMWindow> mWindow;
// mMimeTypes contains MIME types handled by non-hidden plugins, those
// popular plugins that must be exposed in navigator.plugins enumeration to
// avoid breaking web content. Likewise, mMimeTypes are exposed in
// navigator.mimeTypes enumeration.
// mMimeTypes contains MIME types handled by plugins or by an OS
// PreferredApplicationHandler.
nsTArray<nsRefPtr<nsMimeType> > mMimeTypes;
// mHiddenMimeTypes contains MIME types handled by plugins hidden from
// navigator.plugins enumeration or by an OS PreferredApplicationHandler.
// mHiddenMimeTypes are hidden from navigator.mimeTypes enumeration.
nsTArray<nsRefPtr<nsMimeType> > mHiddenMimeTypes;
};
class nsMimeType final : public nsWrapperCache
@@ -65,8 +58,11 @@ public:
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(nsMimeType)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(nsMimeType)
nsMimeType(nsPIDOMWindow* aWindow, nsPluginElement* aPluginElement,
uint32_t aPluginTagMimeIndex, const nsAString& aMimeType);
nsMimeType(nsPIDOMWindow* aWindow,
nsPluginElement* aPluginElement,
const nsAString& aType,
const nsAString& aDescription,
const nsAString& aExtension);
nsMimeType(nsPIDOMWindow* aWindow, const nsAString& aMimeType);
nsPIDOMWindow* GetParentObject() const;
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
@@ -92,8 +88,9 @@ protected:
// mimetype array. We rely on the cycle collector to break this
// cycle.
nsRefPtr<nsPluginElement> mPluginElement;
uint32_t mPluginTagMimeIndex;
nsString mType;
nsString mDescription;
nsString mExtension;
};
#endif /* nsMimeTypeArray_h___ */
+26 -76
View File
@@ -6,11 +6,9 @@
#include "nsPluginArray.h"
#include "mozilla/Preferences.h"
#include "mozilla/dom/PluginArrayBinding.h"
#include "mozilla/dom/PluginBinding.h"
#include "nsCharSeparatedTokenizer.h"
#include "nsMimeTypeArray.h"
#include "Navigator.h"
#include "nsIDocShell.h"
@@ -68,8 +66,7 @@ NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsPluginArray,
mWindow,
mPlugins,
mHiddenPlugins)
mPlugins)
static void
GetPluginMimeTypes(const nsTArray<nsRefPtr<nsPluginElement> >& aPlugins,
@@ -89,11 +86,9 @@ operator<(const nsRefPtr<nsMimeType>& lhs, const nsRefPtr<nsMimeType>& rhs)
}
void
nsPluginArray::GetMimeTypes(nsTArray<nsRefPtr<nsMimeType> >& aMimeTypes,
nsTArray<nsRefPtr<nsMimeType> >& aHiddenMimeTypes)
nsPluginArray::GetMimeTypes(nsTArray<nsRefPtr<nsMimeType>>& aMimeTypes)
{
aMimeTypes.Clear();
aHiddenMimeTypes.Clear();
if (!AllowPlugins()) {
return;
@@ -102,7 +97,6 @@ nsPluginArray::GetMimeTypes(nsTArray<nsRefPtr<nsMimeType> >& aMimeTypes,
EnsurePlugins();
GetPluginMimeTypes(mPlugins, aMimeTypes);
GetPluginMimeTypes(mHiddenPlugins, aHiddenMimeTypes);
// Alphabetize the enumeration order of non-hidden MIME types to reduce
// fingerprintable entropy based on plugins' installation file times.
@@ -136,7 +130,7 @@ nsPluginArray::Refresh(bool aReloadDocuments)
// that plugins did not change and was not reloaded
if (pluginHost->ReloadPlugins() ==
NS_ERROR_PLUGINS_PLUGINSNOTCHANGED) {
nsTArray<nsRefPtr<nsPluginTag> > newPluginTags;
nsTArray<nsCOMPtr<nsIInternalPluginTag> > newPluginTags;
pluginHost->GetPlugins(newPluginTags);
// Check if the number of plugins we know about are different from
@@ -146,14 +140,12 @@ nsPluginArray::Refresh(bool aReloadDocuments)
// happens, and therefore the lengths will be in sync only when
// the both arrays contain the same plugin tags (though as
// different types).
uint32_t pluginCount = mPlugins.Length() + mHiddenPlugins.Length();
if (newPluginTags.Length() == pluginCount) {
if (newPluginTags.Length() == mPlugins.Length()) {
return;
}
}
mPlugins.Clear();
mHiddenPlugins.Clear();
nsCOMPtr<nsIDOMNavigator> navigator;
mWindow->GetNavigator(getter_AddRefs(navigator));
@@ -229,10 +221,6 @@ nsPluginArray::NamedGetter(const nsAString& aName, bool &aFound)
EnsurePlugins();
nsPluginElement* plugin = FindPlugin(mPlugins, aName);
if (!plugin) {
plugin = FindPlugin(mHiddenPlugins, aName);
}
aFound = (plugin != nullptr);
return plugin;
}
@@ -290,40 +278,18 @@ nsPluginArray::AllowPlugins() const
return docShell && docShell->PluginsAllowedInCurrentDoc();
}
static bool
HasStringPrefix(const nsCString& str, const nsACString& prefix) {
return str.Compare(prefix.BeginReading(), false, prefix.Length()) == 0;
}
static bool
IsPluginEnumerable(const nsTArray<nsCString>& enumerableNames,
const nsPluginTag* pluginTag)
{
const nsCString& pluginName = pluginTag->mName;
const uint32_t length = enumerableNames.Length();
for (uint32_t i = 0; i < length; i++) {
const nsCString& name = enumerableNames[i];
if (HasStringPrefix(pluginName, name)) {
return true; // don't hide plugin
}
}
return false; // hide plugin!
}
static bool
operator<(const nsRefPtr<nsPluginElement>& lhs,
const nsRefPtr<nsPluginElement>& rhs)
{
// Sort plugins alphabetically by name.
return lhs->PluginTag()->mName < rhs->PluginTag()->mName;
return lhs->PluginTag()->Name() < rhs->PluginTag()->Name();
}
void
nsPluginArray::EnsurePlugins()
{
if (!mPlugins.IsEmpty() || !mHiddenPlugins.IsEmpty()) {
if (!mPlugins.IsEmpty()) {
// We already have an array of plugin elements.
return;
}
@@ -334,39 +300,13 @@ nsPluginArray::EnsurePlugins()
return;
}
nsTArray<nsRefPtr<nsPluginTag> > pluginTags;
nsTArray<nsCOMPtr<nsIInternalPluginTag> > pluginTags;
pluginHost->GetPlugins(pluginTags);
nsTArray<nsCString> enumerableNames;
const nsAdoptingCString& enumerableNamesPref =
Preferences::GetCString("plugins.enumerable_names");
bool disablePluginHiding = !enumerableNamesPref ||
enumerableNamesPref.EqualsLiteral("*");
if (!disablePluginHiding) {
nsCCharSeparatedTokenizer tokens(enumerableNamesPref, ',');
while (tokens.hasMoreTokens()) {
const nsCSubstring& token = tokens.nextToken();
if (!token.IsEmpty()) {
enumerableNames.AppendElement(token);
}
}
}
// need to wrap each of these with a nsPluginElement, which is
// scriptable.
for (uint32_t i = 0; i < pluginTags.Length(); ++i) {
nsPluginTag* pluginTag = pluginTags[i];
// Add the plugin to the list of hidden plugins or non-hidden plugins?
nsTArray<nsRefPtr<nsPluginElement> >& pluginArray =
(disablePluginHiding || IsPluginEnumerable(enumerableNames, pluginTag))
? mPlugins
: mHiddenPlugins;
pluginArray.AppendElement(new nsPluginElement(mWindow, pluginTag));
mPlugins.AppendElement(new nsPluginElement(mWindow, pluginTags[i]));
}
// Alphabetize the enumeration order of non-hidden plugins to reduce
@@ -386,7 +326,7 @@ NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsPluginElement, mWindow, mMimeTypes)
nsPluginElement::nsPluginElement(nsPIDOMWindow* aWindow,
nsPluginTag* aPluginTag)
nsIInternalPluginTag* aPluginTag)
: mWindow(aWindow),
mPluginTag(aPluginTag)
{
@@ -412,25 +352,25 @@ nsPluginElement::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
void
nsPluginElement::GetDescription(nsString& retval) const
{
CopyUTF8toUTF16(mPluginTag->mDescription, retval);
CopyUTF8toUTF16(mPluginTag->Description(), retval);
}
void
nsPluginElement::GetFilename(nsString& retval) const
{
CopyUTF8toUTF16(mPluginTag->mFileName, retval);
CopyUTF8toUTF16(mPluginTag->FileName(), retval);
}
void
nsPluginElement::GetVersion(nsString& retval) const
{
CopyUTF8toUTF16(mPluginTag->mVersion, retval);
CopyUTF8toUTF16(mPluginTag->Version(), retval);
}
void
nsPluginElement::GetName(nsString& retval) const
{
CopyUTF8toUTF16(mPluginTag->mName, retval);
CopyUTF8toUTF16(mPluginTag->Name(), retval);
}
nsMimeType*
@@ -519,8 +459,18 @@ nsPluginElement::EnsurePluginMimeTypes()
return;
}
for (uint32_t i = 0; i < mPluginTag->mMimeTypes.Length(); ++i) {
NS_ConvertUTF8toUTF16 type(mPluginTag->mMimeTypes[i]);
mMimeTypes.AppendElement(new nsMimeType(mWindow, this, i, type));
if (mPluginTag->MimeTypes().Length() != mPluginTag->MimeDescriptions().Length() ||
mPluginTag->MimeTypes().Length() != mPluginTag->Extensions().Length()) {
MOZ_ASSERT(false, "mime type arrays expected to be the same length");
return;
}
for (uint32_t i = 0; i < mPluginTag->MimeTypes().Length(); ++i) {
NS_ConvertUTF8toUTF16 type(mPluginTag->MimeTypes()[i]);
NS_ConvertUTF8toUTF16 description(mPluginTag->MimeDescriptions()[i]);
NS_ConvertUTF8toUTF16 extension(mPluginTag->Extensions()[i]);
mMimeTypes.AppendElement(new nsMimeType(mWindow, this, type, description,
extension));
}
}
+5 -17
View File
@@ -11,11 +11,11 @@
#include "nsWeakReference.h"
#include "nsIObserver.h"
#include "nsWrapperCache.h"
#include "nsPluginTags.h"
#include "nsPIDOMWindow.h"
class nsPluginElement;
class nsMimeType;
class nsIInternalPluginTag;
class nsPluginArray final : public nsIObserver,
public nsSupportsWeakReference,
@@ -40,8 +40,7 @@ public:
void Init();
void Invalidate();
void GetMimeTypes(nsTArray<nsRefPtr<nsMimeType> >& aMimeTypes,
nsTArray<nsRefPtr<nsMimeType> >& aHiddenMimeTypes);
void GetMimeTypes(nsTArray<nsRefPtr<nsMimeType>>& aMimeTypes);
// PluginArray WebIDL methods
@@ -61,18 +60,7 @@ private:
void EnsurePlugins();
nsCOMPtr<nsPIDOMWindow> mWindow;
// Many sites check whether a particular plugin is installed by enumerating
// all navigator.plugins, checking each plugin's name. These sites should
// just check navigator.plugins["Popular Plugin Name"] instead. mPlugins
// contains those popular plugins that must be exposed in navigator.plugins
// enumeration to avoid breaking web content.
nsTArray<nsRefPtr<nsPluginElement> > mPlugins;
// mHiddenPlugins contains plugins that can be queried by
// navigator.plugins["Hidden Plugin Name"] but do not need to be exposed in
// navigator.plugins enumeration.
nsTArray<nsRefPtr<nsPluginElement> > mHiddenPlugins;
};
class nsPluginElement final : public nsISupports,
@@ -82,12 +70,12 @@ public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsPluginElement)
nsPluginElement(nsPIDOMWindow* aWindow, nsPluginTag* aPluginTag);
nsPluginElement(nsPIDOMWindow* aWindow, nsIInternalPluginTag* aPluginTag);
nsPIDOMWindow* GetParentObject() const;
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
nsPluginTag* PluginTag() const
nsIInternalPluginTag* PluginTag() const
{
return mPluginTag;
}
@@ -114,7 +102,7 @@ protected:
void EnsurePluginMimeTypes();
nsCOMPtr<nsPIDOMWindow> mWindow;
nsRefPtr<nsPluginTag> mPluginTag;
nsCOMPtr<nsIInternalPluginTag> mPluginTag;
nsTArray<nsRefPtr<nsMimeType> > mMimeTypes;
};
+12
View File
@@ -36,6 +36,8 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
var SimpleURI = Cc["@mozilla.org/network/simple-uri;1"];
var ios = Cc["@mozilla.org/network/io-service;1"]
.getService(Ci.nsIIOService);
var contentSecManager = Cc["@mozilla.org/contentsecuritymanager;1"]
.getService(Ci.nsIContentSecurityManager);
var PROTOCOL_SCHEME = "jsproto";
@@ -68,12 +70,22 @@ CustomChannel.prototype = {
listener.onStopRequest(this, context, Cr.NS_OK);
} catch(e) {}
},
asyncOpen2: function(listener) {
// throws an error if security checks fail
var outListener = contentSecManager.performSecurityCheck(this, listener);
return this.asyncOpen(outListener, null);
},
open: function() {
let data = "bar";
let stream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(Ci.nsIStringInputStream);
stream.setData(data, data.length);
return stream;
},
open2: function() {
// throws an error if security checks fail
contentSecManager.performSecurityCheck(this, null);
return this.open();
},
isPending: function() {
return false;
},
+2 -2
View File
@@ -8446,7 +8446,7 @@ class CGMemberJITInfo(CGThing):
"""
{
{ ${opName} },
prototypes::id::${name},
{ prototypes::id::${name} },
PrototypeTraits<prototypes::id::${name}>::Depth,
JSJitInfo::${opType},
JSJitInfo::${aliasSet}, /* aliasSet. Not relevant for setters. */
@@ -8827,7 +8827,7 @@ class CGStaticMethodJitinfo(CGGeneric):
"\n"
"static const JSJitInfo %s_methodinfo = {\n"
" { (JSJitGetterOp)%s },\n"
" prototypes::id::_ID_Count, 0, JSJitInfo::StaticMethod,\n"
" { prototypes::id::_ID_Count }, 0, JSJitInfo::StaticMethod,\n"
" JSJitInfo::AliasEverything, JSVAL_TYPE_MISSING, false, false,\n"
" false, false, 0\n"
"};\n" %
-25
View File
@@ -162,31 +162,6 @@ DOMProxyHandler::isExtensible(JSContext *cx, JS::Handle<JSObject*> proxy, bool *
return true;
}
bool
BaseDOMProxyHandler::getPropertyDescriptor(JSContext* cx,
JS::Handle<JSObject*> proxy,
JS::Handle<jsid> id,
MutableHandle<JSPropertyDescriptor> desc) const
{
if (!getOwnPropertyDescriptor(cx, proxy, id, desc)) {
return false;
}
if (desc.object()) {
return true;
}
JS::Rooted<JSObject*> proto(cx);
if (!js::GetObjectProto(cx, proxy, &proto)) {
return false;
}
if (!proto) {
desc.object().set(nullptr);
return true;
}
return JS_GetPropertyDescriptorById(cx, proto, id, desc);
}
bool
BaseDOMProxyHandler::getOwnPropertyDescriptor(JSContext* cx,
JS::Handle<JSObject*> proxy,
-4
View File
@@ -59,10 +59,6 @@ public:
virtual bool ownPropertyKeys(JSContext* cx, JS::Handle<JSObject*> proxy,
JS::AutoIdVector &props) const override;
bool getPropertyDescriptor(JSContext* cx, JS::Handle<JSObject*> proxy,
JS::Handle<jsid> id,
JS::MutableHandle<JSPropertyDescriptor> desc) const override;
virtual bool enumerate(JSContext *cx, JS::Handle<JSObject*> proxy,
JS::MutableHandle<JSObject*> objp) const override;
+1
View File
@@ -24,6 +24,7 @@ skip-if = debug == false
[test_bug963382.html]
skip-if = debug == false
[test_bug1041646.html]
[test_bug1123875.html]
[test_barewordGetsWindow.html]
[test_callback_default_thisval.html]
[test_cloneAndImportNode.html]
+14
View File
@@ -0,0 +1,14 @@
<!doctype html>
<meta charset=utf-8>
<title>Test for Bug 1123875</title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<div id=log></div>
<script>
test(() => {
assert_throws(new TypeError, () => {
"use strict";
document.childNodes.length = 0;
});
}, "setting a readonly attribute on a proxy in strict mode should throw a TypeError");
</script>
@@ -427,6 +427,10 @@ const kEventConstructors = {
return e;
},
},
SpeechRecognitionError: { create: function (aName, aProps) {
return new SpeechRecognitionError(aName, aProps);
},
},
SpeechRecognitionEvent: { create: function (aName, aProps) {
return new SpeechRecognitionEvent(aName, aProps);
},
+15 -6
View File
@@ -187,6 +187,7 @@ class IDBDatabase::LogWarningRunnable final
nsCString mMessageName;
nsString mFilename;
uint32_t mLineNumber;
uint32_t mColumnNumber;
uint64_t mInnerWindowID;
bool mIsChrome;
@@ -194,11 +195,13 @@ public:
LogWarningRunnable(const char* aMessageName,
const nsAString& aFilename,
uint32_t aLineNumber,
uint32_t aColumnNumber,
bool aIsChrome,
uint64_t aInnerWindowID)
: mMessageName(aMessageName)
, mFilename(aFilename)
, mLineNumber(aLineNumber)
, mColumnNumber(aColumnNumber)
, mInnerWindowID(aInnerWindowID)
, mIsChrome(aIsChrome)
{
@@ -209,6 +212,7 @@ public:
LogWarning(const char* aMessageName,
const nsAString& aFilename,
uint32_t aLineNumber,
uint32_t aColumnNumber,
bool aIsChrome,
uint64_t aInnerWindowID);
@@ -955,10 +959,10 @@ IDBDatabase::AbortTransactions(bool aShouldWarn)
MOZ_ASSERT(transaction);
nsString filename;
uint32_t lineNo;
transaction->GetCallerLocation(filename, &lineNo);
uint32_t lineNo, column;
transaction->GetCallerLocation(filename, &lineNo, &column);
aDatabase->LogWarning(kWarningMessage, filename, lineNo);
aDatabase->LogWarning(kWarningMessage, filename, lineNo, column);
}
}
};
@@ -1333,7 +1337,8 @@ IDBDatabase::Invalidate()
void
IDBDatabase::LogWarning(const char* aMessageName,
const nsAString& aFilename,
uint32_t aLineNumber)
uint32_t aLineNumber,
uint32_t aColumnNumber)
{
AssertIsOnOwningThread();
MOZ_ASSERT(aMessageName);
@@ -1342,6 +1347,7 @@ IDBDatabase::LogWarning(const char* aMessageName,
LogWarningRunnable::LogWarning(aMessageName,
aFilename,
aLineNumber,
aColumnNumber,
mFactory->IsChrome(),
mFactory->InnerWindowID());
} else {
@@ -1349,6 +1355,7 @@ IDBDatabase::LogWarning(const char* aMessageName,
new LogWarningRunnable(aMessageName,
aFilename,
aLineNumber,
aColumnNumber,
mFactory->IsChrome(),
mFactory->InnerWindowID());
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable)));
@@ -1624,6 +1631,7 @@ IDBDatabase::
LogWarningRunnable::LogWarning(const char* aMessageName,
const nsAString& aFilename,
uint32_t aLineNumber,
uint32_t aColumnNumber,
bool aIsChrome,
uint64_t aInnerWindowID)
{
@@ -1660,7 +1668,7 @@ LogWarningRunnable::LogWarning(const char* aMessageName,
aFilename,
/* aSourceLine */ EmptyString(),
aLineNumber,
/* aColumnNumber */ 0,
aColumnNumber,
nsIScriptError::warningFlag,
category,
aInnerWindowID)));
@@ -1670,7 +1678,7 @@ LogWarningRunnable::LogWarning(const char* aMessageName,
aFilename,
/* aSourceLine */ EmptyString(),
aLineNumber,
/* aColumnNumber */ 0,
aColumnNumber,
nsIScriptError::warningFlag,
category.get())));
}
@@ -1689,6 +1697,7 @@ LogWarningRunnable::Run()
LogWarning(mMessageName.get(),
mFilename,
mLineNumber,
mColumnNumber,
mIsChrome,
mInnerWindowID);
+2 -1
View File
@@ -313,7 +313,8 @@ private:
void
LogWarning(const char* aMessageName,
const nsAString& aFilename,
uint32_t aLineNumber);
uint32_t aLineNumber,
uint32_t aColumnNumber);
};
} // namespace indexedDB
+12 -6
View File
@@ -92,6 +92,7 @@ IDBRequest::InitMembers()
mLoggingSerialNumber = NextSerialNumber();
mErrorCode = NS_OK;
mLineNo = 0;
mColumn = 0;
mHaveResultOrErrorCode = false;
}
@@ -104,7 +105,7 @@ IDBRequest::Create(IDBDatabase* aDatabase,
aDatabase->AssertIsOnOwningThread();
nsRefPtr<IDBRequest> request = new IDBRequest(aDatabase);
CaptureCaller(request->mFilename, &request->mLineNo);
CaptureCaller(request->mFilename, &request->mLineNo, &request->mColumn);
request->mTransaction = aTransaction;
request->SetScriptOwner(aDatabase->GetScriptOwner());
@@ -168,13 +169,15 @@ IDBRequest::SetLoggingSerialNumber(uint64_t aLoggingSerialNumber)
}
void
IDBRequest::CaptureCaller(nsAString& aFilename, uint32_t* aLineNo)
IDBRequest::CaptureCaller(nsAString& aFilename, uint32_t* aLineNo,
uint32_t* aColumn)
{
MOZ_ASSERT(aFilename.IsEmpty());
MOZ_ASSERT(aLineNo);
MOZ_ASSERT(aColumn);
ThreadsafeAutoJSContext cx;
nsJSUtils::GetCallingLocation(cx, aFilename, aLineNo);
nsJSUtils::GetCallingLocation(cx, aFilename, aLineNo, aColumn);
}
void
@@ -271,13 +274,16 @@ IDBRequest::GetErrorAfterResult() const
#endif // DEBUG
void
IDBRequest::GetCallerLocation(nsAString& aFilename, uint32_t* aLineNo) const
IDBRequest::GetCallerLocation(nsAString& aFilename, uint32_t* aLineNo,
uint32_t* aColumn) const
{
AssertIsOnOwningThread();
MOZ_ASSERT(aLineNo);
MOZ_ASSERT(aColumn);
aFilename = mFilename;
*aLineNo = mLineNo;
*aColumn = mColumn;
}
IDBRequestReadyState
@@ -516,7 +522,7 @@ IDBOpenDBRequest::CreateForWindow(IDBFactory* aFactory,
MOZ_ASSERT(aScriptOwner);
nsRefPtr<IDBOpenDBRequest> request = new IDBOpenDBRequest(aFactory, aOwner);
CaptureCaller(request->mFilename, &request->mLineNo);
CaptureCaller(request->mFilename, &request->mLineNo, &request->mColumn);
request->SetScriptOwner(aScriptOwner);
@@ -533,7 +539,7 @@ IDBOpenDBRequest::CreateForJS(IDBFactory* aFactory,
MOZ_ASSERT(aScriptOwner);
nsRefPtr<IDBOpenDBRequest> request = new IDBOpenDBRequest(aFactory, nullptr);
CaptureCaller(request->mFilename, &request->mLineNo);
CaptureCaller(request->mFilename, &request->mLineNo, &request->mColumn);
request->SetScriptOwner(aScriptOwner);
+4 -2
View File
@@ -63,6 +63,7 @@ protected:
uint64_t mLoggingSerialNumber;
nsresult mErrorCode;
uint32_t mLineNo;
uint32_t mColumn;
bool mHaveResultOrErrorCode;
public:
@@ -82,7 +83,7 @@ public:
IDBTransaction* aTransaction);
static void
CaptureCaller(nsAString& aFilename, uint32_t* aLineNo);
CaptureCaller(nsAString& aFilename, uint32_t* aLineNo, uint32_t* aColumn);
static uint64_t
NextSerialNumber();
@@ -130,7 +131,8 @@ public:
GetError(ErrorResult& aRv);
void
GetCallerLocation(nsAString& aFilename, uint32_t* aLineNo) const;
GetCallerLocation(nsAString& aFilename, uint32_t* aLineNo,
uint32_t* aColumn) const;
bool
IsPending() const
+8 -3
View File
@@ -82,6 +82,7 @@ IDBTransaction::IDBTransaction(IDBDatabase* aDatabase,
, mAbortCode(NS_OK)
, mPendingRequestCount(0)
, mLineNo(0)
, mColumn(0)
, mReadyState(IDBTransaction::INITIAL)
, mMode(aMode)
, mCreating(false)
@@ -186,7 +187,7 @@ IDBTransaction::CreateVersionChange(
emptyObjectStoreNames,
VERSION_CHANGE);
aOpenRequest->GetCallerLocation(transaction->mFilename,
&transaction->mLineNo);
&transaction->mLineNo, &transaction->mColumn);
transaction->SetScriptOwner(aDatabase->GetScriptOwner());
@@ -219,7 +220,8 @@ IDBTransaction::Create(IDBDatabase* aDatabase,
nsRefPtr<IDBTransaction> transaction =
new IDBTransaction(aDatabase, aObjectStoreNames, aMode);
IDBRequest::CaptureCaller(transaction->mFilename, &transaction->mLineNo);
IDBRequest::CaptureCaller(transaction->mFilename, &transaction->mLineNo,
&transaction->mColumn);
transaction->SetScriptOwner(aDatabase->GetScriptOwner());
@@ -492,13 +494,16 @@ IDBTransaction::IsOpen() const
}
void
IDBTransaction::GetCallerLocation(nsAString& aFilename, uint32_t* aLineNo) const
IDBTransaction::GetCallerLocation(nsAString& aFilename, uint32_t* aLineNo,
uint32_t* aColumn) const
{
AssertIsOnOwningThread();
MOZ_ASSERT(aLineNo);
MOZ_ASSERT(aColumn);
aFilename = mFilename;
*aLineNo = mLineNo;
*aColumn = mColumn;
}
already_AddRefed<IDBObjectStore>
+3 -1
View File
@@ -100,6 +100,7 @@ private:
nsString mFilename;
uint32_t mLineNo;
uint32_t mColumn;
ReadyState mReadyState;
Mode mMode;
@@ -205,7 +206,8 @@ public:
}
void
GetCallerLocation(nsAString& aFilename, uint32_t* aLineNo) const;
GetCallerLocation(nsAString& aFilename, uint32_t* aLineNo,
uint32_t* aColumn) const;
// 'Get' prefix is to avoid name collisions with the enum
Mode
+3 -3
View File
@@ -480,7 +480,7 @@ IndexedDatabaseManager::CommonPostHandleEvent(EventChainPostVisitor& aVisitor,
ThreadsafeAutoJSContext cx;
RootedDictionary<ErrorEventInit> init(cx);
request->GetCallerLocation(init.mFilename, &init.mLineno);
request->GetCallerLocation(init.mFilename, &init.mLineno, &init.mColno);
init.mMessage = errorName;
init.mCancelable = true;
@@ -556,7 +556,7 @@ IndexedDatabaseManager::CommonPostHandleEvent(EventChainPostVisitor& aVisitor,
init.mFilename,
/* aSourceLine */ EmptyString(),
init.mLineno,
/* aColumnNumber */ 0,
init.mColno,
nsIScriptError::errorFlag,
category,
innerWindowID)));
@@ -566,7 +566,7 @@ IndexedDatabaseManager::CommonPostHandleEvent(EventChainPostVisitor& aVisitor,
init.mFilename,
/* aSourceLine */ EmptyString(),
init.mLineno,
/* aColumnNumber */ 0,
init.mColno,
nsIScriptError::errorFlag,
category.get())));
}
+1
View File
@@ -5,6 +5,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
XPIDL_SOURCES += [
'nsIContentSecurityManager.idl',
'nsIContentSecurityPolicy.idl'
]
@@ -0,0 +1,43 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
interface nsIChannel;
interface nsIStreamListener;
/**
* nsIContentSecurityManager
* Describes an XPCOM component used to perform security checks
* right before opnening a channel.
*/
[scriptable, uuid(70eaa956-1077-41f6-bef8-d722cea31245)]
interface nsIContentSecurityManager : nsISupports
{
/**
* Checks whether a channel is allowed to access the given URI and
* whether the channel should be openend or should be blocked consulting
* internal security checks like Same Origin Policy, Content Security
* Policy, Mixed Content Blocker, etc.
*
* If security checks within performSecurityCheck fail, the function
* throws an exception.
*
* @param aChannel
* The channel about to be openend
* @param aStreamListener
* The Streamlistener of the channel potentially wrapped
* into CORSListenerProxy.
* @return
* The StreamListener of the channel wrapped into CORSListenerProxy.
*
* @throws NS_ERROR_DOM_BAD_URI
* If accessing the URI is not allowed (e.g. prohibted by SOP)
* @throws NS_ERROR_CONTENT_BLOCKED
* If any of the security policies (CSP, Mixed content) is violated
*/
nsIStreamListener performSecurityCheck(in nsIChannel aChannel,
in nsIStreamListener aStreamListener);
};
+1 -23
View File
@@ -12,7 +12,6 @@
#include "mozilla/dom/ipc/BlobChild.h"
#include "mozilla/jsipc/CrossProcessObjectWrappers.h"
#include "mozilla/ipc/InputStreamUtils.h"
#include "nsIObserverService.h"
using namespace mozilla::ipc;
using namespace mozilla::jsipc;
@@ -21,8 +20,7 @@ namespace mozilla {
namespace dom {
NS_IMPL_ISUPPORTS(ContentBridgeChild,
nsIContentChild,
nsIObserver)
nsIContentChild)
ContentBridgeChild::ContentBridgeChild(Transport* aTransport)
: mTransport(aTransport)
@@ -36,10 +34,6 @@ ContentBridgeChild::~ContentBridgeChild()
void
ContentBridgeChild::ActorDestroy(ActorDestroyReason aWhy)
{
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
if (os) {
os->RemoveObserver(this, "content-child-shutdown");
}
MessageLoop::current()->PostTask(
FROM_HERE,
NewRunnableMethod(this, &ContentBridgeChild::DeferredDestroy));
@@ -55,11 +49,6 @@ ContentBridgeChild::Create(Transport* aTransport, ProcessId aOtherPid)
DebugOnly<bool> ok = bridge->Open(aTransport, aOtherPid, XRE_GetIOMessageLoop());
MOZ_ASSERT(ok);
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
if (os) {
os->AddObserver(bridge, "content-child-shutdown", false);
}
return bridge;
}
@@ -180,16 +169,5 @@ ContentBridgeChild::DeallocPBlobChild(PBlobChild* aActor)
return nsIContentChild::DeallocPBlobChild(aActor);
}
NS_IMETHODIMP
ContentBridgeChild::Observe(nsISupports* aSubject,
const char* aTopic,
const char16_t* aData)
{
if (!strcmp(aTopic, "content-child-shutdown")) {
Close();
}
return NS_OK;
}
} // namespace dom
} // namespace mozilla
-3
View File
@@ -9,20 +9,17 @@
#include "mozilla/dom/PContentBridgeChild.h"
#include "mozilla/dom/nsIContentChild.h"
#include "nsIObserver.h"
namespace mozilla {
namespace dom {
class ContentBridgeChild final : public PContentBridgeChild
, public nsIContentChild
, public nsIObserver
{
public:
explicit ContentBridgeChild(Transport* aTransport);
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
static ContentBridgeChild*
Create(Transport* aTransport, ProcessId aOtherProcess);
+11
View File
@@ -163,6 +163,17 @@ ContentBridgeParent::DeallocPBrowserParent(PBrowserParent* aParent)
return nsIContentParent::DeallocPBrowserParent(aParent);
}
void
ContentBridgeParent::NotifyTabDestroyed()
{
int32_t numLiveTabs = ManagedPBrowserParent().Length();
if (numLiveTabs == 1) {
MessageLoop::current()->PostTask(
FROM_HERE,
NewRunnableMethod(this, &ContentBridgeParent::Close));
}
}
// This implementation is identical to ContentParent::GetCPOWManager but we can't
// move it to nsIContentParent because it calls ManagedPJavaScriptParent() which
// only exists in PContentParent and PContentBridgeParent.
+2
View File
@@ -28,6 +28,8 @@ public:
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
void DeferredDestroy();
virtual bool IsContentBridgeParent() override { return true; }
void NotifyTabDestroyed();
static ContentBridgeParent*
Create(Transport* aTransport, ProcessId aOtherProcess);
+150 -37
View File
@@ -1422,7 +1422,9 @@ ContentParent::Init()
}
Preferences::AddStrongObserver(this, "");
if (obs) {
obs->NotifyObservers(static_cast<nsIObserver*>(this), "ipc:content-created", nullptr);
nsAutoString cpId;
cpId.AppendInt(static_cast<uint64_t>(this->ChildID()));
obs->NotifyObservers(static_cast<nsIObserver*>(this), "ipc:content-created", cpId.get());
}
#ifdef ACCESSIBILITY
@@ -1800,11 +1802,12 @@ ContentParent::OnBeginSyncTransaction() {
if (!sDisableUnsafeCPOWWarnings) {
if (console && cx) {
nsAutoString filename;
uint32_t lineno = 0;
nsJSUtils::GetCallingLocation(cx, filename, &lineno);
uint32_t lineno = 0, column = 0;
nsJSUtils::GetCallingLocation(cx, filename, &lineno, &column);
nsCOMPtr<nsIScriptError> error(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
error->Init(NS_LITERAL_STRING("unsafe CPOW usage"), filename, EmptyString(),
lineno, 0, nsIScriptError::warningFlag, "chrome javascript");
error->Init(NS_LITERAL_STRING("unsafe CPOW usage"), filename,
EmptyString(), lineno, column,
nsIScriptError::warningFlag, "chrome javascript");
console->LogMessage(error);
} else {
NS_WARNING("Unsafe synchronous IPC message");
@@ -1990,9 +1993,20 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
props->SetPropertyAsBool(NS_LITERAL_STRING("abnormal"), true);
}
obs->NotifyObservers((nsIPropertyBag2*) props, "ipc:content-shutdown", nullptr);
nsAutoString cpId;
cpId.AppendInt(static_cast<uint64_t>(this->ChildID()));
obs->NotifyObservers((nsIPropertyBag2*) props, "ipc:content-shutdown", cpId.get());
}
// Remove any and all idle listeners.
nsCOMPtr<nsIIdleService> idleService =
do_GetService("@mozilla.org/widget/idleservice;1");
MOZ_ASSERT(idleService);
nsRefPtr<ParentIdleListener> listener;
for (int32_t i = mIdleListeners.Length() - 1; i >= 0; --i) {
listener = static_cast<ParentIdleListener*>(mIdleListeners[i].get());
idleService->RemoveIdleObserver(listener, listener->mTime);
}
mIdleListeners.Clear();
MessageLoop::current()->
@@ -2009,10 +2023,35 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
// least until after the current task finishes running.
NS_DispatchToCurrentThread(new DelayedDeleteContentParentTask(this));
// Destroy any processes created by this ContentParent
ContentProcessManager *cpm = ContentProcessManager::GetSingleton();
// Release the appId's reference count of any processes
// created by this ContentParent and the frame opened by this ContentParent
// if this ContentParent crashes.
ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
nsTArray<ContentParentId> childIDArray =
cpm->GetAllChildProcessById(this->ChildID());
if (why == AbnormalShutdown) {
nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager();
if(permMgr) {
// Release the appId's reference count of its child-processes
for (uint32_t i = 0; i < childIDArray.Length(); i++) {
nsTArray<TabContext> tabCtxs = cpm->GetTabContextByContentProcess(childIDArray[i]);
for (uint32_t j = 0 ; j < tabCtxs.Length() ; j++) {
if (tabCtxs[j].OwnOrContainingAppId() != nsIScriptSecurityManager::NO_APP_ID) {
permMgr->ReleaseAppId(tabCtxs[j].OwnOrContainingAppId());
}
}
}
// Release the appId's reference count belong to itself
nsTArray<TabContext> tabCtxs = cpm->GetTabContextByContentProcess(mChildID);
for (uint32_t i = 0; i < tabCtxs.Length() ; i++) {
if (tabCtxs[i].OwnOrContainingAppId()!= nsIScriptSecurityManager::NO_APP_ID) {
permMgr->ReleaseAppId(tabCtxs[i].OwnOrContainingAppId());
}
}
}
}
// Destroy any processes created by this ContentParent
for(uint32_t i = 0; i < childIDArray.Length(); i++) {
ContentParent* cp = cpm->GetContentProcessById(childIDArray[i]);
MessageLoop::current()->PostTask(
@@ -2028,23 +2067,33 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
}
void
ContentParent::NotifyTabDestroying(PBrowserParent* aTab)
ContentParent::NotifyTabDestroying(const TabId& aTabId,
const ContentParentId& aCpId)
{
if (XRE_IsParentProcess()) {
// There can be more than one PBrowser for a given app process
// because of popup windows. PBrowsers can also destroy
// concurrently. When all the PBrowsers are destroying, kick off
// another task to ensure the child process *really* shuts down,
// even if the PBrowsers themselves never finish destroying.
int32_t numLiveTabs = ManagedPBrowserParent().Length();
++mNumDestroyingTabs;
if (mNumDestroyingTabs != numLiveTabs) {
ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
ContentParent* cp = cpm->GetContentProcessById(aCpId);
if (!cp) {
return;
}
++cp->mNumDestroyingTabs;
nsTArray<TabId> tabIds = cpm->GetTabParentsByProcessId(aCpId);
if (static_cast<size_t>(cp->mNumDestroyingTabs) != tabIds.Length()) {
return;
}
// We're dying now, so prevent this content process from being
// recycled during its shutdown procedure.
MarkAsDead();
StartForceKillTimer();
cp->MarkAsDead();
cp->StartForceKillTimer();
} else {
ContentChild::GetSingleton()->SendNotifyTabDestroying(aTabId, aCpId);
}
}
static int32_t
@@ -2072,16 +2121,15 @@ ContentParent::StartForceKillTimer()
}
void
ContentParent::NotifyTabDestroyed(PBrowserParent* aTab,
ContentParent::NotifyTabDestroyed(const TabId& aTabId,
bool aNotifiedDestroying)
{
if (aNotifiedDestroying) {
--mNumDestroyingTabs;
}
TabId id = static_cast<TabParent*>(aTab)->GetTabId();
nsTArray<PContentPermissionRequestParent*> parentArray =
nsContentPermissionUtils::GetContentPermissionRequestParentById(id);
nsContentPermissionUtils::GetContentPermissionRequestParentById(aTabId);
// Need to close undeleted ContentPermissionRequestParents before tab is closed.
for (auto& permissionRequestParent : parentArray) {
@@ -2094,7 +2142,9 @@ ContentParent::NotifyTabDestroyed(PBrowserParent* aTab,
// There can be more than one PBrowser for a given app process
// because of popup windows. When the last one closes, shut
// us down.
if (ManagedPBrowserParent().Length() == 1) {
ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
nsTArray<TabId> tabIds = cpm->GetTabParentsByProcessId(this->ChildID());
if (tabIds.Length() == 1) {
// In the case of normal shutdown, send a shutdown message to child to
// allow it to perform shutdown tasks.
MessageLoop::current()->PostTask(
@@ -4555,30 +4605,34 @@ ContentParent::RecvAddIdleObserver(const uint64_t& aObserver, const uint32_t& aI
{
nsresult rv;
nsCOMPtr<nsIIdleService> idleService =
do_GetService("@mozilla.org/widget/idleservice;1", &rv);
do_GetService("@mozilla.org/widget/idleservice;1", &rv);
NS_ENSURE_SUCCESS(rv, false);
nsRefPtr<ParentIdleListener> listener = new ParentIdleListener(this, aObserver);
mIdleListeners.Put(aObserver, listener);
idleService->AddIdleObserver(listener, aIdleTimeInS);
nsRefPtr<ParentIdleListener> listener =
new ParentIdleListener(this, aObserver, aIdleTimeInS);
rv = idleService->AddIdleObserver(listener, aIdleTimeInS);
NS_ENSURE_SUCCESS(rv, false);
mIdleListeners.AppendElement(listener);
return true;
}
bool
ContentParent::RecvRemoveIdleObserver(const uint64_t& aObserver, const uint32_t& aIdleTimeInS)
{
nsresult rv;
nsCOMPtr<nsIIdleService> idleService =
do_GetService("@mozilla.org/widget/idleservice;1", &rv);
NS_ENSURE_SUCCESS(rv, false);
nsRefPtr<ParentIdleListener> listener;
bool found = mIdleListeners.Get(aObserver, &listener);
if (found) {
mIdleListeners.Remove(aObserver);
idleService->RemoveIdleObserver(listener, aIdleTimeInS);
for (int32_t i = mIdleListeners.Length() - 1; i >= 0; --i) {
listener = static_cast<ParentIdleListener*>(mIdleListeners[i].get());
if (listener->mObserver == aObserver &&
listener->mTime == aIdleTimeInS) {
nsresult rv;
nsCOMPtr<nsIIdleService> idleService =
do_GetService("@mozilla.org/widget/idleservice;1", &rv);
NS_ENSURE_SUCCESS(rv, false);
idleService->RemoveIdleObserver(listener, aIdleTimeInS);
mIdleListeners.RemoveElementAt(i);
break;
}
}
return true;
}
@@ -4780,8 +4834,12 @@ ContentParent::AllocateTabId(const TabId& aOpenerTabId,
{
TabId tabId;
if (XRE_IsParentProcess()) {
ContentProcessManager *cpm = ContentProcessManager::GetSingleton();
ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
tabId = cpm->AllocateTabId(aOpenerTabId, aContext, aCpId);
// Add appId's reference count in oop case
if (tabId) {
PermissionManagerAddref(aCpId, tabId);
}
}
else {
ContentChild::GetSingleton()->SendAllocateTabId(aOpenerTabId,
@@ -4794,14 +4852,27 @@ ContentParent::AllocateTabId(const TabId& aOpenerTabId,
/*static*/ void
ContentParent::DeallocateTabId(const TabId& aTabId,
const ContentParentId& aCpId)
const ContentParentId& aCpId,
bool aMarkedDestroying)
{
if (XRE_IsParentProcess()) {
// Release appId's reference count in oop case
if (aTabId) {
PermissionManagerRelease(aCpId, aTabId);
}
ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
ContentParent* cp = cpm->GetContentProcessById(aCpId);
cp->NotifyTabDestroyed(aTabId, aMarkedDestroying);
ContentProcessManager::GetSingleton()->DeallocateTabId(aCpId,
aTabId);
}
else {
ContentChild::GetSingleton()->SendDeallocateTabId(aTabId);
ContentChild::GetSingleton()->SendDeallocateTabId(aTabId,
aCpId,
aMarkedDestroying);
}
}
@@ -4819,9 +4890,19 @@ ContentParent::RecvAllocateTabId(const TabId& aOpenerTabId,
}
bool
ContentParent::RecvDeallocateTabId(const TabId& aTabId)
ContentParent::RecvDeallocateTabId(const TabId& aTabId,
const ContentParentId& aCpId,
const bool& aMarkedDestroying)
{
DeallocateTabId(aTabId, this->ChildID());
DeallocateTabId(aTabId, aCpId, aMarkedDestroying);
return true;
}
bool
ContentParent::RecvNotifyTabDestroying(const TabId& aTabId,
const ContentParentId& aCpId)
{
NotifyTabDestroying(aTabId, aCpId);
return true;
}
@@ -4992,6 +5073,38 @@ ContentParent::DeallocPContentPermissionRequestParent(PContentPermissionRequestP
return true;
}
/* static */ bool
ContentParent::PermissionManagerAddref(const ContentParentId& aCpId,
const TabId& aTabId)
{
MOZ_ASSERT(XRE_IsParentProcess(),
"Call PermissionManagerAddref in content process!");
ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
uint32_t appId = cpm->GetAppIdByProcessAndTabId(aCpId, aTabId);
nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager();
if (appId != nsIScriptSecurityManager::NO_APP_ID && permMgr) {
permMgr->AddrefAppId(appId);
return true;
}
return false;
}
/* static */ bool
ContentParent::PermissionManagerRelease(const ContentParentId& aCpId,
const TabId& aTabId)
{
MOZ_ASSERT(XRE_IsParentProcess(),
"Call PermissionManagerRelease in content process!");
ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
uint32_t appId = cpm->GetAppIdByProcessAndTabId(aCpId, aTabId);
nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager();
if (appId != nsIScriptSecurityManager::NO_APP_ID && permMgr) {
permMgr->ReleaseAppId(appId);
return true;
}
return false;
}
bool
ContentParent::RecvGetBrowserConfiguration(const nsCString& aURI, BrowserConfiguration* aConfig)
{
+30 -7
View File
@@ -208,9 +208,10 @@ public:
virtual bool KillChild() override;
/** Notify that a tab is beginning its destruction sequence. */
void NotifyTabDestroying(PBrowserParent* aTab);
static void NotifyTabDestroying(const TabId& aTabId,
const ContentParentId& aCpId);
/** Notify that a tab was destroyed during normal operation. */
void NotifyTabDestroyed(PBrowserParent* aTab,
void NotifyTabDestroyed(const TabId& aTabId,
bool aNotifiedDestroying);
TestShellParent* CreateTestShell();
@@ -223,7 +224,21 @@ public:
const IPCTabContext& aContext,
const ContentParentId& aCpId);
static void
DeallocateTabId(const TabId& aTabId, const ContentParentId& aCpId);
DeallocateTabId(const TabId& aTabId,
const ContentParentId& aCpId,
bool aMarkedDestroying);
/*
* Add the appId's reference count by the given ContentParentId and TabId
*/
static bool
PermissionManagerAddref(const ContentParentId& aCpId, const TabId& aTabId);
/*
* Release the appId's reference count by the given ContentParentId and TabId
*/
static bool
PermissionManagerRelease(const ContentParentId& aCpId, const TabId& aTabId);
static bool
GetBrowserConfiguration(const nsCString& aURI, BrowserConfiguration& aConfig);
@@ -344,7 +359,12 @@ public:
const ContentParentId& aCpId,
TabId* aTabId) override;
virtual bool RecvDeallocateTabId(const TabId& aTabId) override;
virtual bool RecvDeallocateTabId(const TabId& aTabId,
const ContentParentId& aCpId,
const bool& aMarkedDestroying) override;
virtual bool RecvNotifyTabDestroying(const TabId& aTabId,
const ContentParentId& aCpId) override;
nsTArray<TabContext> GetManagedTabContext();
@@ -914,7 +934,7 @@ private:
nsRefPtr<nsConsoleService> mConsoleService;
nsConsoleService* GetConsoleService();
nsDataHashtable<nsUint64HashKey, nsRefPtr<ParentIdleListener> > mIdleListeners;
nsTArray<nsCOMPtr<nsIObserver>> mIdleListeners;
#ifdef MOZ_X11
// Dup of child's X socket, used to scope its resources to this
@@ -945,17 +965,20 @@ private:
} // namespace mozilla
class ParentIdleListener : public nsIObserver {
friend class mozilla::dom::ContentParent;
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
ParentIdleListener(mozilla::dom::ContentParent* aParent, uint64_t aObserver)
: mParent(aParent), mObserver(aObserver)
ParentIdleListener(mozilla::dom::ContentParent* aParent, uint64_t aObserver, uint32_t aTime)
: mParent(aParent), mObserver(aObserver), mTime(aTime)
{}
private:
virtual ~ParentIdleListener() {}
nsRefPtr<mozilla::dom::ContentParent> mParent;
uint64_t mObserver;
uint32_t mTime;
};
#endif
+36
View File
@@ -12,6 +12,7 @@
#include "mozilla/ClearOnShutdown.h"
#include "nsPrintfCString.h"
#include "nsIScriptSecurityManager.h"
// XXX need another bug to move this to a common header.
#ifdef DISABLE_ASSERTS_FOR_FUZZING
@@ -334,5 +335,40 @@ ContentProcessManager::GetTopLevelTabParentByProcessAndTabId(const ContentParent
return GetTabParentByProcessAndTabId(currentCpId, currentTabId);
}
nsTArray<TabId>
ContentProcessManager::GetTabParentsByProcessId(const ContentParentId& aChildCpId)
{
MOZ_ASSERT(NS_IsMainThread());
nsTArray<TabId> tabIdList;
auto iter = mContentParentMap.find(aChildCpId);
if (NS_WARN_IF(iter == mContentParentMap.end())) {
ASSERT_UNLESS_FUZZING();
return Move(tabIdList);
}
for (auto remoteFrameIter = iter->second.mRemoteFrames.begin();
remoteFrameIter != iter->second.mRemoteFrames.end();
++remoteFrameIter) {
tabIdList.AppendElement(remoteFrameIter->first);
}
return Move(tabIdList);
}
uint32_t
ContentProcessManager::GetAppIdByProcessAndTabId(const ContentParentId& aChildCpId,
const TabId& aChildTabId)
{
uint32_t appId = nsIScriptSecurityManager::NO_APP_ID;
if (aChildCpId && aChildTabId) {
TabContext tabContext;
if (GetTabContextByProcessAndTabId(aChildCpId, aChildTabId, &tabContext)) {
appId = tabContext.OwnOrContainingAppId();
}
}
return appId;
}
} // namespace dom
} // namespace mozilla
+16
View File
@@ -110,6 +110,13 @@ public:
const TabId& aChildTabId,
/*out*/ TabId* aOpenerTabId);
/**
* Get all TabParents' Ids managed by the givent content process.
* Return empty array when TabParent couldn't be found via aChildCpId
*/
nsTArray<TabId>
GetTabParentsByProcessId(const ContentParentId& aChildCpId);
/**
* Get the TabParent by the given content process and tab id.
* Return nullptr when TabParent couldn't be found via aChildCpId
@@ -135,6 +142,15 @@ public:
GetTopLevelTabParentByProcessAndTabId(const ContentParentId& aChildCpId,
const TabId& aChildTabId);
/**
* Return appId by given TabId and ContentParentId.
* It will return nsIScriptSecurityManager::NO_APP_ID
* if the given tab is not an app.
*/
uint32_t
GetAppIdByProcessAndTabId(const ContentParentId& aChildCpId,
const TabId& aChildTabId);
private:
static StaticAutoPtr<ContentProcessManager> sSingleton;
TabId mUniqueId;
+8 -1
View File
@@ -980,8 +980,15 @@ parent:
*/
sync AllocateTabId(TabId openerTabId, IPCTabContext context, ContentParentId cpId)
returns (TabId tabId);
async DeallocateTabId(TabId tabId);
async DeallocateTabId(TabId tabId,
ContentParentId cpId,
bool aMarkedDestroying);
/**
* Tell the chrome process there is a destruction of PBrowser(Tab)
*/
async NotifyTabDestroying(TabId tabId,
ContentParentId cpId);
/**
* Starts an offline application cache update.
* @param manifestURI
+1 -1
View File
@@ -750,7 +750,7 @@ HangMonitoredProcess::GetPluginName(nsACString& aPluginName)
return NS_ERROR_UNEXPECTED;
}
aPluginName = tag->mName;
aPluginName = tag->Name();
return NS_OK;
}
+46 -12
View File
@@ -16,8 +16,10 @@
#include "nsAccessibilityService.h"
#endif
#include "mozilla/BrowserElementParent.h"
#include "mozilla/dom/ContentBridgeParent.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/DataTransfer.h"
#include "mozilla/dom/Event.h"
#include "mozilla/dom/indexedDB/ActorsParent.h"
#include "mozilla/plugins/PluginWidgetParent.h"
#include "mozilla/EventStateManager.h"
@@ -430,11 +432,9 @@ TabParent::IsVisible()
}
void
TabParent::Destroy()
TabParent::DestroyInternal()
{
if (mIsDestroyed) {
return;
}
IMEStateManager::OnTabParentDestroying(this);
RemoveWindowListeners();
@@ -447,11 +447,6 @@ TabParent::Destroy()
RemoveTabParentFromTable(frame->GetLayersId());
frame->Destroy();
}
mIsDestroyed = true;
if (XRE_IsParentProcess()) {
Manager()->AsContentParent()->NotifyTabDestroying(this);
}
// Let all PluginWidgets know we are tearing down. Prevents
// these objects from sending async events after the child side
@@ -460,6 +455,24 @@ TabParent::Destroy()
for (uint32_t idx = 0; idx < kids.Length(); ++idx) {
static_cast<mozilla::plugins::PluginWidgetParent*>(kids[idx])->ParentDestroy();
}
}
void
TabParent::Destroy()
{
if (mIsDestroyed) {
return;
}
DestroyInternal();
mIsDestroyed = true;
if (XRE_IsParentProcess()) {
ContentParent::NotifyTabDestroying(this->GetTabId(), Manager()->AsContentParent()->ChildID());
} else {
ContentParent::NotifyTabDestroying(this->GetTabId(), Manager()->ChildID());
}
mMarkedDestroying = true;
}
@@ -468,12 +481,15 @@ bool
TabParent::Recv__delete__()
{
if (XRE_IsParentProcess()) {
Manager()->AsContentParent()->NotifyTabDestroyed(this, mMarkedDestroying);
ContentParent::DeallocateTabId(mTabId,
Manager()->AsContentParent()->ChildID());
Manager()->AsContentParent()->ChildID(),
mMarkedDestroying);
}
else {
ContentParent::DeallocateTabId(mTabId, ContentParentId(0));
Manager()->AsContentBridgeParent()->NotifyTabDestroyed();
ContentParent::DeallocateTabId(mTabId,
Manager()->ChildID(),
mMarkedDestroying);
}
return true;
@@ -482,8 +498,26 @@ TabParent::Recv__delete__()
void
TabParent::ActorDestroy(ActorDestroyReason why)
{
// Even though TabParent::Destroy calls this, we need to do it here too in
// case of a crash.
IMEStateManager::OnTabParentDestroying(this);
// Prevent executing ContentParent::NotifyTabDestroying in
// TabParent::Destroy() called by frameLoader->DestroyComplete() below
// when tab crashes in contentprocess because ContentParent::ActorDestroy()
// in main process will be triggered before this function
// and remove the process information that
// ContentParent::NotifyTabDestroying need from mContentParentMap.
// When tab crashes in content process,
// there is no need to call ContentParent::NotifyTabDestroying
// because the jobs in ContentParent::NotifyTabDestroying
// will be done by ContentParent::ActorDestroy.
if (XRE_IsContentProcess() && why == AbnormalShutdown && !mIsDestroyed) {
DestroyInternal();
mIsDestroyed = true;
}
nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader(true);
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
if (frameLoader) {
+1
View File
@@ -478,6 +478,7 @@ protected:
LayoutDeviceIntPoint mChromeOffset;
private:
void DestroyInternal();
already_AddRefed<nsFrameLoader> GetFrameLoader(bool aUseCachedFrameLoaderAfterDestroy = false) const;
nsRefPtr<nsIContentParent> mManager;
void TryCacheDPIAndScale();
+8
View File
@@ -10,6 +10,7 @@
#include "mozilla/Preferences.h"
#include "mozilla/dom/File.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/ContentBridgeParent.h"
#include "mozilla/dom/PTabContext.h"
#include "mozilla/dom/PermissionMessageUtils.h"
#include "mozilla/dom/StructuredCloneUtils.h"
@@ -46,6 +47,13 @@ nsIContentParent::AsContentParent()
return static_cast<ContentParent*>(this);
}
ContentBridgeParent*
nsIContentParent::AsContentBridgeParent()
{
MOZ_ASSERT(IsContentBridgeParent());
return static_cast<ContentBridgeParent*>(this);
}
PJavaScriptParent*
nsIContentParent::AllocPJavaScriptParent()
{
+3
View File
@@ -38,6 +38,7 @@ class BlobConstructorParams;
class BlobImpl;
class BlobParent;
class ContentParent;
class ContentBridgeParent;
class IPCTabContext;
class PBlobParent;
class PBrowserParent;
@@ -77,6 +78,8 @@ public:
virtual bool IsContentParent() { return false; }
ContentParent* AsContentParent();
virtual bool IsContentBridgeParent() { return false; }
ContentBridgeParent* AsContentBridgeParent();
protected: // methods
bool CanOpenBrowser(const IPCTabContext& aContext);
+55
View File
@@ -0,0 +1,55 @@
var gBasePath = "tests/dom/ipc/tests/";
function handleRequest(request, response) {
var query = getQuery(request);
var testToken = '';
if ('testToken' in query) {
testToken = query.testToken;
}
var template = '';
if ('template' in query) {
template = query.template;
}
var template = gBasePath + template;
response.setHeader("Content-Type", "application/x-web-app-manifest+json", false);
response.write(readTemplate(template).replace(/TESTTOKEN/g, testToken));
}
// Copy-pasted incantations. There ought to be a better way to synchronously read
// a file into a string, but I guess we're trying to discourage that.
function readTemplate(path) {
var file = Components.classes["@mozilla.org/file/directory_service;1"].
getService(Components.interfaces.nsIProperties).
get("CurWorkD", Components.interfaces.nsILocalFile);
var fis = Components.classes['@mozilla.org/network/file-input-stream;1'].
createInstance(Components.interfaces.nsIFileInputStream);
var cis = Components.classes["@mozilla.org/intl/converter-input-stream;1"].
createInstance(Components.interfaces.nsIConverterInputStream);
var split = path.split("/");
for(var i = 0; i < split.length; ++i) {
file.append(split[i]);
}
fis.init(file, -1, -1, false);
cis.init(fis, "UTF-8", 0, 0);
var data = "";
let str = {};
let read = 0;
do {
read = cis.readString(0xffffffff, str); // read as much as we can and put it in str.value
data += str.value;
} while (read != 0);
cis.close();
return data;
}
function getQuery(request) {
var query = {};
request.queryString.split('&').forEach(function (val) {
var [name, value] = val.split('=');
query[name] = unescape(value);
});
return query;
}
+6
View File
@@ -0,0 +1,6 @@
{
"name": "Nested-OOP",
"description": "Nested-OOP test app used for mochitest.",
"launch_path": "/tests/dom/ipc/tests/TESTTOKEN",
"icons": { "128": "default_icon" }
}
+36
View File
@@ -12,3 +12,39 @@ skip-if = toolkit != 'gonk'
run-if = toolkit == 'gonk'
[test_child_docshell.html]
run-if = toolkit != 'cocoa' # disabled due to hangs, see changeset 6852e7c47edf
[test_permission_for_in_process_app.html]
skip-if = e10s || os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app
support-files =
test_permission_helper.js
[test_permission_for_oop_app.html]
skip-if = buildapp == 'mulet' || os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app
support-files =
file_app.sjs
file_app.template.webapp
test_permission_helper.js
test_permission_embed.html
test_permission_framescript.js
[test_permission_for_nested_oop_app.html]
skip-if = buildapp == 'mulet' || os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app
support-files =
file_app.sjs
file_app.template.webapp
test_permission_helper.js
test_permission_embed.html
test_permission_framescript.js
[test_permission_for_two_oop_apps.html]
skip-if = buildapp == 'mulet' || os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app
support-files =
file_app.sjs
file_app.template.webapp
test_permission_helper.js
test_permission_embed.html
test_permission_framescript.js
[test_permission_when_oop_app_crashes.html]
skip-if = buildapp == 'mulet' || os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app
support-files =
file_app.sjs
file_app.template.webapp
test_permission_helper.js
test_permission_embed.html
test_permission_framescript.js
+51
View File
@@ -0,0 +1,51 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>oop-test apps</title>
<script type="application/javascript">
"use strict";
var queryString = decodeURIComponent(window.location.hash.substring(1));
// test-target-app
var APP_URL = "http://example.org";
var APP_MANIFEST = "http://example.org/manifest.webapp";
var APP_IFRAME_ID = "test-target";
function removeAppFrame(){
var ifr = document.getElementById(APP_IFRAME_ID);
ifr.remove();
}
function allocateAppFrame(source, manifestURL, useRemote) {
var ifr = document.createElement('iframe');
ifr.setAttribute('id', APP_IFRAME_ID);
ifr.setAttribute('remote', useRemote? "true" : "false");
ifr.setAttribute('mozbrowser', 'true');
ifr.setAttribute('mozapp', manifestURL);
ifr.setAttribute('src', source);
ifr.addEventListener('mozbrowserloadend', function () {
if (queryString == "crash") {
// Send a crash request to parent-process
sendMessgeToParent('crash');
} else {
removeAppFrame();
}
});
document.body.appendChild(ifr);
}
function sendMessgeToParent(msg) {
window.alert(msg);
}
</script>
</head>
<body>
<script>
allocateAppFrame(APP_URL, APP_MANIFEST, true);
</script>
</body>
</html>
@@ -0,0 +1,43 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1114507
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1114507</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=1114507">Mozilla Bug1114507</a>
<p id="display"></p>
<div id="container" style="display: none"></div>
<script type="text/javascript" src="test_permission_helper.js"></script>
<script type="application/javascript">
// Put all the tests in order
var tests = [
// Setup preferences and permissions
setupPrefsAndPermissions,
// +-------------------------------------------+
// | Test 1: Open and close a in-process |
// | test-target-app in chrome-process |
// +-------------------------------------------+
//
// level
// 1 chrome process <-- app is here
// Add permission to app
function () {
addPermissionToApp(APP_URL, APP_MANIFEST);
},
test1
];
runTests();
</script>
</body>
</html>
@@ -0,0 +1,75 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1114507
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1114507</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=1114507">Mozilla Bug1114507</a>
<p id="display"></p>
<div id="container" style="display: none"></div>
<script type="text/javascript" src="test_permission_helper.js"></script>
<script type="application/javascript">
// Put all the tests in order
var tests = [
// Setup preferences and permissions
setupPrefsAndPermissions,
// ****************************************************
// Setup the enviroment for testing nested-oop cases: *
// test 3,4,5 *
// ****************************************************
// Install the app
installApp,
// Allow permission for embedApp to open mozbrowser and mozapp
function() {
var appId = gAppsService.getAppLocalIdByManifestURL(embedAppHostedManifestURL);
var context = { url: embedApp.origin,
appId: appId,
isInBrowserElement: false };
setupOpenAppPermission(context, runTests);
},
// +-------------------------------------------+
// | Test 3: Open a test-target-app on 3rd |
// | level child-process then close it |
// +-------------------------------------------+
//
// level
// 1 chrome process
// |
// 2 child process
// |
// 3 child process <-- app is here
// Add permission to app
function() {
addPermissionToApp(APP_URL, APP_MANIFEST);
},
test3,
// Remove the child-process on 2nd level
function() {
var afterShutdown = function() {
runTests();
};
afterContentShutdown(1, afterShutdown);
removeAppFrame(APP_IFRAME_ID);
},
uninstallApp
];
runTests();
</script>
</body>
</html>
@@ -0,0 +1,45 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1114507
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1114507</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=1114507">Mozilla Bug1114507</a>
<p id="display"></p>
<div id="container" style="display: none"></div>
<script type="text/javascript" src="test_permission_helper.js"></script>
<script type="application/javascript">
// Put all the tests in order
var tests = [
// Setup preferences and permissions
setupPrefsAndPermissions,
// +------------------------------------------+
// | Test 2: Open and close a test-target-app |
// | on 2nd level child-process |
// +------------------------------------------+
//
// level
// 1 chrome process
// |
// 2 child process <-- app is here
// Add permission to app
function() {
addPermissionToApp(APP_URL, APP_MANIFEST);
},
test2,
];
runTests();
</script>
</body>
</html>
@@ -0,0 +1,88 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1114507
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1114507</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=1114507">Mozilla Bug1114507</a>
<p id="display"></p>
<div id="container" style="display: none"></div>
<script type="text/javascript" src="test_permission_helper.js"></script>
<script type="application/javascript">
// Put all the tests in order
var tests = [
// Setup preferences and permissions
setupPrefsAndPermissions,
// ****************************************************
// Setup the enviroment for testing nested-oop cases: *
// test 3,4,5 *
// ****************************************************
// Install the app
installApp,
// Allow permission for embedApp to open mozbrowser and mozapp
function() {
var appId = gAppsService.getAppLocalIdByManifestURL(embedAppHostedManifestURL);
var context = { url: embedApp.origin,
appId: appId,
isInBrowserElement: false };
setupOpenAppPermission(context, runTests);
},
// +---------------------------------------------------------+
// | Test 4: Open two test-target-app on 2nd and 3rd level |
// | child-processes then close the one on 3rd level |
// +---------------------------------------------------------+
//
// level
// 1 chrome process
// / \
// 2 child process child process <-- app is here
// /
// 3 child process <-- app is here
// Add permission to app
function() {
addPermissionToApp(APP_URL, APP_MANIFEST);
},
test4,
// Remove another test-target-app on 2nd level process
function() {
var afterShutdown = function() {
// We expect there is no permission for the test-target-app now
runNextIfAppHasPermission(4, false, APP_URL, APP_MANIFEST);
};
// Test permission after test-target-app
// on 2nd level process is killed
afterContentShutdown(1, afterShutdown);
removeAppFrame(APP_IFRAME_ID2);
},
// Remove the last child-process on 2nd level
function() {
var afterShutdown = function() {
runTests();
};
afterContentShutdown(1, afterShutdown);
removeAppFrame(APP_IFRAME_ID);
},
uninstallApp
];
runTests();
</script>
</body>
</html>
@@ -0,0 +1,31 @@
Components.utils.import("resource://gre/modules/Services.jsm");
let cm = Services.crashmanager;
var cpIdList = [];
var shutdownObs = {
observe: function(subject, topic, data) {
if (topic == 'ipc:content-shutdown') {
var index = cpIdList.indexOf(parseInt(data));
if (index > -1) {
cpIdList.splice(index, 1);
sendAsyncMessage('content-shutdown', '');
}
}
}
};
var createdObs = {
observe: function(subject, topic, data) {
if (topic == 'ipc:content-created') {
cpIdList.push(parseInt(data));
sendAsyncMessage('content-created', '');
}
}
};
addMessageListener('crashreporter-status', function(message) {
sendAsyncMessage('crashreporter-enable', !!cm);
});
Services.obs.addObserver(shutdownObs, 'ipc:content-shutdown', false);
Services.obs.addObserver(createdObs, 'ipc:content-created', false);
+362
View File
@@ -0,0 +1,362 @@
"use strict";
// Used to access the DOM node in this test
const DOM_PARENT_ID = "container";
const DOM_PARENT = document.getElementById(DOM_PARENT_ID);
const APP_IFRAME_ID = "appFrame";
const APP_IFRAME_ID2 = "appFrame2";
// Settings for testing the permission
const SESSION_PERSIST_MINUTES = 10;
const PERMISSION_TYPE = "geolocation";
const permManager = SpecialPowers.Cc["@mozilla.org/permissionmanager;1"]
.getService(SpecialPowers.Ci.nsIPermissionManager);
// Used to access App's information like appId
const gAppsService = SpecialPowers.Cc["@mozilla.org/AppsService;1"]
.getService(SpecialPowers.Ci.nsIAppsService);
// Target-app for this testing
const APP_URL = "http://example.org";
const APP_MANIFEST = "http://example.org/manifest.webapp";
// Used to embed a remote app that open the test-target-app above
const embedAppHostedManifestURL = window.location.origin +
'/tests/dom/ipc/tests/file_app.sjs?testToken=test_permission_embed.html&template=file_app.template.webapp';
var embedApp;
// Used to add listener for ipc:content-shutdown that
// will be triggered after ContentParent::DeallocateTabId
var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('test_permission_framescript.js'));
// Delay reporting a result until after finish() got called
SimpleTest.waitForExplicitFinish();
// Allow tests to disable the per platform app validity checks
SpecialPowers.setAllAppsLaunchable(true);
// Run tests in order
function runTests() {
if (!tests.length) {
ok(true, "pass all tests!");
SimpleTest.finish();
return;
}
var test = tests.shift();
test();
}
function test1() {
allocateAppFrame(APP_IFRAME_ID, DOM_PARENT, APP_URL, APP_MANIFEST);
var appId = gAppsService.getAppLocalIdByManifestURL(APP_MANIFEST);
if (!SpecialPowers.hasPermission( PERMISSION_TYPE,
{ url: APP_URL,
appId: appId,
isInBrowserElement: false })) {
errorHandler('[test 1] App should have permission: ' + PERMISSION_TYPE);
}
removeAppFrame(APP_IFRAME_ID);
// We expect there is no permission for the test-target-app
// after removing the in-process iframe embedding this app
runNextIfAppHasPermission(1, false, APP_URL, APP_MANIFEST);
}
function test2() {
var afterShutdown = function () {
// We expect there is no permission for the test-target-app
// after removing the remote iframe embedding this app
runNextIfAppHasPermission(2, false, APP_URL, APP_MANIFEST);
};
// Test permission after the child-process containing
// test-target-app is killed
afterContentShutdown(1, afterShutdown);
allocateAppFrame(APP_IFRAME_ID, DOM_PARENT, APP_URL, APP_MANIFEST, true);
var appId = gAppsService.getAppLocalIdByManifestURL(APP_MANIFEST);
if (!SpecialPowers.hasPermission( PERMISSION_TYPE,
{ url: APP_URL,
appId: appId,
isInBrowserElement: false })) {
errorHandler('[test 2] App should have permission: ' + PERMISSION_TYPE);
}
removeAppFrame(APP_IFRAME_ID);
}
function test3() {
var afterGrandchildShutdown = function () {
// We expect there is no permission for the test-target-app
// after removing the remote iframe embedding this app
runNextIfAppHasPermission(3, false, APP_URL, APP_MANIFEST);
};
// Test permission after the grandchild-process
// containing test-target-app is killed
afterContentShutdown(1, afterGrandchildShutdown);
allocateAppFrame(APP_IFRAME_ID,
DOM_PARENT,
embedApp.manifest.launch_path,
embedApp.manifestURL,
true);
var appId = gAppsService.getAppLocalIdByManifestURL(APP_MANIFEST);
if (!SpecialPowers.hasPermission(PERMISSION_TYPE,
{ url: APP_URL,
appId: appId,
isInBrowserElement: false })) {
errorHandler('[test 3] App should have permission: ' + PERMISSION_TYPE);
}
}
function test4() {
var afterGrandchildShutdown = function () {
// We expect there is still a permission for the test-target-app
// after killing test-target-app on 3rd-level process
runNextIfAppHasPermission(4, true, APP_URL, APP_MANIFEST);
};
// Test permission after the grandchild-process
// containing test-target-app is killed
afterContentShutdown(1, afterGrandchildShutdown);
// Open a child process(2nd level) and a grandchild process(3rd level)
// that contains a test-target-app
allocateAppFrame(APP_IFRAME_ID,
DOM_PARENT,
embedApp.manifest.launch_path,
embedApp.manifestURL,
true);
// Open another child process that contains
// another test-target-app(2nd level)
allocateAppFrame(APP_IFRAME_ID2,
DOM_PARENT,
APP_URL,
APP_MANIFEST,
true);
var appId = gAppsService.getAppLocalIdByManifestURL(APP_MANIFEST);
if (!SpecialPowers.hasPermission(PERMISSION_TYPE,
{ url: APP_URL,
appId: appId,
isInBrowserElement: false })) {
errorHandler('[test 4] App should have permission: ' + PERMISSION_TYPE);
}
}
function test5() {
var afterShutdown = function () {
// We expect there is no permission for the test-target-app
// after crashing its parent-process
runNextIfAppHasPermission(5, false, APP_URL, APP_MANIFEST);
};
// Test permission after the parent-process of test-target-app is crashed.
afterContentShutdown(2, afterShutdown);
allocateAppFrame(APP_IFRAME_ID,
DOM_PARENT,
embedApp.manifest.launch_path + '#' + encodeURIComponent('crash'),
embedApp.manifestURL,
true);
var appId = gAppsService.getAppLocalIdByManifestURL(APP_MANIFEST);
if (!SpecialPowers.hasPermission( PERMISSION_TYPE,
{ url: APP_URL,
appId: appId,
isInBrowserElement: false })) {
errorHandler('[test 5] App should have permission: ' + PERMISSION_TYPE);
}
// Crash the child-process on 2nd level after
// the grandchild process on 3rd is allocated
var handler = {'crash': function() {
gScript.sendAsyncMessage("crashreporter-status", {});
getCrashReporterStatus(function(enable) {
if (enable) {
SimpleTest.expectChildProcessCrash();
}
crashChildProcess(APP_IFRAME_ID);
});
}
};
receiveMessageFromChildFrame(APP_IFRAME_ID, handler);
}
// Setup the prefrences and permissions.
// This function should be called before any tests
function setupPrefsAndPermissions() {
SpecialPowers.pushPrefEnv({"set": [
["dom.mozBrowserFramesEnabled", true],
["dom.ipc.tabs.nested.enabled", true],
["dom.ipc.tabs.disabled", false]]},
function() {
var autoManageApp = function () {
SpecialPowers.setAllAppsLaunchable(true);
// No confirmation needed when an app is installed and uninstalled.
SpecialPowers.autoConfirmAppInstall(() => {
// This callback should trigger the first test
SpecialPowers.autoConfirmAppUninstall(runTests);
});
};
setupOpenAppPermission(document, autoManageApp);
}
);
}
function setupOpenAppPermission(ctx, callback) {
SpecialPowers.pushPermissions([
{ "type": "browser", "allow": true, "context": ctx}, // for mozbrowser
{ "type": "embed-apps", "allow": true, "context": ctx }, // for mozapp
{ "type": "webapps-manage", "allow": true, "context": ctx }], // for (un)installing apps
function checkPermissions() {
if (SpecialPowers.hasPermission("browser", ctx) &&
SpecialPowers.hasPermission("embed-apps", ctx) &&
SpecialPowers.hasPermission("webapps-manage", ctx)) {
callback();
} else {
errorHandler(">> At least one of required permissions to open app is disallowed!\n");
}
});
}
function installApp() {
// Install App from manifest
var request = navigator.mozApps.install(embedAppHostedManifestURL);
request.onerror = cbError;
request.onsuccess = function() {
// Get installed app
embedApp = request.result; // Assign to global variable
runTests();
}
}
function uninstallApp() {
var request = navigator.mozApps.mgmt.uninstall(embedApp);
request.onerror = cbError;
request.onsuccess = function() {
info("uninstall app susseccfully!");
runTests();
}
}
function removeAppFrame(id) {
var ifr = document.getElementById(id);
ifr.remove();
}
function allocateAppFrame(id, parentNode, appSRC, manifestURL, useRemote = false) {
var ifr = document.createElement('iframe');
ifr.setAttribute('id', id);
ifr.setAttribute('remote', useRemote? "true" : "false");
ifr.setAttribute('mozbrowser', 'true');
ifr.setAttribute('mozapp', manifestURL);
ifr.setAttribute('src', appSRC);
parentNode.appendChild(ifr);
}
function receiveMessageFromChildFrame(id, handlers) {
var ifr = document.getElementById(id);
ifr.addEventListener('mozbrowsershowmodalprompt', function (recvMsg) {
var msg = recvMsg.detail.message;
handlers[msg]();
});
}
function addPermissionToApp(appURL, manifestURL) {
var appId = gAppsService.getAppLocalIdByManifestURL(manifestURL);
// Get the time now. This is used for permission manager's expire_time
var now = Number(Date.now());
// Add app's permission asynchronously
SpecialPowers.pushPermissions([
{ "type":PERMISSION_TYPE,
"allow": 1,
"expireType":permManager.EXPIRE_SESSION,
"expireTime":now + SESSION_PERSIST_MINUTES*60*1000,
"context": { url: appURL,
appId: appId,
isInBrowserElement:false }
}
], function() {
runTests();
});
}
function runNextIfAppHasPermission(round, expect, appURL, manifestURL) {
var appId = gAppsService.getAppLocalIdByManifestURL(manifestURL);
var hasPerm = SpecialPowers.hasPermission(PERMISSION_TYPE,
{ url: appURL,
appId: appId,
isInBrowserElement: false });
var result = (expect==hasPerm);
if (result) {
runTests();
} else {
errorHandler( '[test ' + round + '] App should ' + ((expect)? '':'NOT ') +
'have permission: ' + PERMISSION_TYPE);
}
}
function afterContentShutdown(times, callback) {
// handle the message from test_permission_framescript.js
var num = 0;
gScript.addMessageListener('content-shutdown', function onShutdown(data) {
num += 1;
if (num >= times) {
gScript.removeMessageListener('content-shutdown', onShutdown);
callback();
}
});
}
function getCrashReporterStatus(callback) {
gScript.addMessageListener('crashreporter-enable', function getStatus(data) {
gScript.removeMessageListener('crashreporter-enable', getStatus);
callback(data);
});
}
// Inject a frame script that crashes the content process
function crashChildProcess(frameId) {
var child = document.getElementById(frameId);
var mm = SpecialPowers.getBrowserFrameMessageManager(child);
var childFrameScriptStr =
'function ContentScriptScope() {' +
'var Cu = Components.utils;' +
'Cu.import("resource://gre/modules/ctypes.jsm");' +
'var crash = function() {' +
'var zero = new ctypes.intptr_t(8);' +
'var badptr = ctypes.cast(zero, ctypes.PointerType(ctypes.int32_t));' +
'badptr.contents;' +
'};' +
'privateNoteIntentionalCrash();' +
'crash();' +
'}';
mm.loadFrameScript('data:,new ' + childFrameScriptStr, false);
}
function errorHandler(errMsg) {
ok(false, errMsg);
SimpleTest.finish();
}
function cbError(e) {
errorHandler("Error callback invoked: " + this.error.name);
}
@@ -0,0 +1,67 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1114507
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1114507</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=1114507">Mozilla Bug1114507</a>
<p id="display"></p>
<div id="container" style="display: none"></div>
<script type="text/javascript" src="test_permission_helper.js"></script>
<script type="application/javascript">
// Put all the tests in order
var tests = [
// Setup preferences and permissions
setupPrefsAndPermissions,
// ****************************************************
// Setup the enviroment for testing nested-oop cases: *
// test 3,4,5 *
// ****************************************************
// Install the app
installApp,
// Allow permission for embedApp to open mozbrowser and mozapp
function() {
var appId = gAppsService.getAppLocalIdByManifestURL(embedAppHostedManifestURL);
var context = { url: embedApp.origin,
appId: appId,
isInBrowserElement: false };
setupOpenAppPermission(context, runTests);
},
// +-----------------------------------------------+
// | Test 5: Open a test-target-app on 3rd level |
// | process then crash its parent-process |
// +-----------------------------------------------+
//
// level
// 1 chrome process
// |
// 2 child process <-- crash this process
// |
// 3 child process <-- app is here
// Add permission to app
function() {
addPermissionToApp(APP_URL, APP_MANIFEST);
},
test5,
uninstallApp
];
runTests();
</script>
</body>
</html>
+9
View File
@@ -565,6 +565,15 @@ nsJSChannel::Open2(nsIInputStream** aStream)
NS_IMETHODIMP
nsJSChannel::AsyncOpen(nsIStreamListener *aListener, nsISupports *aContext)
{
#ifdef DEBUG
{
nsCOMPtr<nsILoadInfo> loadInfo = nsIChannel::GetLoadInfo();
MOZ_ASSERT(!loadInfo || loadInfo->GetSecurityMode() == 0 ||
loadInfo->GetInitialSecurityCheckDone(),
"security flags in loadInfo but asyncOpen2() not called");
}
#endif
NS_ENSURE_ARG(aListener);
// First make sure that we have a usable inner window; we'll want to make
+24 -34
View File
@@ -34,7 +34,7 @@ const GUID MF_XVP_PLAYBACK_MODE =
{ 0xaf, 0x12, 0xcf, 0x3e, 0x23, 0x8a, 0xcc, 0xe9 }
};
DEFINE_GUID(MF_LOW_LATENCY,
DEFINE_GUID(MF_LOW_LATENCY,
0x9c27891a, 0xed7a, 0x40e1, 0x88, 0xe8, 0xb2, 0x27, 0x27, 0xa0, 0x24, 0xee);
namespace mozilla {
@@ -44,6 +44,7 @@ using layers::ImageContainer;
using layers::D3D9SurfaceImage;
using layers::D3D9RecycleAllocator;
using layers::D3D11ShareHandleImage;
using layers::D3D11RecycleAllocator;
class D3D9DXVA2Manager : public DXVA2Manager
{
@@ -412,12 +413,13 @@ private:
HRESULT CreateFormatConverter();
HRESULT CreateOutputSample(RefPtr<IMFSample>& aSample,
RefPtr<ID3D11Texture2D>& aTexture);
ID3D11Texture2D* aTexture);
RefPtr<ID3D11Device> mDevice;
RefPtr<ID3D11DeviceContext> mContext;
RefPtr<IMFDXGIDeviceManager> mDXGIDeviceManager;
RefPtr<MFTDecoder> mTransform;
RefPtr<D3D11RecycleAllocator> mTextureClientAllocator;
uint32_t mWidth;
uint32_t mHeight;
UINT mDeviceManagerToken;
@@ -483,41 +485,27 @@ D3D11DXVA2Manager::Init(nsACString& aFailureReason)
return hr;
}
mTextureClientAllocator = new D3D11RecycleAllocator(layers::ImageBridgeChild::GetSingleton(),
mDevice);
mTextureClientAllocator->SetMaxPoolSize(5);
return S_OK;
}
HRESULT
D3D11DXVA2Manager::CreateOutputSample(RefPtr<IMFSample>& aSample, RefPtr<ID3D11Texture2D>& aTexture)
D3D11DXVA2Manager::CreateOutputSample(RefPtr<IMFSample>& aSample, ID3D11Texture2D* aTexture)
{
RefPtr<IMFSample> sample;
HRESULT hr = wmf::MFCreateSample(byRef(sample));
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
D3D11_TEXTURE2D_DESC desc;
desc.Width = mWidth;
desc.Height = mHeight;
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
desc.CPUAccessFlags = 0;
desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
RefPtr<ID3D11Texture2D> texture;
hr = mDevice->CreateTexture2D(&desc, nullptr, byRef(texture));
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
RefPtr<IMFMediaBuffer> buffer;
hr = wmf::MFCreateDXGISurfaceBuffer(__uuidof(ID3D11Texture2D), texture, 0, FALSE, byRef(buffer));
hr = wmf::MFCreateDXGISurfaceBuffer(__uuidof(ID3D11Texture2D), aTexture, 0, FALSE, byRef(buffer));
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
sample->AddBuffer(buffer);
aSample = sample;
aTexture = texture;
return S_OK;
}
@@ -535,11 +523,23 @@ D3D11DXVA2Manager::CopyToImage(IMFSample* aVideoSample,
// to create a copy of that frame as a sharable resource, save its share
// handle, and put that handle into the rendering pipeline.
HRESULT hr = mTransform->Input(aVideoSample);
ImageFormat format = ImageFormat::D3D11_SHARE_HANDLE_TEXTURE;
nsRefPtr<Image> image(aContainer->CreateImage(format));
NS_ENSURE_TRUE(image, E_FAIL);
NS_ASSERTION(image->GetFormat() == ImageFormat::D3D11_SHARE_HANDLE_TEXTURE,
"Wrong format?");
D3D11ShareHandleImage* videoImage = static_cast<D3D11ShareHandleImage*>(image.get());
HRESULT hr = videoImage->SetData(D3D11ShareHandleImage::Data(mTextureClientAllocator,
gfx::IntSize(mWidth, mHeight),
aRegion));
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
hr = mTransform->Input(aVideoSample);
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
RefPtr<IMFSample> sample;
RefPtr<ID3D11Texture2D> texture;
RefPtr<ID3D11Texture2D> texture = videoImage->GetTexture();
hr = CreateOutputSample(sample, texture);
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
@@ -555,16 +555,6 @@ D3D11DXVA2Manager::CopyToImage(IMFSample* aVideoSample,
keyedMutex->ReleaseSync(0);
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
ImageFormat format = ImageFormat::D3D11_SHARE_HANDLE_TEXTURE;
nsRefPtr<Image> image(aContainer->CreateImage(format));
NS_ENSURE_TRUE(image, E_FAIL);
NS_ASSERTION(image->GetFormat() == ImageFormat::D3D11_SHARE_HANDLE_TEXTURE,
"Wrong format?");
D3D11ShareHandleImage* videoImage = static_cast<D3D11ShareHandleImage*>(image.get());
hr = videoImage->SetData(D3D11ShareHandleImage::Data(texture, mDevice, mContext, aRegion));
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
image.forget(aOutImage);
return S_OK;
@@ -0,0 +1,16 @@
ifdef MOZ_WEBSPEECH_MODELS
MODELSPS_KEEP_PATH := 1
MODELSPS_FILES := models/dict/cmu07a.dic \
models/en-us-semi/mixture_weights \
models/en-us-semi/feat.params \
models/en-us-semi/mdef \
models/en-us-semi/means \
models/en-us-semi/noisedict \
models/en-us-semi/sendump \
models/en-us-semi/transition_matrices \
models/en-us-semi/variances
MODELSPS_DEST := $(DIST)/bin/models
INSTALL_TARGETS += MODELSPS
endif
@@ -0,0 +1,345 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsThreadUtils.h"
#include "nsXPCOMCIDInternal.h"
#include "PocketSphinxSpeechRecognitionService.h"
#include "nsIFile.h"
#include "SpeechGrammar.h"
#include "SpeechRecognition.h"
#include "SpeechRecognitionAlternative.h"
#include "SpeechRecognitionResult.h"
#include "SpeechRecognitionResultList.h"
#include "nsIObserverService.h"
#include "mozilla/Services.h"
#include "nsDirectoryServiceDefs.h"
#include "nsDirectoryServiceUtils.h"
#include "nsMemory.h"
extern "C" {
#include "pocketsphinx/pocketsphinx.h"
#include "sphinxbase/sphinx_config.h"
#include "sphinxbase/jsgf.h"
}
namespace mozilla {
using namespace dom;
class DecodeResultTask : public nsRunnable
{
public:
DecodeResultTask(const nsString& hypstring,
WeakPtr<dom::SpeechRecognition> recognition)
: mResult(hypstring),
mRecognition(recognition),
mWorkerThread(do_GetCurrentThread())
{
MOZ_ASSERT(
!NS_IsMainThread()); // This should be running on the worker thread
}
NS_IMETHOD
Run()
{
MOZ_ASSERT(NS_IsMainThread()); // This method is supposed to run on the main
// thread!
// Declare javascript result events
nsRefPtr<SpeechEvent> event = new SpeechEvent(
mRecognition, SpeechRecognition::EVENT_RECOGNITIONSERVICE_FINAL_RESULT);
SpeechRecognitionResultList* resultList =
new SpeechRecognitionResultList(mRecognition);
SpeechRecognitionResult* result = new SpeechRecognitionResult(mRecognition);
SpeechRecognitionAlternative* alternative =
new SpeechRecognitionAlternative(mRecognition);
alternative->mTranscript = mResult;
alternative->mConfidence = 100;
result->mItems.AppendElement(alternative);
resultList->mItems.AppendElement(result);
event->mRecognitionResultList = resultList;
NS_DispatchToMainThread(event);
// If we don't destroy the thread when we're done with it, it will hang
// around forever... bad!
// But thread->Shutdown must be called from the main thread, not from the
// thread itself.
return mWorkerThread->Shutdown();
}
private:
nsString mResult;
WeakPtr<dom::SpeechRecognition> mRecognition;
nsCOMPtr<nsIThread> mWorkerThread;
};
class DecodeTask : public nsRunnable
{
public:
DecodeTask(WeakPtr<dom::SpeechRecognition> recogntion,
const nsTArray<int16_t>& audiovector, ps_decoder_t* ps)
: mRecognition(recogntion), mAudiovector(audiovector), mPs(ps)
{
}
NS_IMETHOD
Run()
{
char const* hyp;
int rv;
int32 score;
nsAutoCString hypoValue;
rv = ps_start_utt(mPs);
rv = ps_process_raw(mPs, &mAudiovector[0], mAudiovector.Length(), FALSE,
FALSE);
rv = ps_end_utt(mPs);
if (rv >= 0) {
hyp = ps_get_hyp(mPs, &score);
if (hyp == nullptr) {
hypoValue.Assign("ERROR");
} else {
hypoValue.Assign(hyp);
}
}
nsCOMPtr<nsIRunnable> resultrunnable =
new DecodeResultTask(NS_ConvertUTF8toUTF16(hypoValue), mRecognition);
return NS_DispatchToMainThread(resultrunnable);
}
private:
WeakPtr<dom::SpeechRecognition> mRecognition;
nsTArray<int16_t> mAudiovector;
ps_decoder_t* mPs;
};
NS_IMPL_ISUPPORTS(PocketSphinxSpeechRecognitionService,
nsISpeechRecognitionService, nsIObserver)
PocketSphinxSpeechRecognitionService::PocketSphinxSpeechRecognitionService()
{
mSpeexState = nullptr;
// get root folder
nsCOMPtr<nsIFile> tmpFile;
nsAutoString aStringAMPath; // am folder
nsAutoString aStringDictPath; // dict folder
NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(tmpFile));
#if defined(XP_WIN) // for some reason, on windows NS_GRE_DIR is not bin root,
// but bin/browser
tmpFile->AppendRelativePath(NS_LITERAL_STRING(".."));
#endif
tmpFile->AppendRelativePath(NS_LITERAL_STRING("models"));
tmpFile->AppendRelativePath(NS_LITERAL_STRING("en-us-semi"));
tmpFile->GetPath(aStringAMPath);
NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(tmpFile));
#if defined(XP_WIN) // for some reason, on windows NS_GRE_DIR is not bin root,
// but bin/browser
tmpFile->AppendRelativePath(NS_LITERAL_STRING(".."));
#endif
tmpFile->AppendRelativePath(NS_LITERAL_STRING("models")); //
tmpFile->AppendRelativePath(NS_LITERAL_STRING("dict")); //
tmpFile->AppendRelativePath(NS_LITERAL_STRING("cmu07a.dic")); //
tmpFile->GetPath(aStringDictPath);
// FOR B2G PATHS HARDCODED (APPEND /DATA ON THE BEGINING, FOR DESKTOP, ONLY
// MODELS/ RELATIVE TO ROOT
mPSConfig = cmd_ln_init(nullptr, ps_args(), TRUE, "-hmm",
ToNewUTF8String(aStringAMPath), // acoustic model
"-dict", ToNewUTF8String(aStringDictPath), nullptr);
if (mPSConfig == nullptr) {
ISDecoderCreated = false;
} else {
mPSHandle = ps_init(mPSConfig);
if (mPSHandle == nullptr) {
ISDecoderCreated = false;
} else {
ISDecoderCreated = true;
}
}
ISGrammarCompiled = false;
}
PocketSphinxSpeechRecognitionService::~PocketSphinxSpeechRecognitionService()
{
if (mPSConfig) {
free(mPSConfig);
}
if (mPSHandle) {
free(mPSHandle);
}
mSpeexState = nullptr;
}
// CALL START IN JS FALLS HERE
NS_IMETHODIMP
PocketSphinxSpeechRecognitionService::Initialize(
WeakPtr<SpeechRecognition> aSpeechRecognition)
{
if (!ISDecoderCreated || !ISGrammarCompiled) {
return NS_ERROR_NOT_INITIALIZED;
} else {
mAudioVector.Clear();
if (mSpeexState) {
mSpeexState = nullptr;
}
mRecognition = aSpeechRecognition;
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
obs->AddObserver(this, SPEECH_RECOGNITION_TEST_EVENT_REQUEST_TOPIC, false);
obs->AddObserver(this, SPEECH_RECOGNITION_TEST_END_TOPIC, false);
return NS_OK;
}
}
NS_IMETHODIMP
PocketSphinxSpeechRecognitionService::ProcessAudioSegment(
AudioSegment* aAudioSegment, int32_t aSampleRate)
{
if (!mSpeexState) {
mSpeexState = speex_resampler_init(1, aSampleRate, 16000,
SPEEX_RESAMPLER_QUALITY_MAX, nullptr);
}
aAudioSegment->ResampleChunks(mSpeexState, aSampleRate, 16000);
AudioSegment::ChunkIterator iterator(*aAudioSegment);
while (!iterator.IsEnded()) {
mozilla::AudioChunk& chunk = *(iterator);
MOZ_ASSERT(chunk.mBuffer);
const int16_t* buf = static_cast<const int16_t*>(chunk.mChannelData[0]);
for (int i = 0; i < iterator->mDuration; i++) {
mAudioVector.AppendElement((int16_t)buf[i]);
}
iterator.Next();
}
return NS_OK;
}
NS_IMETHODIMP
PocketSphinxSpeechRecognitionService::SoundEnd()
{
speex_resampler_destroy(mSpeexState);
mSpeexState = nullptr;
// To create a new thread, get the thread manager
nsCOMPtr<nsIThreadManager> tm = do_GetService(NS_THREADMANAGER_CONTRACTID);
nsCOMPtr<nsIThread> decodethread;
nsresult rv = tm->NewThread(0, 0, getter_AddRefs(decodethread));
if (NS_FAILED(rv)) {
// In case of failure, call back immediately with an empty string which
// indicates failure
return NS_OK;
}
nsCOMPtr<nsIRunnable> r =
new DecodeTask(mRecognition, mAudioVector, mPSHandle);
decodethread->Dispatch(r, nsIEventTarget::DISPATCH_NORMAL);
return NS_OK;
}
NS_IMETHODIMP
PocketSphinxSpeechRecognitionService::ValidateAndSetGrammarList(
SpeechGrammar* aSpeechGrammar,
nsISpeechGrammarCompilationCallback* aCallback)
{
if (!ISDecoderCreated) {
ISGrammarCompiled = false;
} else if (aSpeechGrammar) {
nsAutoString grammar;
ErrorResult rv;
aSpeechGrammar->GetSrc(grammar, rv);
int result = ps_set_jsgf_string(mPSHandle, "name",
NS_ConvertUTF16toUTF8(grammar).get());
ps_set_search(mPSHandle, "name");
if (result != 0) {
ISGrammarCompiled = false;
} else {
ISGrammarCompiled = true;
}
} else {
ISGrammarCompiled = false;
}
return ISGrammarCompiled ? NS_OK : NS_ERROR_NOT_INITIALIZED;
}
NS_IMETHODIMP
PocketSphinxSpeechRecognitionService::Abort()
{
return NS_OK;
}
NS_IMETHODIMP
PocketSphinxSpeechRecognitionService::Observe(nsISupports* aSubject,
const char* aTopic,
const char16_t* aData)
{
MOZ_ASSERT(mRecognition->mTestConfig.mFakeRecognitionService,
"Got request to fake recognition service event, "
"but " TEST_PREFERENCE_FAKE_RECOGNITION_SERVICE " is not set");
if (!strcmp(aTopic, SPEECH_RECOGNITION_TEST_END_TOPIC)) {
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
obs->RemoveObserver(this, SPEECH_RECOGNITION_TEST_EVENT_REQUEST_TOPIC);
obs->RemoveObserver(this, SPEECH_RECOGNITION_TEST_END_TOPIC);
return NS_OK;
}
const nsDependentString eventName = nsDependentString(aData);
if (eventName.EqualsLiteral("EVENT_RECOGNITIONSERVICE_ERROR")) {
mRecognition->DispatchError(
SpeechRecognition::EVENT_RECOGNITIONSERVICE_ERROR,
SpeechRecognitionErrorCode::Network, // TODO different codes?
NS_LITERAL_STRING("RECOGNITIONSERVICE_ERROR test event"));
} else if (eventName.EqualsLiteral("EVENT_RECOGNITIONSERVICE_FINAL_RESULT")) {
nsRefPtr<SpeechEvent> event = new SpeechEvent(
mRecognition, SpeechRecognition::EVENT_RECOGNITIONSERVICE_FINAL_RESULT);
event->mRecognitionResultList = BuildMockResultList();
NS_DispatchToMainThread(event);
}
return NS_OK;
}
SpeechRecognitionResultList*
PocketSphinxSpeechRecognitionService::BuildMockResultList()
{
SpeechRecognitionResultList* resultList =
new SpeechRecognitionResultList(mRecognition);
SpeechRecognitionResult* result = new SpeechRecognitionResult(mRecognition);
SpeechRecognitionAlternative* alternative =
new SpeechRecognitionAlternative(mRecognition);
alternative->mTranscript = NS_LITERAL_STRING("Mock final result");
alternative->mConfidence = 0.0f;
result->mItems.AppendElement(alternative);
resultList->mItems.AppendElement(result);
return resultList;
}
} // namespace mozilla
@@ -0,0 +1,85 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_PocketSphinxRecognitionService_h
#define mozilla_dom_PocketSphinxRecognitionService_h
#include "nsCOMPtr.h"
#include "nsTArray.h"
#include "nsIObserver.h"
#include "nsISpeechRecognitionService.h"
#include "speex/speex_resampler.h"
extern "C" {
#include <pocketsphinx/pocketsphinx.h>
#include <sphinxbase/sphinx_config.h>
}
#define NS_POCKETSPHINX_SPEECH_RECOGNITION_SERVICE_CID \
{ \
0x0ff5ce56, 0x5b09, 0x4db8, { \
0xad, 0xc6, 0x82, 0x66, 0xaf, 0x95, 0xf8, 0x64 \
} \
};
namespace mozilla {
/**
* Pocketsphix implementation of the nsISpeechRecognitionService interface
*/
class PocketSphinxSpeechRecognitionService : public nsISpeechRecognitionService,
public nsIObserver
{
public:
// Add XPCOM glue code
NS_DECL_ISUPPORTS
NS_DECL_NSISPEECHRECOGNITIONSERVICE
// Add nsIObserver code
NS_DECL_NSIOBSERVER
/**
* Default constructs a PocketSphinxSpeechRecognitionService loading default
* files
*/
PocketSphinxSpeechRecognitionService();
private:
/**
* Private destructor to prevent bypassing of reference counting
*/
virtual ~PocketSphinxSpeechRecognitionService();
/** The associated SpeechRecognition */
WeakPtr<dom::SpeechRecognition> mRecognition;
/**
* Builds a mock SpeechRecognitionResultList
*/
dom::SpeechRecognitionResultList* BuildMockResultList();
/** Speex state */
SpeexResamplerState* mSpeexState;
/** Pocksphix decoder */
ps_decoder_t* mPSHandle;
/** Sphinxbase parsed command line arguments */
cmd_ln_t* mPSConfig;
/** Flag to verify if decoder was created */
bool ISDecoderCreated;
/** Flag to verify if grammar was compiled */
bool ISGrammarCompiled;
/** Audio data */
nsTArray<int16_t> mAudioVector;
};
} // namespace mozilla
#endif
@@ -53,14 +53,14 @@ SpeechGrammar::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
void
SpeechGrammar::GetSrc(nsString& aRetVal, ErrorResult& aRv) const
{
aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
aRetVal = mSrc;
return;
}
void
SpeechGrammar::SetSrc(const nsAString& aArg, ErrorResult& aRv)
{
aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
mSrc = aArg;
return;
}
@@ -49,6 +49,8 @@ private:
~SpeechGrammar();
nsCOMPtr<nsISupports> mParent;
nsString mSrc;
};
} // namespace dom
@@ -15,7 +15,7 @@
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(SpeechGrammarList, mParent)
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(SpeechGrammarList, mParent, mItems)
NS_IMPL_CYCLE_COLLECTING_ADDREF(SpeechGrammarList)
NS_IMPL_CYCLE_COLLECTING_RELEASE(SpeechGrammarList)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SpeechGrammarList)
@@ -64,14 +64,14 @@ SpeechGrammarList::GetParentObject() const
uint32_t
SpeechGrammarList::Length() const
{
return 0;
return mItems.Length();
}
already_AddRefed<SpeechGrammar>
SpeechGrammarList::Item(uint32_t aIndex, ErrorResult& aRv)
{
aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
return nullptr;
nsRefPtr<SpeechGrammar> result = mItems.ElementAt(aIndex);
return result.forget();
}
void
@@ -88,7 +88,10 @@ SpeechGrammarList::AddFromString(const nsAString& aString,
const Optional<float>& aWeight,
ErrorResult& aRv)
{
mRecognitionService->ValidateAndSetGrammarList(this, nullptr);
SpeechGrammar* speechGrammar = new SpeechGrammar(mParent);
speechGrammar->SetSrc(aString, aRv);
mItems.AppendElement(speechGrammar);
mRecognitionService->ValidateAndSetGrammarList(speechGrammar, nullptr);
return;
}
@@ -96,8 +99,13 @@ already_AddRefed<SpeechGrammar>
SpeechGrammarList::IndexedGetter(uint32_t aIndex, bool& aPresent,
ErrorResult& aRv)
{
aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
return nullptr;
if (aIndex >= Length()) {
aPresent = false;
return nullptr;
}
ErrorResult rv;
aPresent = true;
return Item(aIndex, rv);
}
} // namespace dom
@@ -56,6 +56,8 @@ private:
~SpeechGrammarList();
nsCOMPtr<nsISupports> mParent;
nsTArray<nsRefPtr<SpeechGrammar>> mItems;
};
} // namespace dom
@@ -34,7 +34,7 @@ namespace mozilla {
namespace dom {
#define PREFERENCE_DEFAULT_RECOGNITION_SERVICE "media.webspeech.service.default"
#define DEFAULT_RECOGNITION_SERVICE "google"
#define DEFAULT_RECOGNITION_SERVICE "pocketsphinx"
#define PREFERENCE_ENDPOINTER_SILENCE_LENGTH "media.webspeech.silence_length"
#define PREFERENCE_ENDPOINTER_LONG_SILENCE_LENGTH "media.webspeech.long_silence_length"
@@ -84,9 +84,9 @@ GetSpeechRecognitionService()
NS_SPEECH_RECOGNITION_SERVICE_CONTRACTID_PREFIX "fake";
}
nsresult aRv;
nsresult rv;
nsCOMPtr<nsISpeechRecognitionService> recognitionService;
recognitionService = do_GetService(speechRecognitionServiceCID.get(), &aRv);
recognitionService = do_GetService(speechRecognitionServiceCID.get(), &rv);
return recognitionService.forget();
}
@@ -472,12 +472,12 @@ SpeechRecognition::NotifyFinalResult(SpeechEvent* aEvent)
{
ResetAndEnd();
SpeechRecognitionEventInit init;
RootedDictionary<SpeechRecognitionEventInit> init(nsContentUtils::RootingCx());
init.mBubbles = true;
init.mCancelable = false;
// init.mResultIndex = 0;
init.mResults = aEvent->mRecognitionResultList;
init.mInterpretation = NS_LITERAL_STRING("NOT_IMPLEMENTED");
init.mInterpretation = JS::NullValue();
// init.mEmma = nullptr;
nsRefPtr<SpeechRecognitionEvent> event =
@@ -535,7 +535,9 @@ SpeechRecognition::StartRecording(DOMMediaStream* aDOMStream)
// doesn't get Destroy()'ed
mDOMStream = aDOMStream;
NS_ENSURE_STATE(mDOMStream->GetStream());
if (NS_WARN_IF(!mDOMStream->GetStream())) {
return NS_ERROR_UNEXPECTED;
}
mSpeechListener = new SpeechStreamListener(this);
mDOMStream->GetStream()->AddListener(mSpeechListener);
@@ -698,11 +700,15 @@ SpeechRecognition::Start(const Optional<NonNull<DOMMediaStream>>& aStream, Error
}
mRecognitionService = GetSpeechRecognitionService();
NS_ENSURE_TRUE_VOID(mRecognitionService);
if (NS_WARN_IF(!mRecognitionService)) {
return;
}
nsresult rv;
rv = mRecognitionService->Initialize(this);
NS_ENSURE_SUCCESS_VOID(rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
MediaStreamConstraints constraints;
constraints.mAudio.SetAsBoolean() = true;
@@ -957,7 +963,7 @@ SpeechRecognition::GetUserMediaErrorCallback::OnError(nsISupports* aError)
}
SpeechRecognitionErrorCode errorCode;
nsString name;
nsAutoString name;
error->GetName(name);
if (name.EqualsLiteral("PERMISSION_DENIED")) {
errorCode = SpeechRecognitionErrorCode::Not_allowed;
@@ -965,7 +971,7 @@ SpeechRecognition::GetUserMediaErrorCallback::OnError(nsISupports* aError)
errorCode = SpeechRecognitionErrorCode::Audio_capture;
}
nsString message;
nsAutoString message;
error->GetMessage(message);
mRecognition->DispatchError(SpeechRecognition::EVENT_AUDIO_ERROR, errorCode,
message);
@@ -22,8 +22,7 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SpeechRecognitionAlternative)
NS_INTERFACE_MAP_END
SpeechRecognitionAlternative::SpeechRecognitionAlternative(SpeechRecognition* aParent)
: mTranscript(NS_LITERAL_STRING(""))
, mConfidence(0)
: mConfidence(0)
, mParent(aParent)
{
}
@@ -67,7 +67,7 @@ SpeechRecognitionResult::Item(uint32_t aIndex)
}
bool
SpeechRecognitionResult::Final() const
SpeechRecognitionResult::IsFinal() const
{
return true; // TODO
}
@@ -38,11 +38,11 @@ public:
already_AddRefed<SpeechRecognitionAlternative> Item(uint32_t aIndex);
bool Final() const;
bool IsFinal() const;
already_AddRefed<SpeechRecognitionAlternative> IndexedGetter(uint32_t aIndex, bool& aPresent);
nsTArray<nsRefPtr<SpeechRecognitionAlternative> > mItems;
nsTArray<nsRefPtr<SpeechRecognitionAlternative>> mItems;
private:
~SpeechRecognitionResult();
@@ -41,7 +41,7 @@ public:
already_AddRefed<SpeechRecognitionResult> IndexedGetter(uint32_t aIndex, bool& aPresent);
nsTArray<nsRefPtr<SpeechRecognitionResult> > mItems;
nsTArray<nsRefPtr<SpeechRecognitionResult>> mItems;
private:
~SpeechRecognitionResultList();
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,34 @@
/* ====================================================================
* Copyright (c) 2015 Alpha Cephei Inc. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY ALPHA CEPHEI INC. ``AS IS'' AND.
* ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,.
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ALPHA CEPHEI INC.
* NOR ITS EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT.
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,.
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY.
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT.
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE.
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* ====================================================================
*
*/
This directory contains generic US english acoustic model trained with
latest sphinxtrain.
@@ -0,0 +1,12 @@
-lowerf 130
-upperf 3700
-nfilt 20
-transform dct
-lifter 22
-feat 1s_c_d_dd
-svspec 0-12/13-25/26-38
-agc none
-cmn current
-varnorm no
-cmninit 40,3,-1
-model ptm
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,5 @@
<s> SIL
</s> SIL
<sil> SIL
[NOISE] +NSN+
[SPEECH] +SPN+
+26 -2
View File
@@ -19,9 +19,18 @@ EXPORTS.mozilla.dom += [
'SpeechRecognitionResult.h',
'SpeechRecognitionResultList.h',
'SpeechStreamListener.h',
'test/FakeSpeechRecognitionService.h',
]
if CONFIG['MOZ_WEBSPEECH_TEST_BACKEND']:
EXPORTS.mozilla.dom += [
'test/FakeSpeechRecognitionService.h',
]
if CONFIG['MOZ_WEBSPEECH_POCKETSPHINX']:
EXPORTS.mozilla.dom += [
'PocketSphinxSpeechRecognitionService.h',
]
UNIFIED_SOURCES += [
'endpointer.cc',
'energy_endpointer.cc',
@@ -33,13 +42,28 @@ UNIFIED_SOURCES += [
'SpeechRecognitionResult.cpp',
'SpeechRecognitionResultList.cpp',
'SpeechStreamListener.cpp',
'test/FakeSpeechRecognitionService.cpp',
]
if CONFIG['MOZ_WEBSPEECH_TEST_BACKEND']:
UNIFIED_SOURCES += [
'test/FakeSpeechRecognitionService.cpp',
]
if CONFIG['MOZ_WEBSPEECH_POCKETSPHINX']:
UNIFIED_SOURCES += [
'PocketSphinxSpeechRecognitionService.cpp',
]
LOCAL_INCLUDES += [
'/dom/base',
'/media/sphinxbase',
]
if CONFIG['MOZ_WEBSPEECH_POCKETSPHINX']:
LOCAL_INCLUDES += [
'/media/pocketsphinx',
]
include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'
@@ -21,19 +21,19 @@ class SpeechGrammar;
native SpeechRecognitionWeakPtr(mozilla::WeakPtr<mozilla::dom::SpeechRecognition>);
[ptr] native AudioSegmentPtr(mozilla::AudioSegment);
[ptr] native SpeechGrammarListPtr(mozilla::dom::SpeechGrammarList);
[ptr] native SpeechGrammarPtr(mozilla::dom::SpeechGrammar);
[ptr] native SpeechGrammarListPtr(mozilla::dom::SpeechGrammarList);
[uuid(374583f0-4507-11e4-a183-164230d1df67)]
[uuid(6fcb6ee8-a6db-49ba-9f06-355d7ee18ea7)]
interface nsISpeechGrammarCompilationCallback : nsISupports {
void grammarCompilationEnd(in SpeechGrammarPtr grammarObject, in boolean success);
};
[uuid(857f3fa2-a980-4d3e-a959-a2f53af74232)]
[uuid(8e97f287-f322-44e8-8888-8344fa408ef8)]
interface nsISpeechRecognitionService : nsISupports {
void initialize(in SpeechRecognitionWeakPtr aSpeechRecognition);
void processAudioSegment(in AudioSegmentPtr aAudioSegment, in long aSampleRate);
void validateAndSetGrammarList(in SpeechGrammarListPtr aSpeechGramarList, in nsISpeechGrammarCompilationCallback aCallback);
void validateAndSetGrammarList(in SpeechGrammarPtr aSpeechGrammar, in nsISpeechGrammarCompilationCallback aCallback);
void soundEnd();
void abort();
};
@@ -52,7 +52,7 @@ FakeSpeechRecognitionService::SoundEnd()
}
NS_IMETHODIMP
FakeSpeechRecognitionService::ValidateAndSetGrammarList(mozilla::dom::SpeechGrammarList*, nsISpeechGrammarCompilationCallback*)
FakeSpeechRecognitionService::ValidateAndSetGrammarList(mozilla::dom::SpeechGrammar*, nsISpeechGrammarCompilationCallback*)
{
return NS_OK;
}

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