mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-c to b2g-inbound
This commit is contained in:
commit
2c80c4d658
@ -178,8 +178,6 @@ button {
|
||||
|
||||
input[type="radio"],
|
||||
input[type="checkbox"] {
|
||||
max-width: 14px;
|
||||
max-height: 14px;
|
||||
border: 1px solid #a7a7a7 !important;
|
||||
padding: 2px 1px 2px 1px;
|
||||
}
|
||||
|
@ -1380,6 +1380,13 @@ pref("devtools.debugger.ui.variables-searchbox-visible", false);
|
||||
pref("devtools.profiler.enabled", true);
|
||||
pref("devtools.timeline.enabled", false);
|
||||
|
||||
// Enable perftools via build command
|
||||
#ifdef MOZ_DEVTOOLS_PERFTOOLS
|
||||
pref("devtools.performance_dev.enabled", true);
|
||||
#else
|
||||
pref("devtools.performance_dev.enabled", false);
|
||||
#endif
|
||||
|
||||
// The default Profiler UI settings
|
||||
pref("devtools.profiler.ui.show-platform-data", false);
|
||||
|
||||
|
@ -128,7 +128,7 @@
|
||||
&community.start2;<label class="text-link" href="http://www.mozilla.org/">&community.mozillaLink;</label>&community.middle2;<label class="text-link" href="about:credits">&community.creditsLink;</label>&community.end3;
|
||||
</description>
|
||||
<description class="text-blurb" id="contributeDesc">
|
||||
&contribute.start;<label class="text-link" href="http://www.mozilla.org/contribute/">&contribute.getInvolvedLink;</label>&contribute.end;
|
||||
&helpus.start;<label class="text-link" href="https://sendto.mozilla.org/page/contribute/Give-Now?source=mozillaorg_default_footer&ref=firefox_about&utm_campaign=firefox_about&tm_source=firefox&tm_medium=referral&utm_content=20140929_FireFoxAbout">&helpus.donateLink;</label>&helpus.middle;<label class="text-link" href="http://www.mozilla.org/contribute/">&helpus.getInvolvedLink;</label>&helpus.end;
|
||||
</description>
|
||||
</vbox>
|
||||
</vbox>
|
||||
|
@ -154,14 +154,13 @@ let gUpdater = {
|
||||
*/
|
||||
_fillEmptyCells: function Updater_fillEmptyCells(aLinks, aCallback) {
|
||||
let {cells, sites} = gGrid;
|
||||
let batch = [];
|
||||
|
||||
// Find empty cells and fill them.
|
||||
sites.forEach(function (aSite, aIndex) {
|
||||
Promise.all(sites.map((aSite, aIndex) => {
|
||||
if (aSite || !aLinks[aIndex])
|
||||
return;
|
||||
return null;
|
||||
|
||||
batch.push(new Promise(resolve => {
|
||||
return new Promise(resolve => {
|
||||
// Create the new site and fade it in.
|
||||
let site = gGrid.createSite(aLinks[aIndex], cells[aIndex]);
|
||||
|
||||
@ -172,9 +171,7 @@ let gUpdater = {
|
||||
// the fade-in transition work.
|
||||
window.getComputedStyle(site.node).opacity;
|
||||
gTransformation.showSite(site, resolve);
|
||||
}));
|
||||
});
|
||||
|
||||
Promise.all(batch).then(aCallback);
|
||||
});
|
||||
})).then(aCallback).catch(console.exception);
|
||||
}
|
||||
};
|
||||
|
@ -1,58 +1,95 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
let tab;
|
||||
let notification;
|
||||
let notificationURL = "http://example.org/browser/browser/base/content/test/general/file_dom_notifications.html";
|
||||
|
||||
function test () {
|
||||
waitForExplicitFinish();
|
||||
|
||||
let pm = Services.perms;
|
||||
registerCleanupFunction(function() {
|
||||
pm.remove(notificationURL, "desktop-notification");
|
||||
gBrowser.removeTab(tab);
|
||||
window.restore();
|
||||
});
|
||||
|
||||
pm.add(makeURI(notificationURL), "desktop-notification", pm.ALLOW_ACTION);
|
||||
|
||||
tab = gBrowser.addTab(notificationURL);
|
||||
tab.linkedBrowser.addEventListener("load", onLoad, true);
|
||||
}
|
||||
|
||||
function onLoad() {
|
||||
isnot(gBrowser.selectedTab, tab, "Notification page loaded as a background tab");
|
||||
tab.linkedBrowser.removeEventListener("load", onLoad, true);
|
||||
let win = tab.linkedBrowser.contentWindow.wrappedJSObject;
|
||||
notification = win.showNotification();
|
||||
notification.addEventListener("show", onAlertShowing);
|
||||
}
|
||||
|
||||
function onAlertShowing() {
|
||||
info("Notification alert showing");
|
||||
notification.removeEventListener("show", onAlertShowing);
|
||||
|
||||
let alertWindow = findChromeWindowByURI("chrome://global/content/alerts/alert.xul");
|
||||
if (!alertWindow) {
|
||||
todo(false, "Notifications don't use XUL windows on all platforms.");
|
||||
notification.close();
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
gBrowser.tabContainer.addEventListener("TabSelect", onTabSelect);
|
||||
EventUtils.synthesizeMouseAtCenter(alertWindow.document.getElementById("alertTitleLabel"), {}, alertWindow);
|
||||
info("Clicked on notification");
|
||||
alertWindow.close();
|
||||
}
|
||||
|
||||
function onTabSelect() {
|
||||
gBrowser.tabContainer.removeEventListener("TabSelect", onTabSelect);
|
||||
is(gBrowser.selectedTab.linkedBrowser.contentWindow.location.href, notificationURL,
|
||||
"Notification tab should be selected.");
|
||||
|
||||
finish();
|
||||
}
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
let tab;
|
||||
let notification;
|
||||
let notificationURL = "http://example.org/browser/browser/base/content/test/general/file_dom_notifications.html";
|
||||
let newWindowOpenedFromTab;
|
||||
|
||||
function test () {
|
||||
waitForExplicitFinish();
|
||||
|
||||
let pm = Services.perms;
|
||||
registerCleanupFunction(function() {
|
||||
pm.remove(notificationURL, "desktop-notification");
|
||||
gBrowser.removeTab(tab);
|
||||
window.restore();
|
||||
});
|
||||
|
||||
pm.add(makeURI(notificationURL), "desktop-notification", pm.ALLOW_ACTION);
|
||||
|
||||
tab = gBrowser.addTab(notificationURL);
|
||||
tab.linkedBrowser.addEventListener("load", onLoad, true);
|
||||
}
|
||||
|
||||
function onLoad() {
|
||||
isnot(gBrowser.selectedTab, tab, "Notification page loaded as a background tab");
|
||||
tab.linkedBrowser.removeEventListener("load", onLoad, true);
|
||||
let win = tab.linkedBrowser.contentWindow.wrappedJSObject;
|
||||
win.newWindow = win.open("about:blank", "", "height=100,width=100");
|
||||
newWindowOpenedFromTab = win.newWindow;
|
||||
win.newWindow.addEventListener("load", function() {
|
||||
info("new window loaded");
|
||||
win.newWindow.addEventListener("blur", function b() {
|
||||
info("new window got blur");
|
||||
win.newWindow.removeEventListener("blur", b);
|
||||
notification = win.showNotification1();
|
||||
win.newWindow.addEventListener("focus", onNewWindowFocused);
|
||||
notification.addEventListener("show", onAlertShowing);
|
||||
});
|
||||
|
||||
function waitUntilNewWindowHasFocus() {
|
||||
if (!win.newWindow.document.hasFocus()) {
|
||||
setTimeout(waitUntilNewWindowHasFocus, 50);
|
||||
} else {
|
||||
// Focus another window so that new window gets blur event.
|
||||
gBrowser.selectedTab.linkedBrowser.contentWindow.focus();
|
||||
}
|
||||
}
|
||||
win.newWindow.focus();
|
||||
waitUntilNewWindowHasFocus();
|
||||
});
|
||||
}
|
||||
|
||||
function onAlertShowing() {
|
||||
info("Notification alert showing");
|
||||
notification.removeEventListener("show", onAlertShowing);
|
||||
|
||||
let alertWindow = findChromeWindowByURI("chrome://global/content/alerts/alert.xul");
|
||||
if (!alertWindow) {
|
||||
todo(false, "Notifications don't use XUL windows on all platforms.");
|
||||
notification.close();
|
||||
newWindowOpenedFromTab.close();
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
gBrowser.tabContainer.addEventListener("TabSelect", onTabSelect);
|
||||
EventUtils.synthesizeMouseAtCenter(alertWindow.document.getElementById("alertTitleLabel"), {}, alertWindow);
|
||||
info("Clicked on notification");
|
||||
alertWindow.close();
|
||||
}
|
||||
|
||||
function onNewWindowFocused(event) {
|
||||
event.target.close();
|
||||
isnot(gBrowser.selectedTab, tab, "Notification page loaded as a background tab");
|
||||
// Using timeout to test that something do *not* happen!
|
||||
setTimeout(openSecondNotification, 50);
|
||||
}
|
||||
|
||||
function openSecondNotification() {
|
||||
isnot(gBrowser.selectedTab, tab, "Notification page loaded as a background tab");
|
||||
let win = tab.linkedBrowser.contentWindow.wrappedJSObject;
|
||||
notification = win.showNotification2();
|
||||
notification.addEventListener("show", onAlertShowing);
|
||||
}
|
||||
|
||||
function onTabSelect() {
|
||||
gBrowser.tabContainer.removeEventListener("TabSelect", onTabSelect);
|
||||
is(gBrowser.selectedTab.linkedBrowser.contentWindow.location.href, notificationURL,
|
||||
"Notification tab should be selected.");
|
||||
|
||||
finish();
|
||||
}
|
||||
|
@ -1,23 +1,40 @@
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
function showNotification() {
|
||||
var options = {
|
||||
dir: undefined,
|
||||
lang: undefined,
|
||||
body: "Test body",
|
||||
tag: "Test tag",
|
||||
icon: undefined,
|
||||
};
|
||||
return new Notification("Test title", options);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<form id="notificationForm" onsubmit="showNotification();">
|
||||
<input type="submit" value="Show notification" id="submit"/>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
function showNotification1() {
|
||||
var options = {
|
||||
dir: undefined,
|
||||
lang: undefined,
|
||||
body: "Test body",
|
||||
tag: "Test tag",
|
||||
icon: undefined,
|
||||
};
|
||||
var n = new Notification("Test title", options);
|
||||
n.addEventListener("click", function(event) {
|
||||
event.preventDefault();
|
||||
dump("Should focus new window.");
|
||||
newWindow.focus();
|
||||
});
|
||||
return n;
|
||||
}
|
||||
|
||||
function showNotification2() {
|
||||
var options = {
|
||||
dir: undefined,
|
||||
lang: undefined,
|
||||
body: "Test body",
|
||||
tag: "Test tag",
|
||||
icon: undefined,
|
||||
};
|
||||
return new Notification("Test title", options);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<form id="notificationForm" onsubmit="showNotification();">
|
||||
<input type="submit" value="Show notification" id="submit"/>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -49,6 +49,7 @@ skip-if = e10s # when we backed out bug 1047603, this test broke.
|
||||
[browser_social_marks.js]
|
||||
skip-if = e10s # Bug 915547 (social providers don't install)
|
||||
[browser_social_multiprovider.js]
|
||||
skip-if = e10s # Bug 1069162 - lots of orange
|
||||
[browser_social_multiworker.js]
|
||||
[browser_social_perwindowPB.js]
|
||||
[browser_social_sidebar.js]
|
||||
|
@ -923,7 +923,7 @@ const CustomizableWidgets = [
|
||||
}, {
|
||||
id: "loop-call-button",
|
||||
type: "custom",
|
||||
label: "loop-call-button2.label",
|
||||
label: "loop-call-button3.label",
|
||||
tooltiptext: "loop-call-button2.tooltiptext",
|
||||
defaultArea: CustomizableUI.AREA_NAVBAR,
|
||||
introducedInVersion: 1,
|
||||
|
@ -86,6 +86,10 @@ browser.jar:
|
||||
content/browser/devtools/profiler.js (profiler/profiler.js)
|
||||
content/browser/devtools/ui-recordings.js (profiler/ui-recordings.js)
|
||||
content/browser/devtools/ui-profile.js (profiler/ui-profile.js)
|
||||
#ifdef MOZ_DEVTOOLS_PERFTOOLS
|
||||
content/browser/devtools/performance.xul (performance/performance.xul)
|
||||
content/browser/devtools/performance.js (performance/performance.js)
|
||||
#endif
|
||||
content/browser/devtools/responsivedesign/resize-commands.js (responsivedesign/resize-commands.js)
|
||||
content/browser/devtools/commandline.css (commandline/commandline.css)
|
||||
content/browser/devtools/commandlineoutput.xhtml (commandline/commandlineoutput.xhtml)
|
||||
|
@ -31,6 +31,7 @@ loader.lazyGetter(this, "ShaderEditorPanel", () => require("devtools/shaderedito
|
||||
loader.lazyGetter(this, "CanvasDebuggerPanel", () => require("devtools/canvasdebugger/panel").CanvasDebuggerPanel);
|
||||
loader.lazyGetter(this, "WebAudioEditorPanel", () => require("devtools/webaudioeditor/panel").WebAudioEditorPanel);
|
||||
loader.lazyGetter(this, "ProfilerPanel", () => require("devtools/profiler/panel").ProfilerPanel);
|
||||
loader.lazyGetter(this, "PerformancePanel", () => require("devtools/performance/panel").PerformancePanel);
|
||||
loader.lazyGetter(this, "TimelinePanel", () => require("devtools/timeline/panel").TimelinePanel);
|
||||
loader.lazyGetter(this, "NetMonitorPanel", () => require("devtools/netmonitor/panel").NetMonitorPanel);
|
||||
loader.lazyGetter(this, "StoragePanel", () => require("devtools/storage/panel").StoragePanel);
|
||||
@ -274,6 +275,32 @@ Tools.jsprofiler = {
|
||||
}
|
||||
};
|
||||
|
||||
Tools.performance = {
|
||||
id: "performance",
|
||||
ordinal: 19,
|
||||
icon: "chrome://browser/skin/devtools/tool-profiler.svg",
|
||||
invertIconForLightTheme: true,
|
||||
url: "chrome://browser/content/devtools/performance.xul",
|
||||
// TODO bug 1082695 audit the Performance tools labels
|
||||
label: "Performance++", //l10n("profiler.label2", profilerStrings),
|
||||
panelLabel: "Performance++", //l10n("profiler.panelLabel2", profilerStrings),
|
||||
tooltip: l10n("profiler.tooltip2", profilerStrings),
|
||||
accesskey: l10n("profiler.accesskey", profilerStrings),
|
||||
key: l10n("profiler.commandkey2", profilerStrings),
|
||||
modifiers: "shift",
|
||||
inMenu: true,
|
||||
|
||||
isTargetSupported: function (target) {
|
||||
// Hide the profiler when debugging devices pre bug 1046394,
|
||||
// that don't expose profiler actor in content processes.
|
||||
return !target.isAddon && (!target.isApp || target.form.profilerActor);
|
||||
},
|
||||
|
||||
build: function (frame, target) {
|
||||
return new PerformancePanel(frame, target);
|
||||
}
|
||||
};
|
||||
|
||||
Tools.timeline = {
|
||||
id: "timeline",
|
||||
ordinal: 8,
|
||||
@ -404,6 +431,16 @@ let defaultTools = [
|
||||
Tools.scratchpad
|
||||
];
|
||||
|
||||
// Only enable in-development performance tools if `--enable-devtools-perf`
|
||||
// used in build, turning on `devtools.performance_dev.enabled`.
|
||||
// Add to normal `defaultTools` when ready for normal release,
|
||||
// pull out MOZ_DEVTOOLS_PERFTOOLS setting in `./configure.in`, and
|
||||
// leave config on in `./browser/app/profile/firefox.js`, and always
|
||||
// build in `./browser/devtools/moz.build`.
|
||||
if (Services.prefs.getBoolPref("devtools.performance_dev.enabled")) {
|
||||
defaultTools.push(Tools.performance);
|
||||
}
|
||||
|
||||
exports.defaultTools = defaultTools;
|
||||
|
||||
for (let definition of defaultTools) {
|
||||
|
@ -33,6 +33,9 @@ DIRS += [
|
||||
'webide',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_DEVTOOLS_PERFTOOLS']:
|
||||
DIRS += ['performance']
|
||||
|
||||
EXTRA_COMPONENTS += [
|
||||
'devtools-clhandler.js',
|
||||
'devtools-clhandler.manifest',
|
||||
|
8
browser/devtools/performance/moz.build
Normal file
8
browser/devtools/performance/moz.build
Normal file
@ -0,0 +1,8 @@
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
EXTRA_JS_MODULES.devtools.performance += [
|
||||
'panel.js'
|
||||
]
|
62
browser/devtools/performance/panel.js
Normal file
62
browser/devtools/performance/panel.js
Normal file
@ -0,0 +1,62 @@
|
||||
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
const {Cc, Ci, Cu, Cr} = require("chrome");
|
||||
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
|
||||
loader.lazyRequireGetter(this, "promise");
|
||||
loader.lazyRequireGetter(this, "EventEmitter",
|
||||
"devtools/toolkit/event-emitter");
|
||||
|
||||
function PerformancePanel(iframeWindow, toolbox) {
|
||||
this.panelWin = iframeWindow;
|
||||
this._toolbox = toolbox;
|
||||
|
||||
EventEmitter.decorate(this);
|
||||
}
|
||||
|
||||
exports.PerformancePanel = PerformancePanel;
|
||||
|
||||
PerformancePanel.prototype = {
|
||||
/**
|
||||
* Open is effectively an asynchronous constructor.
|
||||
*
|
||||
* @return object
|
||||
* A promise that is resolved when the Profiler completes opening.
|
||||
*/
|
||||
open: Task.async(function*() {
|
||||
this.panelWin.gToolbox = this._toolbox;
|
||||
this.panelWin.gTarget = this.target;
|
||||
|
||||
// Mock Front for now
|
||||
let gFront = {};
|
||||
EventEmitter.decorate(gFront);
|
||||
this.panelWin.gFront = gFront;
|
||||
|
||||
yield this.panelWin.startupPerformance();
|
||||
|
||||
this.isReady = true;
|
||||
this.emit("ready");
|
||||
return this;
|
||||
}),
|
||||
|
||||
// DevToolPanel API
|
||||
|
||||
get target() this._toolbox.target,
|
||||
|
||||
destroy: Task.async(function*() {
|
||||
// Make sure this panel is not already destroyed.
|
||||
if (this._destroyed) {
|
||||
return;
|
||||
}
|
||||
|
||||
yield this.panelWin.shutdownPerformance();
|
||||
this.emit("destroyed");
|
||||
this._destroyed = true;
|
||||
})
|
||||
};
|
97
browser/devtools/performance/performance.js
Normal file
97
browser/devtools/performance/performance.js
Normal file
@ -0,0 +1,97 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource://gre/modules/devtools/Loader.jsm");
|
||||
Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
|
||||
|
||||
devtools.lazyRequireGetter(this, "Services");
|
||||
devtools.lazyRequireGetter(this, "promise");
|
||||
devtools.lazyRequireGetter(this, "EventEmitter",
|
||||
"devtools/toolkit/event-emitter");
|
||||
devtools.lazyRequireGetter(this, "DevToolsUtils",
|
||||
"devtools/toolkit/DevToolsUtils");
|
||||
|
||||
/**
|
||||
* The current target and the profiler connection, set by this tool's host.
|
||||
*/
|
||||
let gToolbox, gTarget, gFront;
|
||||
|
||||
/**
|
||||
* Initializes the profiler controller and views.
|
||||
*/
|
||||
let startupPerformance = Task.async(function*() {
|
||||
yield promise.all([
|
||||
PrefObserver.register(),
|
||||
EventsHandler.initialize()
|
||||
]);
|
||||
});
|
||||
|
||||
/**
|
||||
* Destroys the profiler controller and views.
|
||||
*/
|
||||
let shutdownPerformance = Task.async(function*() {
|
||||
yield promise.all([
|
||||
PrefObserver.unregister(),
|
||||
EventsHandler.destroy()
|
||||
]);
|
||||
});
|
||||
|
||||
/**
|
||||
* Observes pref changes on the devtools.profiler branch and triggers the
|
||||
* required frontend modifications.
|
||||
*/
|
||||
let PrefObserver = {
|
||||
register: function() {
|
||||
this.branch = Services.prefs.getBranch("devtools.profiler.");
|
||||
this.branch.addObserver("", this, false);
|
||||
},
|
||||
unregister: function() {
|
||||
this.branch.removeObserver("", this);
|
||||
},
|
||||
observe: function(subject, topic, pref) {
|
||||
Prefs.refresh();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Functions handling target-related lifetime events.
|
||||
*/
|
||||
let EventsHandler = {
|
||||
/**
|
||||
* Listen for events emitted by the current tab target.
|
||||
*/
|
||||
initialize: function() {
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove events emitted by the current tab target.
|
||||
*/
|
||||
destroy: function() {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Shortcuts for accessing various profiler preferences.
|
||||
*/
|
||||
const Prefs = new ViewHelpers.Prefs("devtools.profiler", {
|
||||
});
|
||||
|
||||
/**
|
||||
* Convenient way of emitting events from the panel window.
|
||||
*/
|
||||
EventEmitter.decorate(this);
|
||||
|
||||
/**
|
||||
* DOM query helpers.
|
||||
*/
|
||||
function $(selector, target = document) {
|
||||
return target.querySelector(selector);
|
||||
}
|
||||
function $$(selector, target = document) {
|
||||
return target.querySelectorAll(selector);
|
||||
}
|
47
browser/devtools/performance/performance.xul
Normal file
47
browser/devtools/performance/performance.xul
Normal file
@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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/. -->
|
||||
<?xml-stylesheet href="chrome://browser/skin/" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/content/devtools/widgets.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/devtools/common.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/devtools/widgets.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/devtools/performance.css" type="text/css"?>
|
||||
<!DOCTYPE window [
|
||||
<!ENTITY % profilerDTD SYSTEM "chrome://browser/locale/devtools/profiler.dtd">
|
||||
%profilerDTD;
|
||||
]>
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script src="chrome://browser/content/devtools/theme-switching.js"/>
|
||||
<script type="application/javascript" src="performance.js"/>
|
||||
|
||||
<vbox class="theme-body" flex="1">
|
||||
<toolbar id="performance-toolbar" class="devtools-toolbar">
|
||||
<hbox id="performance-toolbar-controls-recordings" class="devtools-toolbarbutton-group">
|
||||
<toolbarbutton id="record-button"
|
||||
class="devtools-toolbarbutton"
|
||||
tooltiptext="&profilerUI.recordButton.tooltip;"/>
|
||||
<toolbarbutton id="clear-button"
|
||||
class="devtools-toolbarbutton"
|
||||
label="&profilerUI.clearButton;"/>
|
||||
</hbox>
|
||||
<spacer flex="1"></spacer>
|
||||
<hbox id="performance-toolbar-controls-storage" class="devtools-toolbarbutton-group">
|
||||
<toolbarbutton id="import-button"
|
||||
class="devtools-toolbarbutton"
|
||||
label="&profilerUI.importButton;"/>
|
||||
</hbox>
|
||||
</toolbar>
|
||||
<splitter class="devtools-horizontal-splitter" />
|
||||
<box id="overview-pane"
|
||||
class="devtools-responsive-container"
|
||||
flex="1">
|
||||
</box>
|
||||
<splitter class="devtools-horizontal-splitter" />
|
||||
<box id="details-pane"
|
||||
class="devtools-responsive-container"
|
||||
flex="1">
|
||||
</box>
|
||||
</vbox>
|
||||
</window>
|
@ -22,6 +22,7 @@ support-files =
|
||||
[browser_audionode-actor-get-type.js]
|
||||
[browser_audionode-actor-is-source.js]
|
||||
[browser_audionode-actor-bypass.js]
|
||||
[browser_audionode-actor-connectnode-disconnect.js]
|
||||
[browser_webaudio-actor-simple.js]
|
||||
[browser_webaudio-actor-destroy-node.js]
|
||||
[browser_webaudio-actor-connect-param.js]
|
||||
|
@ -0,0 +1,44 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests that AudioNodeActor#connectNode() and AudioNodeActor#disconnect() work.
|
||||
* Uses the editor front as the actors do not retain connect state.
|
||||
*/
|
||||
|
||||
function spawnTest() {
|
||||
let { target, panel } = yield initWebAudioEditor(SIMPLE_CONTEXT_URL);
|
||||
let { panelWin } = panel;
|
||||
let { gFront, $, $$, EVENTS, gAudioNodes } = panelWin;
|
||||
|
||||
reload(target);
|
||||
|
||||
let [actors] = yield Promise.all([
|
||||
get3(gFront, "create-node"),
|
||||
waitForGraphRendered(panelWin, 3, 2)
|
||||
]);
|
||||
|
||||
let [dest, osc, gain] = actors;
|
||||
|
||||
info("Disconnecting oscillator...");
|
||||
osc.disconnect();
|
||||
yield Promise.all([
|
||||
waitForGraphRendered(panelWin, 3, 1),
|
||||
once(gAudioNodes, "disconnect")
|
||||
]);
|
||||
ok(true, "Oscillator disconnected, event emitted.");
|
||||
|
||||
|
||||
info("Reconnecting oscillator...");
|
||||
osc.connectNode(gain);
|
||||
yield Promise.all([
|
||||
waitForGraphRendered(panelWin, 3, 2),
|
||||
once(gAudioNodes, "connect")
|
||||
]);
|
||||
ok(true, "Oscillator reconnected.");
|
||||
|
||||
|
||||
yield teardown(panel);
|
||||
finish();
|
||||
}
|
||||
|
@ -38,10 +38,13 @@
|
||||
<!ENTITY community.creditsLink "global community">
|
||||
<!ENTITY community.end3 " working together to keep the Web open, public and accessible to all.">
|
||||
|
||||
<!ENTITY contribute.start "Sound interesting? ">
|
||||
<!-- LOCALIZATION NOTE (contribute.getInvolvedLink): This is a link title that links to http://www.mozilla.org/contribute/. -->
|
||||
<!ENTITY contribute.getInvolvedLink "Get involved!">
|
||||
<!ENTITY contribute.end "">
|
||||
<!ENTITY helpus.start "Want to help? ">
|
||||
<!-- LOCALIZATION NOTE (helpus.donateLink): This is a link title that links to https://sendto.mozilla.org/page/contribute/Give-Now?source=mozillaorg_default_footer&ref=firefox_about&utm_campaign=firefox_about&utm_source=firefox&utm_medium=referral&utm_content=20140929_FireFoxAbout. -->
|
||||
<!ENTITY helpus.donateLink "Make a donation">
|
||||
<!ENTITY helpus.middle " or ">
|
||||
<!-- LOCALIZATION NOTE (helpus.getInvolvedLink): This is a link title that links to http://www.mozilla.org/contribute/. -->
|
||||
<!ENTITY helpus.getInvolvedLink "get involved!">
|
||||
<!ENTITY helpus.end "">
|
||||
|
||||
<!-- LOCALIZATION NOTE (bottomLinks.license): This is a link title that links to about:license. -->
|
||||
<!ENTITY bottomLinks.license "Licensing Information">
|
||||
|
@ -97,7 +97,9 @@ quit-button.tooltiptext.linux2 = Quit %1$S (%2$S)
|
||||
# %2$S is the keyboard shortcut
|
||||
quit-button.tooltiptext.mac = Quit %1$S (%2$S)
|
||||
|
||||
loop-call-button2.label = Start a conversation
|
||||
# LOCALIZATION NOTE(loop-call-button2.label2): This is a brand name, request
|
||||
# approval before you change it.
|
||||
loop-call-button3.label = Hello
|
||||
loop-call-button2.tooltiptext = Start a conversation
|
||||
|
||||
social-share-button.label = Share This Page
|
||||
|
@ -19,7 +19,8 @@ this.E10SUtils = {
|
||||
if (aURL.startsWith("about:") &&
|
||||
aURL.toLowerCase() != "about:home" &&
|
||||
aURL.toLowerCase() != "about:blank" &&
|
||||
!aURL.toLowerCase().startsWith("about:neterror")) {
|
||||
!aURL.toLowerCase().startsWith("about:neterror") &&
|
||||
!aURL.toLowerCase().startsWith("about:certerror")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "BrowserUITelemetry",
|
||||
|
||||
|
||||
const UITOUR_PERMISSION = "uitour";
|
||||
const PREF_TEST_WHITELIST = "browser.uitour.testingOrigins";
|
||||
const PREF_SEENPAGEIDS = "browser.uitour.seenPageIDs";
|
||||
const MAX_BUTTONS = 4;
|
||||
|
||||
@ -620,6 +621,25 @@ this.UITour = {
|
||||
.wrappedJSObject;
|
||||
},
|
||||
|
||||
isTestingOrigin: function(aURI) {
|
||||
if (Services.prefs.getPrefType(PREF_TEST_WHITELIST) != Services.prefs.PREF_STRING) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add any testing origins (comma-seperated) to the whitelist for the session.
|
||||
for (let origin of Services.prefs.getCharPref(PREF_TEST_WHITELIST).split(",")) {
|
||||
try {
|
||||
let testingURI = Services.io.newURI(origin, null, null);
|
||||
if (aURI.prePath == testingURI.prePath) {
|
||||
return true;
|
||||
}
|
||||
} catch (ex) {
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
ensureTrustedOrigin: function(aDocument) {
|
||||
if (aDocument.defaultView.top != aDocument.defaultView)
|
||||
return false;
|
||||
@ -633,7 +653,10 @@ this.UITour = {
|
||||
return false;
|
||||
|
||||
let permission = Services.perms.testPermission(uri, UITOUR_PERMISSION);
|
||||
return permission == Services.perms.ALLOW_ACTION;
|
||||
if (permission == Services.perms.ALLOW_ACTION)
|
||||
return true;
|
||||
|
||||
return this.isTestingOrigin(uri);
|
||||
},
|
||||
|
||||
isSafeScheme: function(aURI) {
|
||||
|
@ -25,6 +25,23 @@ let tests = [
|
||||
done();
|
||||
}, "http://mochi.test:8888/");
|
||||
},
|
||||
function test_testing_host(done) {
|
||||
// Add two testing origins intentionally surrounded by whitespace to be ignored.
|
||||
Services.prefs.setCharPref("browser.uitour.testingOrigins",
|
||||
"https://test1.example.com, https://test2.example.com:443 ");
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
Services.prefs.clearUserPref("browser.uitour.testingOrigins");
|
||||
});
|
||||
function callback(result) {
|
||||
ok(result, "Callback should be called on a testing origin");
|
||||
done();
|
||||
}
|
||||
|
||||
loadUITourTestPage(function() {
|
||||
gContentAPI.getConfiguration("appinfo", callback);
|
||||
}, "https://test2.example.com/");
|
||||
},
|
||||
function test_unsecure_host(done) {
|
||||
loadUITourTestPage(function() {
|
||||
let bookmarksMenu = document.getElementById("bookmarks-menu-button");
|
||||
|
@ -2,13 +2,4 @@
|
||||
* 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 "nsNetStrings.h"
|
||||
#include "nsChannelProperties.h"
|
||||
|
||||
nsNetStrings* gNetStrings;
|
||||
|
||||
nsNetStrings::nsNetStrings()
|
||||
: NS_LITERAL_STRING_INIT(kChannelPolicy, NS_CHANNEL_PROP_CHANNEL_POLICY_STR)
|
||||
{}
|
||||
|
||||
|
||||
%include ../../shared/devtools/performance.inc.css
|
@ -252,6 +252,7 @@ browser.jar:
|
||||
skin/classic/browser/devtools/eyedropper.css (../shared/devtools/eyedropper.css)
|
||||
* skin/classic/browser/devtools/netmonitor.css (devtools/netmonitor.css)
|
||||
* skin/classic/browser/devtools/profiler.css (devtools/profiler.css)
|
||||
* skin/classic/browser/devtools/performance.css (devtools/performance.css)
|
||||
* skin/classic/browser/devtools/timeline.css (devtools/timeline.css)
|
||||
* skin/classic/browser/devtools/scratchpad.css (devtools/scratchpad.css)
|
||||
* skin/classic/browser/devtools/shadereditor.css (devtools/shadereditor.css)
|
||||
|
6
browser/themes/osx/devtools/performance.css
Normal file
6
browser/themes/osx/devtools/performance.css
Normal file
@ -0,0 +1,6 @@
|
||||
/* 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 ../shared.inc
|
||||
%include ../../shared/devtools/performance.inc.css
|
@ -382,6 +382,7 @@ browser.jar:
|
||||
skin/classic/browser/devtools/eyedropper.css (../shared/devtools/eyedropper.css)
|
||||
* skin/classic/browser/devtools/netmonitor.css (devtools/netmonitor.css)
|
||||
* skin/classic/browser/devtools/profiler.css (devtools/profiler.css)
|
||||
* skin/classic/browser/devtools/performance.css (devtools/performance.css)
|
||||
* skin/classic/browser/devtools/timeline.css (devtools/timeline.css)
|
||||
* skin/classic/browser/devtools/scratchpad.css (devtools/scratchpad.css)
|
||||
* skin/classic/browser/devtools/shadereditor.css (devtools/shadereditor.css)
|
||||
|
34
browser/themes/shared/devtools/performance.inc.css
Normal file
34
browser/themes/shared/devtools/performance.inc.css
Normal file
@ -0,0 +1,34 @@
|
||||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/* 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/. */
|
||||
|
||||
/* Toolbar */
|
||||
|
||||
#performance-toolbar {
|
||||
-moz-border-end: 1px solid;
|
||||
}
|
||||
|
||||
.theme-dark #performance-toolbar > tabs,
|
||||
.theme-dark #performance-toolbar {
|
||||
-moz-border-end-color: #000; /* Splitters */
|
||||
}
|
||||
|
||||
.theme-light #performance-toolbar > tabs,
|
||||
.theme-light #performance-toolbar {
|
||||
-moz-border-end-color: #aaa; /* Splitters */
|
||||
}
|
||||
|
||||
/* Overview Panel */
|
||||
|
||||
#record-button {
|
||||
list-style-image: url(profiler-stopwatch.svg);
|
||||
}
|
||||
|
||||
#record-button[checked] {
|
||||
list-style-image: url(profiler-stopwatch-checked.svg);
|
||||
}
|
||||
|
||||
#record-button[locked] {
|
||||
pointer-events: none;
|
||||
}
|
5
browser/themes/windows/devtools/performance.css
Normal file
5
browser/themes/windows/devtools/performance.css
Normal file
@ -0,0 +1,5 @@
|
||||
/* 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 ../../shared/devtools/performance.inc.css
|
@ -289,6 +289,7 @@ browser.jar:
|
||||
* skin/classic/browser/devtools/debugger.css (devtools/debugger.css)
|
||||
* skin/classic/browser/devtools/netmonitor.css (devtools/netmonitor.css)
|
||||
* skin/classic/browser/devtools/profiler.css (devtools/profiler.css)
|
||||
* skin/classic/browser/devtools/performance.css (devtools/performance.css)
|
||||
* skin/classic/browser/devtools/timeline.css (devtools/timeline.css)
|
||||
* skin/classic/browser/devtools/scratchpad.css (devtools/scratchpad.css)
|
||||
* skin/classic/browser/devtools/shadereditor.css (devtools/shadereditor.css)
|
||||
|
7
config/external/nss/nss.def
vendored
7
config/external/nss/nss.def
vendored
@ -87,6 +87,7 @@ CERT_FilterCertListByUsage
|
||||
CERT_FilterCertListForUserCerts
|
||||
CERT_FindCertByDERCert
|
||||
CERT_FindCertByIssuerAndSN
|
||||
CERT_FindCertByName
|
||||
CERT_FindCertByNickname
|
||||
CERT_FindCertByNicknameOrEmailAddr
|
||||
CERT_FindCertExtension
|
||||
@ -159,6 +160,8 @@ DER_GetInteger_Util
|
||||
DER_Lengths
|
||||
DER_SetUInteger
|
||||
DER_UTCTimeToTime_Util
|
||||
DSAU_DecodeDerSigToLen
|
||||
DSAU_EncodeDerSigWithLen
|
||||
DTLS_GetHandshakeTimeout
|
||||
DTLS_ImportFD
|
||||
HASH_Begin
|
||||
@ -307,6 +310,7 @@ PK11_DeriveWithTemplate
|
||||
PK11_DestroyContext
|
||||
PK11_DestroyGenericObject
|
||||
PK11_DestroyMergeLog
|
||||
PK11_DestroyObject
|
||||
PK11_DestroyTokenObject
|
||||
PK11_DigestBegin
|
||||
PK11_DigestFinal
|
||||
@ -368,6 +372,7 @@ PK11_ImportCert
|
||||
PK11_ImportCertForKey
|
||||
PK11_ImportCRL
|
||||
PK11_ImportDERPrivateKeyInfoAndReturnKey
|
||||
PK11_ImportPublicKey
|
||||
PK11_ImportSymKey
|
||||
PK11_InitPin
|
||||
PK11_IsDisabled
|
||||
@ -632,6 +637,7 @@ SSL_CipherPrefSet
|
||||
SSL_CipherPrefSetDefault
|
||||
SSL_ClearSessionCache
|
||||
SSL_ConfigSecureServer
|
||||
SSL_ConfigSecureServerWithCertChain
|
||||
SSL_ConfigServerSessionIDCache
|
||||
SSL_ExportKeyingMaterial
|
||||
SSL_ForceHandshake
|
||||
@ -670,6 +676,7 @@ VFY_CreateContext
|
||||
VFY_DestroyContext
|
||||
VFY_End
|
||||
VFY_Update
|
||||
VFY_VerifyData
|
||||
VFY_VerifyDataDirect
|
||||
VFY_VerifyDataWithAlgorithmID
|
||||
_SGN_VerifyPKCS1DigestInfo
|
||||
|
16
configure.in
16
configure.in
@ -7241,9 +7241,6 @@ dnl our own linker.
|
||||
if test "$OS_TARGET" = Android; then
|
||||
WRAP_LDFLAGS="${WRAP_LDFLAGS} -L$_objdir/dist/lib -lmozglue"
|
||||
WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=PR_GetEnv,--wrap=PR_SetEnv"
|
||||
if test -z "$gonkdir"; then
|
||||
WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=memccpy,--wrap=memchr,--wrap=memrchr,--wrap=memcmp,--wrap=memcpy,--wrap=memmove,--wrap=memset,--wrap=memmem,--wrap=index,--wrap=strchr,--wrap=strrchr,--wrap=strlen,--wrap=strcmp,--wrap=strcpy,--wrap=strcat,--wrap=strcasecmp,--wrap=strncasecmp,--wrap=strstr,--wrap=strcasestr,--wrap=strtok,--wrap=strtok_r,--wrap=strerror,--wrap=strerror_r,--wrap=strnlen,--wrap=strncat,--wrap=strncmp,--wrap=strncpy,--wrap=strlcat,--wrap=strlcpy,--wrap=strcspn,--wrap=strpbrk,--wrap=strsep,--wrap=strspn,--wrap=strcoll,--wrap=strxfrm"
|
||||
fi
|
||||
if test "$MOZ_WIDGET_TOOLKIT" = gonk -a -n "$MOZ_NUWA_PROCESS"; then
|
||||
WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=pthread_create,--wrap=epoll_wait,--wrap=poll,--wrap=pthread_cond_timedwait,--wrap=__pthread_cond_timedwait,--wrap=pthread_cond_wait,--wrap=epoll_create,--wrap=epoll_ctl,--wrap=close,--wrap=pthread_key_create,--wrap=pthread_key_delete,--wrap=socketpair,--wrap=pthread_self,--wrap=pthread_mutex_lock,--wrap=pthread_join,--wrap=pipe,--wrap=pipe2,--wrap=tgkill"
|
||||
fi
|
||||
@ -7709,6 +7706,19 @@ if test "$MOZ_CHROME_FILE_FORMAT" != "jar" &&
|
||||
AC_MSG_ERROR([--enable-chrome-format must be set to either jar, flat, or omni])
|
||||
fi
|
||||
|
||||
dnl =========================================================
|
||||
dnl Enable support for revamped devtools Performance Tools
|
||||
dnl =========================================================
|
||||
|
||||
MOZ_ARG_ENABLE_BOOL(devtools-perf,
|
||||
[ --enable-devtools-perf Set compile flags necessary for compiling devtools perftools],
|
||||
MOZ_DEVTOOLS_PERFTOOLS=1,
|
||||
MOZ_DEVTOOLS_PERFTOOLS= )
|
||||
if test -n "$MOZ_DEVTOOLS_PERFTOOLS"; then
|
||||
AC_DEFINE(MOZ_DEVTOOLS_PERFTOOLS)
|
||||
fi
|
||||
AC_SUBST(MOZ_DEVTOOLS_PERFTOOLS)
|
||||
|
||||
dnl =========================================================
|
||||
dnl Omnijar packaging (bug 552121)
|
||||
dnl =========================================================
|
||||
|
@ -435,7 +435,7 @@ DOMMatrix::TranslateSelf(double aTx,
|
||||
|
||||
if (mMatrix3D || aTz != 0) {
|
||||
Ensure3DMatrix();
|
||||
mMatrix3D->Translate(aTx, aTy, aTz);
|
||||
mMatrix3D->PreTranslate(aTx, aTy, aTz);
|
||||
} else {
|
||||
mMatrix2D->PreTranslate(aTx, aTy);
|
||||
}
|
||||
|
@ -27,7 +27,6 @@
|
||||
#include "nsIAsyncVerifyRedirectCallback.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "mozilla/dom/EncodingUtils.h"
|
||||
#include "nsIChannelPolicy.h"
|
||||
#include "nsIContentSecurityPolicy.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
@ -737,17 +736,7 @@ EventSource::InitChannelAndRequestEventSource()
|
||||
nsLoadFlags loadFlags;
|
||||
loadFlags = nsIRequest::LOAD_BACKGROUND | nsIRequest::LOAD_BYPASS_CACHE;
|
||||
|
||||
// get Content Security Policy from principal to pass into channel
|
||||
nsCOMPtr<nsIChannelPolicy> channelPolicy;
|
||||
nsCOMPtr<nsIContentSecurityPolicy> csp;
|
||||
nsresult rv = mPrincipal->GetCsp(getter_AddRefs(csp));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (csp) {
|
||||
channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
|
||||
channelPolicy->SetContentSecurityPolicy(csp);
|
||||
channelPolicy->SetLoadType(nsIContentPolicy::TYPE_DATAREQUEST);
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
nsIScriptContext* sc = GetContextForEventHandlers(&rv);
|
||||
nsCOMPtr<nsIDocument> doc =
|
||||
nsContentUtils::GetDocumentFromScriptContext(sc);
|
||||
@ -760,7 +749,6 @@ EventSource::InitChannelAndRequestEventSource()
|
||||
doc,
|
||||
nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL,
|
||||
nsIContentPolicy::TYPE_DATAREQUEST,
|
||||
channelPolicy, // aChannelPolicy
|
||||
mLoadGroup, // loadGroup
|
||||
nullptr, // aCallbacks
|
||||
loadFlags); // aLoadFlags
|
||||
@ -771,7 +759,6 @@ EventSource::InitChannelAndRequestEventSource()
|
||||
mPrincipal,
|
||||
nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL,
|
||||
nsIContentPolicy::TYPE_DATAREQUEST,
|
||||
channelPolicy, // aChannelPolicy
|
||||
mLoadGroup, // loadGroup
|
||||
nullptr, // aCallbacks
|
||||
loadFlags); // aLoadFlags
|
||||
|
@ -12,7 +12,6 @@
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCrossSiteListenerProxy.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsIChannelPolicy.h"
|
||||
#include "nsIContentPolicy.h"
|
||||
#include "nsIContentSecurityPolicy.h"
|
||||
#include "nsIDocument.h"
|
||||
@ -485,23 +484,12 @@ ImportLoader::Open()
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
|
||||
nsCOMPtr<nsILoadGroup> loadGroup = master->GetDocumentLoadGroup();
|
||||
nsCOMPtr<nsIChannelPolicy> channelPolicy;
|
||||
nsCOMPtr<nsIContentSecurityPolicy> csp;
|
||||
rv = principal->GetCsp(getter_AddRefs(csp));
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
|
||||
if (csp) {
|
||||
channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
|
||||
channelPolicy->SetContentSecurityPolicy(csp);
|
||||
channelPolicy->SetLoadType(nsIContentPolicy::TYPE_SUBDOCUMENT);
|
||||
}
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
rv = NS_NewChannel(getter_AddRefs(channel),
|
||||
mURI,
|
||||
mImportParent,
|
||||
nsILoadInfo::SEC_NORMAL,
|
||||
nsIContentPolicy::TYPE_SUBDOCUMENT,
|
||||
channelPolicy,
|
||||
loadGroup,
|
||||
nullptr, // aCallbacks
|
||||
nsIRequest::LOAD_BACKGROUND);
|
||||
|
@ -112,7 +112,6 @@ UNIFIED_SOURCES += [
|
||||
'nsAttrValue.cpp',
|
||||
'nsAttrValueOrString.cpp',
|
||||
'nsCCUncollectableMarker.cpp',
|
||||
'nsChannelPolicy.cpp',
|
||||
'nsContentAreaDragDrop.cpp',
|
||||
'nsContentIterator.cpp',
|
||||
'nsContentList.cpp',
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include "nsCSPService.h"
|
||||
#include "nsError.h"
|
||||
#include "nsIAsyncVerifyRedirectCallback.h"
|
||||
#include "nsIChannelPolicy.h"
|
||||
#include "nsIClassInfoImpl.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsIDocShellTreeItem.h"
|
||||
@ -25,12 +24,10 @@
|
||||
#include "nsIObjectOutputStream.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIPropertyBag2.h"
|
||||
#include "nsIStringStream.h"
|
||||
#include "nsIUploadChannel.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsIWebNavigation.h"
|
||||
#include "nsIWritablePropertyBag2.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsNullPrincipal.h"
|
||||
#include "nsIContentPolicy.h"
|
||||
|
@ -12,17 +12,13 @@
|
||||
#include "nsIContent.h"
|
||||
#include "nsCSPService.h"
|
||||
#include "nsIContentSecurityPolicy.h"
|
||||
#include "nsIChannelPolicy.h"
|
||||
#include "nsIChannelEventSink.h"
|
||||
#include "nsIPropertyBag2.h"
|
||||
#include "nsIWritablePropertyBag2.h"
|
||||
#include "nsError.h"
|
||||
#include "nsChannelProperties.h"
|
||||
#include "nsIAsyncVerifyRedirectCallback.h"
|
||||
#include "nsAsyncRedirectVerifyHelper.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsContentPolicyUtils.h"
|
||||
#include "nsPrincipal.h"
|
||||
|
||||
using namespace mozilla;
|
||||
@ -236,53 +232,56 @@ CSPService::AsyncOnChannelRedirect(nsIChannel *oldChannel,
|
||||
{
|
||||
nsAsyncRedirectAutoCallback autoCallback(callback);
|
||||
|
||||
// get the Content Security Policy and load type from the property bag
|
||||
nsCOMPtr<nsISupports> policyContainer;
|
||||
nsCOMPtr<nsIPropertyBag2> props(do_QueryInterface(oldChannel));
|
||||
if (!props)
|
||||
nsCOMPtr<nsILoadInfo> loadInfo;
|
||||
nsresult rv = oldChannel->GetLoadInfo(getter_AddRefs(loadInfo));
|
||||
|
||||
// if no loadInfo on the channel, nothing for us to do
|
||||
if (!loadInfo) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
props->GetPropertyAsInterface(NS_CHANNEL_PROP_CHANNEL_POLICY,
|
||||
NS_GET_IID(nsISupports),
|
||||
getter_AddRefs(policyContainer));
|
||||
// The loadInfo must not necessarily contain a Node, hence we try to query
|
||||
// the CSP in the following order:
|
||||
// a) Get the Node, the Principal of that Node, and the CSP of that Principal
|
||||
// b) Get the Principal and the CSP of that Principal
|
||||
|
||||
// see if we have a valid nsIChannelPolicy containing CSP and load type
|
||||
nsCOMPtr<nsIChannelPolicy> channelPolicy(do_QueryInterface(policyContainer));
|
||||
if (!channelPolicy)
|
||||
return NS_OK;
|
||||
|
||||
nsCOMPtr<nsISupports> supports;
|
||||
nsCOMPtr<nsINode> loadingNode = loadInfo->LoadingNode();
|
||||
nsCOMPtr<nsIPrincipal> principal = loadingNode ?
|
||||
loadingNode->NodePrincipal() :
|
||||
loadInfo->LoadingPrincipal();
|
||||
NS_ASSERTION(principal, "Can not evaluate CSP without a principal");
|
||||
nsCOMPtr<nsIContentSecurityPolicy> csp;
|
||||
channelPolicy->GetContentSecurityPolicy(getter_AddRefs(supports));
|
||||
csp = do_QueryInterface(supports);
|
||||
uint32_t loadType;
|
||||
channelPolicy->GetLoadType(&loadType);
|
||||
rv = principal->GetCsp(getter_AddRefs(csp));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// if no CSP in the channelPolicy, nothing for us to add to the channel
|
||||
if (!csp)
|
||||
// if there is no CSP, nothing for us to do
|
||||
if (!csp) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* Since redirecting channels don't call into nsIContentPolicy, we call our
|
||||
* Content Policy implementation directly when redirects occur. When channels
|
||||
* are created using NS_NewChannel(), callers can optionally pass in a
|
||||
* nsIChannelPolicy containing a CSP object and load type, which is placed in
|
||||
* the new channel's property bag. This container is propagated forward when
|
||||
* channels redirect.
|
||||
* Content Policy implementation directly when redirects occur using the
|
||||
* information set in the LoadInfo when channels are created.
|
||||
*
|
||||
* We check if the CSP permits this host for this type of load, if not,
|
||||
* we cancel the load now.
|
||||
*/
|
||||
|
||||
// Does the CSP permit this host for this type of load?
|
||||
// If not, cancel the load now.
|
||||
nsCOMPtr<nsIURI> newUri;
|
||||
newChannel->GetURI(getter_AddRefs(newUri));
|
||||
rv = newChannel->GetURI(getter_AddRefs(newUri));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsIURI> originalUri;
|
||||
oldChannel->GetOriginalURI(getter_AddRefs(originalUri));
|
||||
rv = oldChannel->GetOriginalURI(getter_AddRefs(originalUri));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsContentPolicyType policyType = loadInfo->GetContentPolicyType();
|
||||
|
||||
int16_t aDecision = nsIContentPolicy::ACCEPT;
|
||||
csp->ShouldLoad(loadType, // load type per nsIContentPolicy (uint32_t)
|
||||
newUri, // nsIURI
|
||||
nullptr, // nsIURI
|
||||
nullptr, // nsISupports
|
||||
EmptyCString(), // ACString - MIME guess
|
||||
originalUri, // nsISupports - extra
|
||||
csp->ShouldLoad(policyType, // load type per nsIContentPolicy (uint32_t)
|
||||
newUri, // nsIURI
|
||||
nullptr, // nsIURI
|
||||
nullptr, // nsISupports
|
||||
EmptyCString(), // ACString - MIME guess
|
||||
originalUri, // aMimeTypeGuess
|
||||
&aDecision);
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
@ -302,36 +301,9 @@ CSPService::AsyncOnChannelRedirect(nsIChannel *oldChannel,
|
||||
#endif
|
||||
|
||||
// if ShouldLoad doesn't accept the load, cancel the request
|
||||
if (aDecision != 1) {
|
||||
if (!NS_CP_ACCEPTED(aDecision)) {
|
||||
autoCallback.DontCallback();
|
||||
return NS_BINDING_FAILED;
|
||||
}
|
||||
|
||||
// the redirect is permitted, so propagate the Content Security Policy
|
||||
// and load type to the redirecting channel
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIWritablePropertyBag2> props2 = do_QueryInterface(newChannel);
|
||||
if (props2) {
|
||||
rv = props2->SetPropertyAsInterface(NS_CHANNEL_PROP_CHANNEL_POLICY,
|
||||
channelPolicy);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// The redirecting channel isn't a writable property bag, we won't be able
|
||||
// to enforce the load policy if it redirects again, so we stop it now.
|
||||
nsAutoCString newUriSpec;
|
||||
rv = newUri->GetSpec(newUriSpec);
|
||||
NS_ConvertUTF8toUTF16 unicodeSpec(newUriSpec);
|
||||
const char16_t *formatParams[] = { unicodeSpec.get() };
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
|
||||
NS_LITERAL_CSTRING("Redirect Error"), nullptr,
|
||||
nsContentUtils::eDOM_PROPERTIES,
|
||||
"InvalidRedirectChannelWarning",
|
||||
formatParams, 1);
|
||||
}
|
||||
|
||||
return NS_BINDING_FAILED;
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -1,46 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* 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 "nsChannelPolicy.h"
|
||||
|
||||
nsChannelPolicy::nsChannelPolicy()
|
||||
: mLoadType(0)
|
||||
{
|
||||
}
|
||||
|
||||
nsChannelPolicy::~nsChannelPolicy()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsChannelPolicy, nsIChannelPolicy)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsChannelPolicy::GetLoadType(uint32_t *aLoadType)
|
||||
{
|
||||
*aLoadType = mLoadType;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsChannelPolicy::SetLoadType(uint32_t aLoadType)
|
||||
{
|
||||
mLoadType = aLoadType;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsChannelPolicy::GetContentSecurityPolicy(nsISupports **aCSP)
|
||||
{
|
||||
*aCSP = mCSP;
|
||||
NS_IF_ADDREF(*aCSP);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsChannelPolicy::SetContentSecurityPolicy(nsISupports *aCSP)
|
||||
{
|
||||
mCSP = aCSP;
|
||||
return NS_OK;
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* 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 nsChannelPolicy_h___
|
||||
#define nsChannelPolicy_h___
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIChannelPolicy.h"
|
||||
|
||||
#define NSCHANNELPOLICY_CONTRACTID "@mozilla.org/nschannelpolicy;1"
|
||||
#define NSCHANNELPOLICY_CID \
|
||||
{ 0xd396b3cd, 0xf164, 0x4ce8, \
|
||||
{ 0x93, 0xa7, 0xe3, 0x85, 0xe1, 0x46, 0x56, 0x3c } }
|
||||
|
||||
class nsChannelPolicy : public nsIChannelPolicy
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSICHANNELPOLICY
|
||||
|
||||
nsChannelPolicy();
|
||||
|
||||
protected:
|
||||
virtual ~nsChannelPolicy();
|
||||
|
||||
/* Represents the type of content being loaded in the channel per
|
||||
* nsIContentPolicy, e.g. TYPE_IMAGE, TYPE_SCRIPT
|
||||
*/
|
||||
unsigned long mLoadType;
|
||||
|
||||
/* pointer to a Content Security Policy object if available */
|
||||
nsCOMPtr<nsISupports> mCSP;
|
||||
};
|
||||
|
||||
#endif /* nsChannelPolicy_h___ */
|
@ -59,7 +59,6 @@
|
||||
#include "nsAttrValueInlines.h"
|
||||
#include "nsBindingManager.h"
|
||||
#include "nsCCUncollectableMarker.h"
|
||||
#include "nsChannelPolicy.h"
|
||||
#include "nsCharSeparatedTokenizer.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsContentCreatorFunctions.h"
|
||||
@ -88,7 +87,6 @@
|
||||
#include "nsIAsyncVerifyRedirectCallback.h"
|
||||
#include "nsICategoryManager.h"
|
||||
#include "nsIChannelEventSink.h"
|
||||
#include "nsIChannelPolicy.h"
|
||||
#include "nsICharsetDetectionObserver.h"
|
||||
#include "nsIChromeRegistry.h"
|
||||
#include "nsIConsoleService.h"
|
||||
@ -3007,20 +3005,6 @@ nsContentUtils::LoadImage(nsIURI* aURI, nsIDocument* aLoadingDocument,
|
||||
NS_ASSERTION(loadGroup || IsFontTableURI(documentURI),
|
||||
"Could not get loadgroup; onload may fire too early");
|
||||
|
||||
// check for a Content Security Policy to pass down to the channel that
|
||||
// will get created to load the image
|
||||
nsCOMPtr<nsIChannelPolicy> channelPolicy;
|
||||
nsCOMPtr<nsIContentSecurityPolicy> csp;
|
||||
if (aLoadingPrincipal) {
|
||||
nsresult rv = aLoadingPrincipal->GetCsp(getter_AddRefs(csp));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (csp) {
|
||||
channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
|
||||
channelPolicy->SetContentSecurityPolicy(csp);
|
||||
channelPolicy->SetLoadType(nsIContentPolicy::TYPE_IMAGE);
|
||||
}
|
||||
}
|
||||
|
||||
// Make the URI immutable so people won't change it under us
|
||||
NS_TryToSetImmutable(aURI);
|
||||
|
||||
@ -3035,7 +3019,6 @@ nsContentUtils::LoadImage(nsIURI* aURI, nsIDocument* aLoadingDocument,
|
||||
aLoadingDocument, /* uniquification key */
|
||||
aLoadFlags, /* load flags */
|
||||
nullptr, /* cache key */
|
||||
channelPolicy, /* CSP info */
|
||||
initiatorType, /* the load initiator */
|
||||
aRequest);
|
||||
}
|
||||
|
@ -1122,7 +1122,6 @@ NS_StartCORSPreflight(nsIChannel* aRequestChannel,
|
||||
rv = NS_NewChannelInternal(getter_AddRefs(preflightChannel),
|
||||
uri,
|
||||
loadInfo,
|
||||
nullptr, // aChannelPolicy
|
||||
loadGroup,
|
||||
nullptr, // aCallbacks
|
||||
loadFlags);
|
||||
@ -1134,7 +1133,6 @@ NS_StartCORSPreflight(nsIChannel* aRequestChannel,
|
||||
nsContentUtils::GetSystemPrincipal(),
|
||||
nsILoadInfo::SEC_NORMAL,
|
||||
nsIContentPolicy::TYPE_OTHER,
|
||||
nullptr, // aChannelPolicy
|
||||
loadGroup,
|
||||
nullptr, // aCallbacks
|
||||
loadFlags);
|
||||
|
@ -1330,7 +1330,6 @@ nsExternalResourceMap::PendingLoad::StartLoad(nsIURI* aURI,
|
||||
aRequestingNode,
|
||||
nsILoadInfo::SEC_NORMAL,
|
||||
nsIContentPolicy::TYPE_OTHER,
|
||||
nullptr, // aChannelPolicy
|
||||
loadGroup,
|
||||
req); // aCallbacks
|
||||
|
||||
|
@ -65,8 +65,6 @@
|
||||
#include "nsObjectLoadingContent.h"
|
||||
#include "mozAutoDocUpdate.h"
|
||||
#include "nsIContentSecurityPolicy.h"
|
||||
#include "nsIChannelPolicy.h"
|
||||
#include "nsChannelPolicy.h"
|
||||
#include "GeckoProfiler.h"
|
||||
#include "nsPluginFrame.h"
|
||||
#include "nsDOMClassInfo.h"
|
||||
@ -2492,15 +2490,6 @@ nsObjectLoadingContent::OpenChannel()
|
||||
|
||||
nsCOMPtr<nsILoadGroup> group = doc->GetDocumentLoadGroup();
|
||||
nsCOMPtr<nsIChannel> chan;
|
||||
nsCOMPtr<nsIChannelPolicy> channelPolicy;
|
||||
nsCOMPtr<nsIContentSecurityPolicy> csp;
|
||||
rv = doc->NodePrincipal()->GetCsp(getter_AddRefs(csp));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (csp) {
|
||||
channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
|
||||
channelPolicy->SetContentSecurityPolicy(csp);
|
||||
channelPolicy->SetLoadType(nsIContentPolicy::TYPE_OBJECT);
|
||||
}
|
||||
nsRefPtr<ObjectInterfaceRequestorShim> shim =
|
||||
new ObjectInterfaceRequestorShim(this);
|
||||
|
||||
@ -2522,7 +2511,6 @@ nsObjectLoadingContent::OpenChannel()
|
||||
thisContent,
|
||||
securityFlags,
|
||||
nsIContentPolicy::TYPE_OBJECT,
|
||||
channelPolicy,
|
||||
group, // aLoadGroup
|
||||
shim, // aCallbacks
|
||||
nsIChannel::LOAD_CALL_CONTENT_SNIFFERS |
|
||||
|
@ -41,8 +41,6 @@
|
||||
#include "nsDocShellCID.h"
|
||||
#include "nsIContentSecurityPolicy.h"
|
||||
#include "prlog.h"
|
||||
#include "nsIChannelPolicy.h"
|
||||
#include "nsChannelPolicy.h"
|
||||
#include "nsCRT.h"
|
||||
#include "nsContentCreatorFunctions.h"
|
||||
#include "nsCrossSiteListenerProxy.h"
|
||||
@ -307,25 +305,12 @@ nsScriptLoader::StartLoad(nsScriptLoadRequest *aRequest, const nsAString &aType,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// check for a Content Security Policy to pass down to the channel
|
||||
// that will be created to load the script
|
||||
nsCOMPtr<nsIChannelPolicy> channelPolicy;
|
||||
nsCOMPtr<nsIContentSecurityPolicy> csp;
|
||||
rv = mDocument->NodePrincipal()->GetCsp(getter_AddRefs(csp));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (csp) {
|
||||
channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
|
||||
channelPolicy->SetContentSecurityPolicy(csp);
|
||||
channelPolicy->SetLoadType(nsIContentPolicy::TYPE_SCRIPT);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
rv = NS_NewChannel(getter_AddRefs(channel),
|
||||
aRequest->mURI,
|
||||
mDocument,
|
||||
nsILoadInfo::SEC_NORMAL,
|
||||
nsIContentPolicy::TYPE_SCRIPT,
|
||||
channelPolicy,
|
||||
loadGroup,
|
||||
prompter,
|
||||
nsIRequest::LOAD_NORMAL |
|
||||
|
@ -315,7 +315,6 @@ nsSyncLoadService::LoadDocument(nsIURI *aURI, nsIPrincipal *aLoaderPrincipal,
|
||||
aLoaderPrincipal,
|
||||
nsILoadInfo::SEC_NORMAL,
|
||||
nsIContentPolicy::TYPE_OTHER,
|
||||
nullptr, // aChannelPolicy
|
||||
aLoadGroup);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
@ -52,8 +52,6 @@
|
||||
#include "nsIPromptFactory.h"
|
||||
#include "nsIWindowWatcher.h"
|
||||
#include "nsIConsoleService.h"
|
||||
#include "nsIChannelPolicy.h"
|
||||
#include "nsChannelPolicy.h"
|
||||
#include "nsIContentSecurityPolicy.h"
|
||||
#include "nsAsyncRedirectVerifyHelper.h"
|
||||
#include "nsStringBuffer.h"
|
||||
@ -474,6 +472,10 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXMLHttpRequest,
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mXMLParserStreamListener)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mResponseBlob)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMFile)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNotificationCallbacks)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChannelEventSink)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mProgressEventSink)
|
||||
|
||||
@ -492,6 +494,10 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsXMLHttpRequest,
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mXMLParserStreamListener)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mResponseBlob)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMFile)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mNotificationCallbacks)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mChannelEventSink)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mProgressEventSink)
|
||||
|
||||
@ -1724,17 +1730,6 @@ nsXMLHttpRequest::Open(const nsACString& inMethod, const nsACString& url,
|
||||
// will be automatically aborted if the user leaves the page.
|
||||
nsCOMPtr<nsILoadGroup> loadGroup = GetLoadGroup();
|
||||
|
||||
// get Content Security Policy from principal to pass into channel
|
||||
nsCOMPtr<nsIChannelPolicy> channelPolicy;
|
||||
nsCOMPtr<nsIContentSecurityPolicy> csp;
|
||||
rv = mPrincipal->GetCsp(getter_AddRefs(csp));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (csp) {
|
||||
channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
|
||||
channelPolicy->SetContentSecurityPolicy(csp);
|
||||
channelPolicy->SetLoadType(nsIContentPolicy::TYPE_XMLHTTPREQUEST);
|
||||
}
|
||||
|
||||
nsSecurityFlags secFlags = nsILoadInfo::SEC_NORMAL;
|
||||
if (IsSystemXHR()) {
|
||||
// Don't give this document the system principal. We need to keep track of
|
||||
@ -1754,7 +1749,6 @@ nsXMLHttpRequest::Open(const nsACString& inMethod, const nsACString& url,
|
||||
doc,
|
||||
secFlags,
|
||||
nsIContentPolicy::TYPE_XMLHTTPREQUEST,
|
||||
channelPolicy,
|
||||
loadGroup,
|
||||
nullptr, // aCallbacks
|
||||
nsIRequest::LOAD_BACKGROUND);
|
||||
@ -1765,7 +1759,6 @@ nsXMLHttpRequest::Open(const nsACString& inMethod, const nsACString& url,
|
||||
mPrincipal,
|
||||
secFlags,
|
||||
nsIContentPolicy::TYPE_XMLHTTPREQUEST,
|
||||
channelPolicy,
|
||||
loadGroup,
|
||||
nullptr, // aCallbacks
|
||||
nsIRequest::LOAD_BACKGROUND);
|
||||
|
@ -291,6 +291,7 @@ skip-if = buildapp == 'b2g' || toolkit == 'android' # b2g(https not working, bug
|
||||
[test_bug340571.html]
|
||||
[test_bug343596.html]
|
||||
[test_bug345339.html]
|
||||
skip-if = e10s # Bug 1081453 - shutdown leaks with e10s and WebIDL dom::File
|
||||
[test_bug346485.html]
|
||||
[test_bug352728.html]
|
||||
[test_bug352728.xhtml]
|
||||
|
@ -99,8 +99,6 @@ static PRLogModuleInfo* gMediaElementEventsLog;
|
||||
#endif
|
||||
|
||||
#include "nsIContentSecurityPolicy.h"
|
||||
#include "nsIChannelPolicy.h"
|
||||
#include "nsChannelPolicy.h"
|
||||
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
@ -1170,25 +1168,12 @@ nsresult HTMLMediaElement::LoadResource()
|
||||
}
|
||||
|
||||
nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup();
|
||||
|
||||
// check for a Content Security Policy to pass down to the channel
|
||||
// created to load the media content
|
||||
nsCOMPtr<nsIChannelPolicy> channelPolicy;
|
||||
nsCOMPtr<nsIContentSecurityPolicy> csp;
|
||||
rv = NodePrincipal()->GetCsp(getter_AddRefs(csp));
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
if (csp) {
|
||||
channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
|
||||
channelPolicy->SetContentSecurityPolicy(csp);
|
||||
channelPolicy->SetLoadType(nsIContentPolicy::TYPE_MEDIA);
|
||||
}
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
rv = NS_NewChannel(getter_AddRefs(channel),
|
||||
mLoadingSrc,
|
||||
static_cast<Element*>(this),
|
||||
nsILoadInfo::SEC_NORMAL,
|
||||
nsIContentPolicy::TYPE_MEDIA,
|
||||
channelPolicy,
|
||||
loadGroup,
|
||||
nullptr, // aCallbacks
|
||||
nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE_IF_BUSY |
|
||||
|
@ -21,7 +21,6 @@
|
||||
#include "nsIAsyncVerifyRedirectCallback.h"
|
||||
#include "nsICachingChannel.h"
|
||||
#include "nsIChannelEventSink.h"
|
||||
#include "nsIChannelPolicy.h"
|
||||
#include "nsIContentPolicy.h"
|
||||
#include "nsIContentSecurityPolicy.h"
|
||||
#include "nsIDocument.h"
|
||||
@ -237,20 +236,6 @@ HTMLTrackElement::LoadResource()
|
||||
CreateTextTrack();
|
||||
}
|
||||
|
||||
// Check for a Content Security Policy to pass down to the channel
|
||||
// created to load the media content.
|
||||
nsCOMPtr<nsIChannelPolicy> channelPolicy;
|
||||
nsCOMPtr<nsIContentSecurityPolicy> csp;
|
||||
rv = NodePrincipal()->GetCsp(getter_AddRefs(csp));
|
||||
NS_ENSURE_TRUE_VOID(NS_SUCCEEDED(rv));
|
||||
if (csp) {
|
||||
channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
|
||||
if (!channelPolicy) {
|
||||
return;
|
||||
}
|
||||
channelPolicy->SetContentSecurityPolicy(csp);
|
||||
channelPolicy->SetLoadType(nsIContentPolicy::TYPE_MEDIA);
|
||||
}
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
nsCOMPtr<nsILoadGroup> loadGroup = OwnerDoc()->GetDocumentLoadGroup();
|
||||
rv = NS_NewChannel(getter_AddRefs(channel),
|
||||
@ -258,7 +243,6 @@ HTMLTrackElement::LoadResource()
|
||||
static_cast<Element*>(this),
|
||||
nsILoadInfo::SEC_NORMAL,
|
||||
nsIContentPolicy::TYPE_MEDIA,
|
||||
channelPolicy,
|
||||
loadGroup);
|
||||
|
||||
NS_ENSURE_TRUE_VOID(NS_SUCCEEDED(rv));
|
||||
|
@ -291,16 +291,11 @@ static const nsAttrValue::EnumTable kDirTable[] = {
|
||||
void
|
||||
nsGenericHTMLElement::GetAccessKeyLabel(nsString& aLabel)
|
||||
{
|
||||
//XXXsmaug We shouldn't need PresContext for this.
|
||||
nsPresContext *presContext = GetPresContext(eForComposedDoc);
|
||||
|
||||
if (presContext) {
|
||||
nsAutoString suffix;
|
||||
GetAccessKey(suffix);
|
||||
if (!suffix.IsEmpty() &&
|
||||
presContext->EventStateManager()->GetAccessKeyLabelPrefix(aLabel)) {
|
||||
aLabel.Append(suffix);
|
||||
}
|
||||
nsAutoString suffix;
|
||||
GetAccessKey(suffix);
|
||||
if (!suffix.IsEmpty()) {
|
||||
EventStateManager::GetAccessKeyLabelPrefix(this, aLabel);
|
||||
aLabel.Append(suffix);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1516,7 +1516,6 @@ nsHTMLDocument::Open(JSContext* cx,
|
||||
callerDoc,
|
||||
nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL,
|
||||
nsIContentPolicy::TYPE_OTHER,
|
||||
nullptr, // aChannelPolicy
|
||||
group);
|
||||
|
||||
if (rv.Failed()) {
|
||||
|
@ -464,7 +464,7 @@ AsyncCubebTask::AsyncCubebTask(AudioCallbackDriver* aDriver, AsyncCubebOperation
|
||||
mOperation(aOperation),
|
||||
mShutdownGrip(aDriver->GraphImpl())
|
||||
{
|
||||
MOZ_ASSERT(mDriver->mAudioStream || aOperation == INIT, "No audio stream !");
|
||||
NS_WARN_IF_FALSE(mDriver->mAudioStream || aOperation == INIT, "No audio stream !");
|
||||
}
|
||||
|
||||
AsyncCubebTask::~AsyncCubebTask()
|
||||
|
@ -924,7 +924,6 @@ ChannelMediaResource::RecreateChannel()
|
||||
element,
|
||||
nsILoadInfo::SEC_NORMAL,
|
||||
nsIContentPolicy::TYPE_MEDIA,
|
||||
nullptr, // aChannelPolicy
|
||||
loadGroup,
|
||||
nullptr, // aCallbacks
|
||||
loadFlags);
|
||||
@ -1442,7 +1441,6 @@ already_AddRefed<MediaResource> FileMediaResource::CloneData(MediaDecoder* aDeco
|
||||
element,
|
||||
nsILoadInfo::SEC_NORMAL,
|
||||
nsIContentPolicy::TYPE_MEDIA,
|
||||
nullptr, // aChannelPolicy
|
||||
loadGroup);
|
||||
|
||||
if (NS_FAILED(rv))
|
||||
|
@ -202,24 +202,26 @@ void
|
||||
MediaSourceReader::Shutdown()
|
||||
{
|
||||
MediaDecoderReader::Shutdown();
|
||||
for (uint32_t i = 0; i < mTrackBuffers.Length(); ++i) {
|
||||
mTrackBuffers[i]->Shutdown();
|
||||
}
|
||||
mAudioTrack = nullptr;
|
||||
mAudioReader = nullptr;
|
||||
mVideoTrack = nullptr;
|
||||
mVideoReader = nullptr;
|
||||
for (uint32_t i = 0; i < mTrackBuffers.Length(); ++i) {
|
||||
mTrackBuffers[i]->Shutdown();
|
||||
}
|
||||
mTrackBuffers.Clear();
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceReader::BreakCycles()
|
||||
{
|
||||
MediaDecoderReader::BreakCycles();
|
||||
mAudioTrack = nullptr;
|
||||
mAudioReader = nullptr;
|
||||
mVideoTrack = nullptr;
|
||||
mVideoReader = nullptr;
|
||||
|
||||
// These were cleared in Shutdown().
|
||||
MOZ_ASSERT(!mAudioTrack);
|
||||
MOZ_ASSERT(!mAudioReader);
|
||||
MOZ_ASSERT(!mVideoTrack);
|
||||
MOZ_ASSERT(!mVideoReader);
|
||||
|
||||
for (uint32_t i = 0; i < mTrackBuffers.Length(); ++i) {
|
||||
mTrackBuffers[i]->BreakCycles();
|
||||
}
|
||||
|
@ -416,8 +416,21 @@ SourceBuffer::Dump(const char* aPath)
|
||||
}
|
||||
#endif
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED(SourceBuffer, DOMEventTargetHelper,
|
||||
mMediaSource)
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(SourceBuffer)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(SourceBuffer)
|
||||
// Tell the TrackBuffer to end its current SourceBufferResource.
|
||||
TrackBuffer* track = tmp->mTrackBuffer;
|
||||
if (track) {
|
||||
track->Detach();
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mMediaSource)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(DOMEventTargetHelper)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(SourceBuffer,
|
||||
DOMEventTargetHelper)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaSource)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(SourceBuffer, DOMEventTargetHelper)
|
||||
NS_IMPL_RELEASE_INHERITED(SourceBuffer, DOMEventTargetHelper)
|
||||
|
@ -54,31 +54,22 @@ TrackBuffer::~TrackBuffer()
|
||||
class ReleaseDecoderTask : public nsRunnable {
|
||||
public:
|
||||
explicit ReleaseDecoderTask(SourceBufferDecoder* aDecoder)
|
||||
: mDecoder(aDecoder)
|
||||
{
|
||||
mDecoders.AppendElement(aDecoder);
|
||||
}
|
||||
|
||||
explicit ReleaseDecoderTask(nsTArray<nsRefPtr<SourceBufferDecoder>>& aDecoders)
|
||||
{
|
||||
mDecoders.SwapElements(aDecoders);
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() MOZ_OVERRIDE MOZ_FINAL {
|
||||
mDecoders.Clear();
|
||||
mDecoder = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsTArray<nsRefPtr<SourceBufferDecoder>> mDecoders;
|
||||
nsRefPtr<SourceBufferDecoder> mDecoder;
|
||||
};
|
||||
|
||||
void
|
||||
TrackBuffer::Shutdown()
|
||||
{
|
||||
// End the SourceBufferResource associated with mCurrentDecoder, which will
|
||||
// unblock any decoder initialization in ReadMetadata().
|
||||
DiscardDecoder();
|
||||
|
||||
// Finish any decoder initialization, which may add to mInitializedDecoders.
|
||||
// Shutdown waits for any pending events, which may require the monitor,
|
||||
// so we must not hold the monitor during this call.
|
||||
@ -91,8 +82,6 @@ TrackBuffer::Shutdown()
|
||||
mDecoders[i]->GetReader()->Shutdown();
|
||||
}
|
||||
mInitializedDecoders.Clear();
|
||||
NS_DispatchToMainThread(new ReleaseDecoderTask(mDecoders));
|
||||
MOZ_ASSERT(mDecoders.IsEmpty());
|
||||
mParentDecoder = nullptr;
|
||||
}
|
||||
|
||||
@ -399,13 +388,16 @@ TrackBuffer::ContainsTime(int64_t aTime)
|
||||
void
|
||||
TrackBuffer::BreakCycles()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
for (uint32_t i = 0; i < mDecoders.Length(); ++i) {
|
||||
mDecoders[i]->GetReader()->BreakCycles();
|
||||
}
|
||||
mInitializedDecoders.Clear();
|
||||
NS_DispatchToMainThread(new ReleaseDecoderTask(mDecoders));
|
||||
MOZ_ASSERT(mDecoders.IsEmpty());
|
||||
mParentDecoder = nullptr;
|
||||
mDecoders.Clear();
|
||||
|
||||
// These are cleared in Shutdown()
|
||||
MOZ_ASSERT(mInitializedDecoders.IsEmpty());
|
||||
MOZ_ASSERT(!mParentDecoder);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -460,7 +460,6 @@ skip-if = true # bug 1021673
|
||||
[test_standalone.html]
|
||||
[test_streams_autoplay.html]
|
||||
[test_streams_element_capture.html]
|
||||
skip-if = e10s && os == 'win' # Bug 1065881 - Crash on child process shutdown in ShadowLayerForwarder::InWorkerThread
|
||||
[test_streams_element_capture_createObjectURL.html]
|
||||
[test_streams_element_capture_playback.html]
|
||||
[test_streams_element_capture_reset.html]
|
||||
|
@ -97,9 +97,9 @@ function startTest(test, token) {
|
||||
|
||||
// This handler completes a start and stop of recording and verifies
|
||||
// respective media recorder state.
|
||||
var canPlayThrough = function() {
|
||||
element.removeEventListener('canplaythrough', canPlayThrough, false);
|
||||
|
||||
element.onloadedmetadata = function () {
|
||||
element.onloadedmetadata = null;
|
||||
element.play();
|
||||
mediaRecorder.start();
|
||||
is(mediaRecorder.state, 'recording', 'Media recorder should be recording');
|
||||
is(mediaRecorder.stream, element.stream,
|
||||
@ -112,8 +112,7 @@ function startTest(test, token) {
|
||||
'Media recorder stream = element stream post recording');
|
||||
};
|
||||
|
||||
element.addEventListener('canplaythrough', canPlayThrough, false);
|
||||
element.play();
|
||||
element.preload = "metadata";
|
||||
}
|
||||
|
||||
manager.runTests(gMediaRecorderTests, startTest);
|
||||
|
@ -84,24 +84,18 @@ function startTest(test, token) {
|
||||
}
|
||||
};
|
||||
|
||||
element.oncanplaythrough = function () {
|
||||
element.oncanplaythrough = null;
|
||||
// If content has ended, skip the test
|
||||
if (element.ended) {
|
||||
ok(true, 'ended fired before canplaythrough, skipping test');
|
||||
manager.finished(token);
|
||||
} else {
|
||||
// If content hasn't ended, start recording
|
||||
mediaRecorder.start();
|
||||
is(mediaRecorder.state, 'recording',
|
||||
'Media recorder should be recording');
|
||||
is(mediaRecorder.stream, element.stream,
|
||||
'Media recorder stream = element stream at the start of recording');
|
||||
// Recording will automatically stop when the stream ends.
|
||||
}
|
||||
}
|
||||
element.preload = "metadata";
|
||||
|
||||
element.play();
|
||||
element.onloadedmetadata = function () {
|
||||
element.onloadedmetadata = null;
|
||||
mediaRecorder.start();
|
||||
is(mediaRecorder.state, 'recording',
|
||||
'Media recorder should be recording');
|
||||
is(mediaRecorder.stream, element.stream,
|
||||
'Media recorder stream = element stream at the start of recording');
|
||||
|
||||
element.play();
|
||||
}
|
||||
}
|
||||
|
||||
manager.runTests(gMediaRecorderTests, startTest);
|
||||
|
@ -54,15 +54,17 @@ function startTest(test, token) {
|
||||
ok(false, 'Unexpected warning fired');
|
||||
}
|
||||
|
||||
element.oncanplaythrough = function () {
|
||||
element.oncanplaythrough = null;
|
||||
element.preload = "metadata";
|
||||
|
||||
element.onloadedmetadata = function () {
|
||||
element.onloadedmetadata = null;
|
||||
element.play();
|
||||
for (var i = 0; i < mExpectStopCount; i++) {
|
||||
mediaRecorder.start(1000);
|
||||
mediaRecorder.stop();
|
||||
}
|
||||
}
|
||||
|
||||
element.play();
|
||||
}
|
||||
|
||||
manager.runTests(gMediaRecorderTests, startTest);
|
||||
|
@ -17,17 +17,17 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=495319
|
||||
|
||||
var manager = new MediaTestManager;
|
||||
|
||||
function timeupdate(e) {
|
||||
var v = e.target;
|
||||
v._timeupdateCount++;
|
||||
ok(v.gotEnded == 0, v._name + " - shouldn't get timeupdate after ended");
|
||||
}
|
||||
|
||||
function ended(e) {
|
||||
var v = e.target;
|
||||
++v.gotEnded;
|
||||
ok(v._timeupdateCount > 0, v._name + " - should see at least one timeupdate: " + v.currentTime);
|
||||
v._finished = true;
|
||||
++v.counter["ended"];
|
||||
is(v.counter["ended"], 1, v._name + " should see ended only once");
|
||||
ok(v.counter["timeupdate"] > 0, v._name + " should see at least one timeupdate: " + v.currentTime);
|
||||
|
||||
// Rest event counters for we don't allow events after ended.
|
||||
eventsToLog.forEach(function(e) {
|
||||
v.counter[e] = 0;
|
||||
});
|
||||
|
||||
// Finish the test after 500ms. We shouldn't receive any timeupdate events
|
||||
// after the ended event, so this gives time for any pending timeupdate events
|
||||
// to fire so we can ensure we don't regress behaviour.
|
||||
@ -39,10 +39,9 @@ function ended(e) {
|
||||
// invoked when it's removed from a document), and we don't want those
|
||||
// confusing the test results.
|
||||
v.removeEventListener("ended", ended, false);
|
||||
v.removeEventListener("timeupdate", timeupdate, false);
|
||||
for (var i = 0; i < eventsToLog.length; ++i) {
|
||||
v.removeEventListener(eventsToLog[i], logEvent, false);
|
||||
}
|
||||
eventsToLog.forEach(function(e) {
|
||||
v.removeEventListener(e, logEvent, false);
|
||||
});
|
||||
removeNodeAndSource(v);
|
||||
manager.finished(v.token);
|
||||
},
|
||||
@ -50,17 +49,14 @@ function ended(e) {
|
||||
}
|
||||
|
||||
var eventsToLog = ["play", "canplay", "canplaythrough", "loadstart", "loadedmetadata",
|
||||
"loadeddata", "playing", "progress", "timeupdate", "ended", "suspend", "error", "stalled", "emptied", "abort",
|
||||
"loadeddata", "playing", "timeupdate", "error", "stalled", "emptied", "abort",
|
||||
"waiting", "pause"];
|
||||
|
||||
function logEvent(event) {
|
||||
if (event.target.gotEnded > (event.type == "ended" ? 1 : 0)) {
|
||||
if (event.target.currentSrc.slice(-9) == "seek.webm" && event.type == "stalled") {
|
||||
todo(false, event.target.currentSrc + " got unexpected stalled after ended (bug 760770)");
|
||||
} else {
|
||||
ok(false, event.target.currentSrc + " got unexpected " + event.type + " after ended");
|
||||
}
|
||||
} else {
|
||||
info(event.target.currentSrc + " got " + event.type);
|
||||
var v = event.target;
|
||||
++v.counter[event.type];
|
||||
if (v.counter["ended"] > 0) {
|
||||
is(v.counter[event.type], 0, v._name + " got unexpected " + event.type + " after ended");
|
||||
}
|
||||
}
|
||||
|
||||
@ -71,14 +67,15 @@ function startTest(test, token) {
|
||||
manager.started(token);
|
||||
v.src = test.name;
|
||||
v._name = test.name;
|
||||
v._timeupdateCount = 0;
|
||||
v._finished = false;
|
||||
v.gotEnded = 0;
|
||||
|
||||
// Keep how many events received for each event type.
|
||||
v.counter = {};
|
||||
eventsToLog.forEach(function(e) {
|
||||
v.addEventListener(e, logEvent, false);
|
||||
v.counter[e] = 0;
|
||||
});
|
||||
v.addEventListener("ended", ended, false);
|
||||
v.addEventListener("timeupdate", timeupdate, false);
|
||||
for (var i = 0; i < eventsToLog.length; ++i) {
|
||||
v.addEventListener(eventsToLog[i], logEvent, false);
|
||||
}
|
||||
v.counter["ended"] = 0;
|
||||
document.body.appendChild(v);
|
||||
v.play();
|
||||
}
|
||||
|
@ -411,7 +411,8 @@ PicoCallbackRunnable::OnCancel()
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(nsPicoService)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISpeechService)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISpeechService)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIObserver)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_ADDREF(nsPicoService)
|
||||
@ -427,10 +428,6 @@ nsPicoService::nsPicoService()
|
||||
, mTaResource(nullptr)
|
||||
, mPicoMemArea(nullptr)
|
||||
{
|
||||
DebugOnly<nsresult> rv = NS_NewNamedThread("Pico Worker", getter_AddRefs(mThread));
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
rv = mThread->Dispatch(NS_NewRunnableMethod(this, &nsPicoService::Init), NS_DISPATCH_NORMAL);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
}
|
||||
|
||||
nsPicoService::~nsPicoService()
|
||||
@ -447,6 +444,20 @@ nsPicoService::~nsPicoService()
|
||||
UnloadEngine();
|
||||
}
|
||||
|
||||
// nsIObserver
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPicoService::Observe(nsISupports* aSubject, const char* aTopic,
|
||||
const char16_t* aData)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
NS_ENSURE_TRUE(!strcmp(aTopic, "profile-after-change"), NS_ERROR_UNEXPECTED);
|
||||
|
||||
DebugOnly<nsresult> rv = NS_NewNamedThread("Pico Worker", getter_AddRefs(mThread));
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
return mThread->Dispatch(
|
||||
NS_NewRunnableMethod(this, &nsPicoService::Init), NS_DISPATCH_NORMAL);
|
||||
}
|
||||
// nsISpeechService
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIThread.h"
|
||||
#include "nsISpeechService.h"
|
||||
#include "nsRefPtrHashtable.h"
|
||||
@ -26,7 +27,8 @@ typedef void* pico_System;
|
||||
typedef void* pico_Resource;
|
||||
typedef void* pico_Engine;
|
||||
|
||||
class nsPicoService : public nsISpeechService
|
||||
class nsPicoService : public nsIObserver,
|
||||
public nsISpeechService
|
||||
{
|
||||
friend class PicoCallbackRunnable;
|
||||
friend class PicoInitRunnable;
|
||||
@ -34,6 +36,7 @@ class nsPicoService : public nsISpeechService
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSISPEECHSERVICE
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
nsPicoService();
|
||||
|
||||
|
@ -2702,7 +2702,6 @@ XULDocument::LoadOverlayInternal(nsIURI* aURI, bool aIsDynamic,
|
||||
NodePrincipal(),
|
||||
nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL,
|
||||
nsIContentPolicy::TYPE_OTHER,
|
||||
nullptr, // aChannelPolicy
|
||||
group);
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
|
@ -67,7 +67,7 @@ static RedirEntry kRedirMap[] = {
|
||||
nsIAboutModule::ALLOW_SCRIPT },
|
||||
{ "networking", "chrome://global/content/aboutNetworking.xhtml",
|
||||
nsIAboutModule::ALLOW_SCRIPT },
|
||||
{ "webrtc", "chrome://global/content/aboutWebrtc.xhtml",
|
||||
{ "webrtc", "chrome://global/content/aboutwebrtc/aboutWebrtc.xhtml",
|
||||
nsIAboutModule::ALLOW_SCRIPT },
|
||||
// about:srcdoc is unresolvable by specification. It is included here
|
||||
// because the security manager would disallow srcdoc iframes otherwise.
|
||||
|
@ -168,7 +168,6 @@
|
||||
#endif
|
||||
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIChannelPolicy.h"
|
||||
#include "nsIContentSecurityPolicy.h"
|
||||
#include "nsILoadInfo.h"
|
||||
#include "nsSandboxFlags.h"
|
||||
@ -10158,27 +10157,7 @@ nsDocShell::DoURILoad(nsIURI * aURI,
|
||||
loadFlags |= nsIChannel::LOAD_BACKGROUND;
|
||||
}
|
||||
|
||||
// check for Content Security Policy to pass along with the
|
||||
// new channel we are creating
|
||||
nsCOMPtr<nsIChannelPolicy> channelPolicy;
|
||||
if (IsFrame()) {
|
||||
// check the parent docshell for a CSP
|
||||
nsCOMPtr<nsIContentSecurityPolicy> csp;
|
||||
nsCOMPtr<nsIDocShellTreeItem> parentItem;
|
||||
GetSameTypeParent(getter_AddRefs(parentItem));
|
||||
if (parentItem) {
|
||||
nsCOMPtr<nsIDocument> doc = parentItem->GetDocument();
|
||||
if (doc) {
|
||||
rv = doc->NodePrincipal()->GetCsp(getter_AddRefs(csp));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (csp) {
|
||||
channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
|
||||
channelPolicy->SetContentSecurityPolicy(csp);
|
||||
channelPolicy->SetLoadType(nsIContentPolicy::TYPE_SUBDOCUMENT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Only allow view-source scheme in top-level docshells. view-source is
|
||||
// the only scheme to which this applies at the moment due to potential
|
||||
// timing attacks to read data from cross-origin iframes. If this widens
|
||||
@ -10247,7 +10226,6 @@ nsDocShell::DoURILoad(nsIURI * aURI,
|
||||
requestingPrincipal,
|
||||
securityFlags,
|
||||
aContentPolicyType,
|
||||
channelPolicy,
|
||||
nullptr, // loadGroup
|
||||
static_cast<nsIInterfaceRequestor*>(this),
|
||||
loadFlags);
|
||||
|
@ -21,7 +21,9 @@
|
||||
#include "mozilla/WeakPtr.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "GeckoProfiler.h"
|
||||
#ifdef MOZ_ENABLE_PROFILER_SPS
|
||||
#include "ProfilerMarkers.h"
|
||||
#endif
|
||||
|
||||
// Helper Classes
|
||||
#include "nsCOMPtr.h"
|
||||
@ -951,6 +953,8 @@ private:
|
||||
|
||||
// Storing profile timeline markers and if/when recording started
|
||||
mozilla::TimeStamp mProfileTimelineStartTime;
|
||||
|
||||
#ifdef MOZ_ENABLE_PROFILER_SPS
|
||||
struct InternalProfileTimelineMarker
|
||||
{
|
||||
InternalProfileTimelineMarker(const char* aName,
|
||||
@ -971,6 +975,7 @@ private:
|
||||
float mTime;
|
||||
};
|
||||
nsTArray<InternalProfileTimelineMarker*> mProfileTimelineMarkers;
|
||||
#endif
|
||||
|
||||
// Get the elapsed time (in millis) since the profile timeline recording
|
||||
// started
|
||||
|
@ -131,9 +131,6 @@ this.DOMApplicationRegistry = {
|
||||
APPS_IPC_MSG_NAMES.forEach((aMsgName) => {
|
||||
this.cpmm.removeMessageListener(aMsgName, this);
|
||||
});
|
||||
|
||||
this.cpmm.sendAsyncMessage("Webapps:UnregisterForMessages",
|
||||
APPS_IPC_MSG_NAMES)
|
||||
},
|
||||
|
||||
receiveMessage: function receiveMessage(aMessage) {
|
||||
|
@ -67,7 +67,6 @@
|
||||
#include "mozIApplication.h"
|
||||
#include "WidgetUtils.h"
|
||||
#include "mozIThirdPartyUtil.h"
|
||||
#include "nsChannelPolicy.h"
|
||||
|
||||
#ifdef MOZ_MEDIA_NAVIGATOR
|
||||
#include "MediaManager.h"
|
||||
@ -1056,26 +1055,11 @@ Navigator::SendBeacon(const nsAString& aUrl,
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
nsCOMPtr<nsIChannelPolicy> channelPolicy;
|
||||
nsCOMPtr<nsIContentSecurityPolicy> csp;
|
||||
rv = principal->GetCsp(getter_AddRefs(csp));
|
||||
if (NS_FAILED(rv)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (csp) {
|
||||
channelPolicy = do_CreateInstance(NSCHANNELPOLICY_CONTRACTID);
|
||||
channelPolicy->SetContentSecurityPolicy(csp);
|
||||
channelPolicy->SetLoadType(nsIContentPolicy::TYPE_BEACON);
|
||||
}
|
||||
|
||||
rv = NS_NewChannel(getter_AddRefs(channel),
|
||||
uri,
|
||||
doc,
|
||||
nsILoadInfo::SEC_NORMAL,
|
||||
nsIContentPolicy::TYPE_BEACON,
|
||||
channelPolicy);
|
||||
nsIContentPolicy::TYPE_BEACON);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
aRv.Throw(rv);
|
||||
|
@ -75,7 +75,7 @@ public:
|
||||
|
||||
void Delete(const nsAString& aName);
|
||||
|
||||
void Stringify(nsString& aRetval)
|
||||
void Stringify(nsString& aRetval) const
|
||||
{
|
||||
Serialize(aRetval);
|
||||
}
|
||||
|
@ -62,3 +62,4 @@ MSG_DEF(MSG_PERMISSION_DENIED_TO_PASS_ARG, 1, "Permission denied to pass cross-o
|
||||
MSG_DEF(MSG_MISSING_REQUIRED_DICTIONARY_MEMBER, 1, "Missing required {0}.")
|
||||
MSG_DEF(MSG_INVALID_REQUEST_METHOD, 1, "Invalid request method {0}.")
|
||||
MSG_DEF(MSG_REQUEST_BODY_CONSUMED_ERROR, 0, "Request body has already been consumed.")
|
||||
MSG_DEF(MSG_RESPONSE_INVALID_STATUSTEXT_ERROR, 0, "Response statusText may not contain newline or carriage return.")
|
||||
|
@ -83,6 +83,7 @@ let SSL_ERROR_BAD_CERT_DOMAIN = (SSL_ERROR_BASE + 12);
|
||||
|
||||
let MOZILLA_PKIX_ERROR_BASE = Ci.nsINSSErrorsService.MOZILLA_PKIX_ERROR_BASE;
|
||||
let MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY = (MOZILLA_PKIX_ERROR_BASE + 1);
|
||||
let MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA = (MOZILLA_PKIX_ERROR_BASE + 3);
|
||||
|
||||
function getErrorClass(errorCode) {
|
||||
let NSPRCode = -1 * NS_ERROR_GET_CODE(errorCode);
|
||||
@ -96,6 +97,7 @@ function getErrorClass(errorCode) {
|
||||
case SEC_ERROR_EXPIRED_CERTIFICATE:
|
||||
case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED:
|
||||
case MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY:
|
||||
case MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA:
|
||||
return Ci.nsINSSErrorsService.ERROR_CLASS_BAD_CERT;
|
||||
default:
|
||||
return Ci.nsINSSErrorsService.ERROR_CLASS_SSL_PROTOCOL;
|
||||
|
@ -1022,8 +1022,10 @@ CanvasRenderingContext2D::Redraw(const mgfx::Rect &r)
|
||||
void
|
||||
CanvasRenderingContext2D::DidRefresh()
|
||||
{
|
||||
SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
|
||||
if (glue) {
|
||||
if (IsTargetValid() && SkiaGLTex()) {
|
||||
SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
|
||||
MOZ_ASSERT(glue);
|
||||
|
||||
auto gl = glue->GetGLContext();
|
||||
gl->FlushIfHeavyGLCallsSinceLastFlush();
|
||||
}
|
||||
@ -4823,6 +4825,14 @@ CanvasRenderingContext2D::CreateImageData(JSContext* cx,
|
||||
|
||||
static uint8_t g2DContextLayerUserData;
|
||||
|
||||
|
||||
uint32_t
|
||||
CanvasRenderingContext2D::SkiaGLTex() const
|
||||
{
|
||||
MOZ_ASSERT(IsTargetValid());
|
||||
return (uint32_t)(uintptr_t)mTarget->GetNativeSurface(NativeSurfaceType::OPENGL_TEXTURE);
|
||||
}
|
||||
|
||||
already_AddRefed<CanvasLayer>
|
||||
CanvasRenderingContext2D::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
|
||||
CanvasLayer *aOldLayer,
|
||||
@ -4854,9 +4864,11 @@ CanvasRenderingContext2D::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
|
||||
|
||||
CanvasLayer::Data data;
|
||||
|
||||
SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
|
||||
GLuint skiaGLTex = (GLuint)(uintptr_t)mTarget->GetNativeSurface(NativeSurfaceType::OPENGL_TEXTURE);
|
||||
if (glue && skiaGLTex) {
|
||||
GLuint skiaGLTex = SkiaGLTex();
|
||||
if (skiaGLTex) {
|
||||
SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
|
||||
MOZ_ASSERT(glue);
|
||||
|
||||
data.mGLContext = glue->GetGLContext();
|
||||
data.mFrontbufferGLTex = skiaGLTex;
|
||||
} else {
|
||||
@ -4898,11 +4910,14 @@ CanvasRenderingContext2D::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
|
||||
data.mSize = nsIntSize(mWidth, mHeight);
|
||||
data.mHasAlpha = !mOpaque;
|
||||
|
||||
SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
|
||||
GLuint skiaGLTex = (GLuint)(uintptr_t)mTarget->GetNativeSurface(NativeSurfaceType::OPENGL_TEXTURE);
|
||||
if (glue && skiaGLTex) {
|
||||
GLuint skiaGLTex = SkiaGLTex();
|
||||
if (skiaGLTex) {
|
||||
canvasLayer->SetPreTransactionCallback(
|
||||
CanvasRenderingContext2DUserData::PreTransactionCallback, userData);
|
||||
|
||||
SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
|
||||
MOZ_ASSERT(glue);
|
||||
|
||||
data.mGLContext = glue->GetGLContext();
|
||||
data.mFrontbufferGLTex = skiaGLTex;
|
||||
} else {
|
||||
|
@ -698,7 +698,9 @@ protected:
|
||||
/**
|
||||
* Check if the target is valid after calling EnsureTarget.
|
||||
*/
|
||||
bool IsTargetValid() { return mTarget != sErrorTarget && mTarget != nullptr; }
|
||||
bool IsTargetValid() const {
|
||||
return mTarget != sErrorTarget && mTarget != nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the surface format this canvas should be allocated using. Takes
|
||||
@ -764,6 +766,8 @@ protected:
|
||||
// sErrorTarget.
|
||||
mozilla::RefPtr<mozilla::gfx::DrawTarget> mTarget;
|
||||
|
||||
uint32_t SkiaGLTex() const;
|
||||
|
||||
/**
|
||||
* Flag to avoid duplicate calls to InvalidateFrame. Set to true whenever
|
||||
* Redraw is called, reset to false when Render is called.
|
||||
|
@ -351,6 +351,8 @@ WebGL2Context::GetTexParameterInternal(const TexTarget& target, GLenum pname)
|
||||
{
|
||||
switch (pname) {
|
||||
case LOCAL_GL_TEXTURE_IMMUTABLE_FORMAT:
|
||||
case LOCAL_GL_TEXTURE_BASE_LEVEL:
|
||||
case LOCAL_GL_TEXTURE_MAX_LEVEL:
|
||||
{
|
||||
GLint i = 0;
|
||||
gl->fGetTexParameteriv(target.get(), pname, &i);
|
||||
|
@ -922,7 +922,7 @@ WebGLContext::GenerateMipmap(GLenum rawTarget)
|
||||
const TexImageTarget imageTarget = (target == LOCAL_GL_TEXTURE_2D)
|
||||
? LOCAL_GL_TEXTURE_2D
|
||||
: LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X;
|
||||
if (!tex->HasImageInfoAt(imageTarget, 0))
|
||||
if (!tex->HasImageInfoAt(imageTarget, tex->GetBaseMipmapLevel()))
|
||||
{
|
||||
return ErrorInvalidOperation("generateMipmap: Level zero of texture is not defined.");
|
||||
}
|
||||
@ -1510,6 +1510,19 @@ void WebGLContext::TexParameter_base(GLenum rawTarget, GLenum pname,
|
||||
bool paramValueInvalid = false;
|
||||
|
||||
switch (pname) {
|
||||
case LOCAL_GL_TEXTURE_BASE_LEVEL:
|
||||
case LOCAL_GL_TEXTURE_MAX_LEVEL:
|
||||
if (!IsWebGL2())
|
||||
return ErrorInvalidEnumInfo("texParameter: pname", pname);
|
||||
if (intParam < 0) {
|
||||
paramValueInvalid = true;
|
||||
break;
|
||||
}
|
||||
if (pname == LOCAL_GL_TEXTURE_BASE_LEVEL)
|
||||
tex->SetBaseMipmapLevel(intParam);
|
||||
else
|
||||
tex->SetMaxMipmapLevel(intParam);
|
||||
break;
|
||||
case LOCAL_GL_TEXTURE_MIN_FILTER:
|
||||
switch (intParam) {
|
||||
case LOCAL_GL_NEAREST:
|
||||
|
@ -186,6 +186,10 @@ WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
|
||||
gl->fGetIntegerv(pname, &val);
|
||||
return JS::NumberValue(uint32_t(val));
|
||||
}
|
||||
|
||||
case LOCAL_GL_TEXTURE_BINDING_3D: {
|
||||
return WebGLObjectAsJSValue(cx, mBound3DTextures[mActiveTexture].get(), rv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -219,6 +219,13 @@ bool WebGLContext::ValidateTextureTargetEnum(GLenum target, const char *info)
|
||||
case LOCAL_GL_TEXTURE_2D:
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP:
|
||||
return true;
|
||||
case LOCAL_GL_TEXTURE_3D: {
|
||||
const bool isValid = IsWebGL2();
|
||||
if (!isValid) {
|
||||
ErrorInvalidEnumInfo(info, target);
|
||||
}
|
||||
return isValid;
|
||||
}
|
||||
default:
|
||||
ErrorInvalidEnumInfo(info, target);
|
||||
return false;
|
||||
|
@ -33,6 +33,8 @@ WebGLTexture::WebGLTexture(WebGLContext *context)
|
||||
, mMaxLevelWithCustomImages(0)
|
||||
, mHaveGeneratedMipmap(false)
|
||||
, mImmutable(false)
|
||||
, mBaseMipmapLevel(0)
|
||||
, mMaxMipmapLevel(1000)
|
||||
, mFakeBlackStatus(WebGLTextureFakeBlackStatus::IncompleteTexture)
|
||||
{
|
||||
mContext->MakeContextCurrent();
|
||||
@ -62,22 +64,8 @@ WebGLTexture::MemoryUsage() const {
|
||||
return 0;
|
||||
size_t result = 0;
|
||||
for(size_t face = 0; face < mFacesCount; face++) {
|
||||
if (mHaveGeneratedMipmap) {
|
||||
size_t level0MemoryUsage = ImageInfoAtFace(face, 0).MemoryUsage();
|
||||
// Each mipmap level is 1/(2^d) the size of the previous level,
|
||||
// where d is 2 or 3 depending on whether the images are 2D or 3D
|
||||
// 1 + x + x^2 + ... = 1/(1-x)
|
||||
// for x = 1/(2^2), we get 1/(1-1/4) = 4/3
|
||||
// for x = 1/(2^3), we get 1/(1-1/8) = 8/7
|
||||
size_t allLevelsMemoryUsage =
|
||||
mTarget == LOCAL_GL_TEXTURE_3D
|
||||
? level0MemoryUsage * 8 / 7
|
||||
: level0MemoryUsage * 4 / 3;
|
||||
result += allLevelsMemoryUsage;
|
||||
} else {
|
||||
for(size_t level = 0; level <= mMaxLevelWithCustomImages; level++)
|
||||
result += ImageInfoAtFace(face, level).MemoryUsage();
|
||||
}
|
||||
for(size_t level = 0; level <= mMaxLevelWithCustomImages; level++)
|
||||
result += ImageInfoAtFace(face, level).MemoryUsage();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -88,15 +76,24 @@ WebGLTexture::DoesMipmapHaveAllLevelsConsistentlyDefined(TexImageTarget texImage
|
||||
if (mHaveGeneratedMipmap)
|
||||
return true;
|
||||
|
||||
if (GetMaxMipmapLevel() < GetBaseMipmapLevel())
|
||||
return false;
|
||||
|
||||
// We want a copy here so we can modify it temporarily.
|
||||
ImageInfo expected = ImageInfoAt(texImageTarget, 0);
|
||||
ImageInfo expected = ImageInfoAt(texImageTarget, GetBaseMipmapLevel());
|
||||
|
||||
// checks if custom level>0 images are all defined up to the highest level defined
|
||||
// and have the expected dimensions
|
||||
for (size_t level = 0; level <= mMaxLevelWithCustomImages; ++level) {
|
||||
for (size_t level = GetBaseMipmapLevel(); level <= GetMaxMipmapLevel(); ++level) {
|
||||
const ImageInfo& actual = ImageInfoAt(texImageTarget, level);
|
||||
if (actual != expected)
|
||||
return false;
|
||||
|
||||
// Check the raw value here, not the clamped one, since we don't want
|
||||
// to terminate early if there aren't enough levels defined.
|
||||
if (level == mMaxMipmapLevel)
|
||||
return true;
|
||||
|
||||
expected.mWidth = std::max(1, expected.mWidth / 2);
|
||||
expected.mHeight = std::max(1, expected.mHeight / 2);
|
||||
expected.mDepth = std::max(1, expected.mDepth / 2);
|
||||
@ -185,7 +182,7 @@ WebGLTexture::SetCustomMipmap() {
|
||||
|
||||
// since we were in GeneratedMipmap mode, we know that the level 0 images all have the same info,
|
||||
// and are power-of-two.
|
||||
ImageInfo imageInfo = ImageInfoAtFace(0, 0);
|
||||
ImageInfo imageInfo = ImageInfoAtFace(0, GetBaseMipmapLevel());
|
||||
NS_ASSERTION(mContext->IsWebGL2() || imageInfo.IsPowerOfTwo(),
|
||||
"this texture is NPOT, so how could GenerateMipmap() ever accept it?");
|
||||
|
||||
@ -198,7 +195,7 @@ WebGLTexture::SetCustomMipmap() {
|
||||
|
||||
EnsureMaxLevelWithCustomImagesAtLeast(maxLevel);
|
||||
|
||||
for (size_t level = 1; level <= maxLevel; ++level) {
|
||||
for (size_t level = GetBaseMipmapLevel() + 1; level <= GetMaxMipmapLevel(); ++level) {
|
||||
imageInfo.mWidth = std::max(imageInfo.mWidth / 2, 1);
|
||||
imageInfo.mHeight = std::max(imageInfo.mHeight / 2, 1);
|
||||
imageInfo.mDepth = std::max(imageInfo.mDepth / 2, 1);
|
||||
@ -223,7 +220,7 @@ WebGLTexture::IsMipmapComplete() const {
|
||||
MOZ_ASSERT(mTarget == LOCAL_GL_TEXTURE_2D ||
|
||||
mTarget == LOCAL_GL_TEXTURE_3D);
|
||||
|
||||
if (!ImageInfoAtFace(0, 0).IsPositive())
|
||||
if (!ImageInfoAtFace(0, GetBaseMipmapLevel()).IsPositive())
|
||||
return false;
|
||||
if (mHaveGeneratedMipmap)
|
||||
return true;
|
||||
@ -262,7 +259,7 @@ WebGLTexture::ResolvedFakeBlackStatus() {
|
||||
// See 3.8.2 Shader Execution in the OpenGL ES 2.0.24 spec.
|
||||
|
||||
for (size_t face = 0; face < mFacesCount; ++face) {
|
||||
if (ImageInfoAtFace(face, 0).mImageDataStatus == WebGLImageDataStatus::NoImageData) {
|
||||
if (ImageInfoAtFace(face, GetBaseMipmapLevel()).mImageDataStatus == WebGLImageDataStatus::NoImageData) {
|
||||
// In case of undefined texture image, we don't print any message because this is a very common
|
||||
// and often legitimate case (asynchronous texture loading).
|
||||
mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
|
||||
|
@ -213,6 +213,9 @@ protected:
|
||||
bool mHaveGeneratedMipmap; // set by generateMipmap
|
||||
bool mImmutable; // set by texStorage*
|
||||
|
||||
size_t mBaseMipmapLevel; // set by texParameter (defaults to 0)
|
||||
size_t mMaxMipmapLevel; // set by texParameter (defaults to 1000)
|
||||
|
||||
WebGLTextureFakeBlackStatus mFakeBlackStatus;
|
||||
|
||||
void EnsureMaxLevelWithCustomImagesAtLeast(size_t aMaxLevelWithCustomImages) {
|
||||
@ -283,6 +286,17 @@ public:
|
||||
bool IsImmutable() const { return mImmutable; }
|
||||
void SetImmutable() { mImmutable = true; }
|
||||
|
||||
void SetBaseMipmapLevel(unsigned level) { mBaseMipmapLevel = level; }
|
||||
void SetMaxMipmapLevel(unsigned level) { mMaxMipmapLevel = level; }
|
||||
size_t GetBaseMipmapLevel() const {
|
||||
// Clamp to [0, levels - 1]
|
||||
return std::min(mBaseMipmapLevel, mMaxLevelWithCustomImages);
|
||||
}
|
||||
size_t GetMaxMipmapLevel() const {
|
||||
// Clamp to [base, levels - 1]
|
||||
return std::min(mMaxMipmapLevel, mMaxLevelWithCustomImages);
|
||||
}
|
||||
|
||||
size_t MaxLevelWithCustomImages() const { return mMaxLevelWithCustomImages; }
|
||||
|
||||
// Returns the current fake-black-status, except if it was Unknown,
|
||||
|
@ -395,7 +395,12 @@ CryptoKey::PublicKeyFromSpki(CryptoBuffer& aKeyData,
|
||||
}
|
||||
}
|
||||
|
||||
return SECKEY_ExtractPublicKey(spki.get());
|
||||
ScopedSECKEYPublicKey tmp(SECKEY_ExtractPublicKey(spki.get()));
|
||||
if (!tmp.get() || !PublicKeyValid(tmp.get())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return SECKEY_CopyPublicKey(tmp);
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -843,6 +848,10 @@ CryptoKey::PublicKeyFromJwk(const JsonWebKey& aJwk,
|
||||
}
|
||||
key->u.ec.publicValue = *point;
|
||||
|
||||
if (!PublicKeyValid(key)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return SECKEY_CopyPublicKey(key);
|
||||
}
|
||||
|
||||
@ -881,6 +890,26 @@ CryptoKey::PublicKeyToJwk(SECKEYPublicKey* aPubKey,
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CryptoKey::PublicKeyValid(SECKEYPublicKey* aPubKey)
|
||||
{
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
if (!slot.get()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// This assumes that NSS checks the validity of a public key when
|
||||
// it is imported into a PKCS#11 module, and returns CK_INVALID_HANDLE
|
||||
// if it is invalid.
|
||||
CK_OBJECT_HANDLE id = PK11_ImportPublicKey(slot, aPubKey, PR_FALSE);
|
||||
if (id == CK_INVALID_HANDLE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SECStatus rv = PK11_DestroyObject(slot, id);
|
||||
return (rv == SECSuccess);
|
||||
}
|
||||
|
||||
bool
|
||||
CryptoKey::WriteStructuredClone(JSStructuredCloneWriter* aWriter) const
|
||||
{
|
||||
|
@ -171,6 +171,8 @@ public:
|
||||
JsonWebKey& aRetVal,
|
||||
const nsNSSShutDownPreventionLock& /*proofOfLock*/);
|
||||
|
||||
static bool PublicKeyValid(SECKEYPublicKey* aPubKey);
|
||||
|
||||
// Structured clone methods use these to clone keys
|
||||
bool WriteStructuredClone(JSStructuredCloneWriter* aWriter) const;
|
||||
bool ReadStructuredClone(JSStructuredCloneReader* aReader);
|
||||
|
@ -27,6 +27,7 @@
|
||||
#define WEBCRYPTO_ALG_RSASSA_PKCS1 "RSASSA-PKCS1-v1_5"
|
||||
#define WEBCRYPTO_ALG_RSA_OAEP "RSA-OAEP"
|
||||
#define WEBCRYPTO_ALG_ECDH "ECDH"
|
||||
#define WEBCRYPTO_ALG_ECDSA "ECDSA"
|
||||
|
||||
// WebCrypto key formats
|
||||
#define WEBCRYPTO_KEY_FORMAT_RAW "raw"
|
||||
@ -84,6 +85,9 @@
|
||||
#define JWK_ALG_RSA_OAEP_256 "RSA-OAEP-256"
|
||||
#define JWK_ALG_RSA_OAEP_384 "RSA-OAEP-384"
|
||||
#define JWK_ALG_RSA_OAEP_512 "RSA-OAEP-512"
|
||||
#define JWK_ALG_ECDSA_P_256 "ES256"
|
||||
#define JWK_ALG_ECDSA_P_384 "ES384"
|
||||
#define JWK_ALG_ECDSA_P_521 "ES521"
|
||||
|
||||
// JWK usages
|
||||
#define JWK_USE_ENC "enc"
|
||||
@ -225,6 +229,8 @@ NormalizeToken(const nsString& aName, nsString& aDest)
|
||||
aDest.AssignLiteral(WEBCRYPTO_ALG_RSA_OAEP);
|
||||
} else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_ECDH)) {
|
||||
aDest.AssignLiteral(WEBCRYPTO_ALG_ECDH);
|
||||
} else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_ECDSA)) {
|
||||
aDest.AssignLiteral(WEBCRYPTO_ALG_ECDSA);
|
||||
// Named curve values
|
||||
} else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_NAMED_CURVE_P256)) {
|
||||
aDest.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P256);
|
||||
|
@ -66,7 +66,8 @@ enum TelemetryAlgorithm {
|
||||
// Later additions
|
||||
TA_AES_KW = 19,
|
||||
TA_ECDH = 20,
|
||||
TA_PBKDF2 = 21
|
||||
TA_PBKDF2 = 21,
|
||||
TA_ECDSA = 22,
|
||||
};
|
||||
|
||||
// Convenience functions for extracting / converting information
|
||||
@ -782,10 +783,9 @@ public:
|
||||
mMgfMechanism = CKG_MGF1_SHA384; break;
|
||||
case CKM_SHA512:
|
||||
mMgfMechanism = CKG_MGF1_SHA512; break;
|
||||
default: {
|
||||
default:
|
||||
mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -955,49 +955,97 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
class RsassaPkcs1Task : public WebCryptoTask
|
||||
class AsymmetricSignVerifyTask : public WebCryptoTask
|
||||
{
|
||||
public:
|
||||
RsassaPkcs1Task(JSContext* aCx, const ObjectOrString& aAlgorithm,
|
||||
CryptoKey& aKey,
|
||||
const CryptoOperationData& aSignature,
|
||||
const CryptoOperationData& aData,
|
||||
bool aSign)
|
||||
AsymmetricSignVerifyTask(JSContext* aCx,
|
||||
const ObjectOrString& aAlgorithm,
|
||||
CryptoKey& aKey,
|
||||
const CryptoOperationData& aSignature,
|
||||
const CryptoOperationData& aData,
|
||||
bool aSign)
|
||||
: mOidTag(SEC_OID_UNKNOWN)
|
||||
, mPrivKey(aKey.GetPrivateKey())
|
||||
, mPubKey(aKey.GetPublicKey())
|
||||
, mSign(aSign)
|
||||
, mVerified(false)
|
||||
, mEcdsa(false)
|
||||
{
|
||||
Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_RSASSA_PKCS1);
|
||||
|
||||
CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_RSASSA_PKCS1);
|
||||
|
||||
ATTEMPT_BUFFER_INIT(mData, aData);
|
||||
if (!aSign) {
|
||||
ATTEMPT_BUFFER_INIT(mSignature, aSignature);
|
||||
}
|
||||
|
||||
// Look up the SECOidTag based on the KeyAlgorithm
|
||||
// static_cast is safe because we only get here if the algorithm name
|
||||
// is RSASSA-PKCS1-v1_5, and that only happens if we've constructed
|
||||
// an RsaHashedKeyAlgorithm
|
||||
CK_MECHANISM_TYPE mech;
|
||||
mech = KeyAlgorithmProxy::GetMechanism(aKey.Algorithm().mRsa.mHash);
|
||||
nsString algName;
|
||||
mEarlyRv = GetAlgorithmName(aCx, aAlgorithm, algName);
|
||||
if (NS_FAILED(mEarlyRv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (mech) {
|
||||
case CKM_SHA_1:
|
||||
mOidTag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; break;
|
||||
case CKM_SHA256:
|
||||
mOidTag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION; break;
|
||||
case CKM_SHA384:
|
||||
mOidTag = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION; break;
|
||||
case CKM_SHA512:
|
||||
mOidTag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION; break;
|
||||
default: {
|
||||
mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
// Look up the SECOidTag
|
||||
if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1)) {
|
||||
mEcdsa = false;
|
||||
Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_RSASSA_PKCS1);
|
||||
CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_RSASSA_PKCS1);
|
||||
|
||||
// For RSA, the hash name comes from the key algorithm
|
||||
nsString hashName = aKey.Algorithm().mRsa.mHash.mName;
|
||||
switch (MapAlgorithmNameToMechanism(hashName)) {
|
||||
case CKM_SHA_1:
|
||||
mOidTag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; break;
|
||||
case CKM_SHA256:
|
||||
mOidTag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION; break;
|
||||
case CKM_SHA384:
|
||||
mOidTag = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION; break;
|
||||
case CKM_SHA512:
|
||||
mOidTag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION; break;
|
||||
default:
|
||||
mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
return;
|
||||
}
|
||||
} else if (algName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA)) {
|
||||
mEcdsa = true;
|
||||
Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_ECDSA);
|
||||
CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_ECDSA);
|
||||
|
||||
// For ECDSA, the hash name comes from the algorithm parameter
|
||||
RootedDictionary<EcdsaParams> params(aCx);
|
||||
mEarlyRv = Coerce(aCx, params, aAlgorithm);
|
||||
if (NS_FAILED(mEarlyRv)) {
|
||||
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
|
||||
return;
|
||||
}
|
||||
|
||||
nsString hashName;
|
||||
mEarlyRv = GetAlgorithmName(aCx, params.mHash, hashName);
|
||||
if (NS_FAILED(mEarlyRv)) {
|
||||
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
|
||||
return;
|
||||
}
|
||||
|
||||
CK_MECHANISM_TYPE hashMechanism = MapAlgorithmNameToMechanism(hashName);
|
||||
if (hashMechanism == UNKNOWN_CK_MECHANISM) {
|
||||
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (hashMechanism) {
|
||||
case CKM_SHA_1:
|
||||
mOidTag = SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE; break;
|
||||
case CKM_SHA256:
|
||||
mOidTag = SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE; break;
|
||||
case CKM_SHA384:
|
||||
mOidTag = SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE; break;
|
||||
case CKM_SHA512:
|
||||
mOidTag = SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE; break;
|
||||
default:
|
||||
mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// This shouldn't happen; CreateSignVerifyTask shouldn't create
|
||||
// one of these unless it's for the above algorithms.
|
||||
MOZ_ASSERT(false);
|
||||
}
|
||||
|
||||
// Check that we have the appropriate key
|
||||
@ -1015,6 +1063,7 @@ private:
|
||||
CryptoBuffer mData;
|
||||
bool mSign;
|
||||
bool mVerified;
|
||||
bool mEcdsa;
|
||||
|
||||
virtual nsresult DoCrypto() MOZ_OVERRIDE
|
||||
{
|
||||
@ -1022,44 +1071,53 @@ private:
|
||||
if (mSign) {
|
||||
ScopedSECItem signature((SECItem*) PORT_Alloc(sizeof(SECItem)));
|
||||
ScopedSGNContext ctx(SGN_NewContext(mOidTag, mPrivKey));
|
||||
if (!ctx) {
|
||||
if (!signature.get() || !ctx.get()) {
|
||||
return NS_ERROR_DOM_OPERATION_ERR;
|
||||
}
|
||||
|
||||
rv = MapSECStatus(SGN_Begin(ctx));
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
|
||||
rv = MapSECStatus(SEC_SignData(signature, mData.Elements(),
|
||||
mData.Length(), mPrivKey, mOidTag));
|
||||
|
||||
rv = MapSECStatus(SGN_Update(ctx, mData.Elements(), mData.Length()));
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
|
||||
|
||||
rv = MapSECStatus(SGN_End(ctx, signature));
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
|
||||
|
||||
ATTEMPT_BUFFER_ASSIGN(mSignature, signature);
|
||||
} else {
|
||||
ScopedSECItem signature(mSignature.ToSECItem());
|
||||
if (!signature) {
|
||||
return NS_ERROR_DOM_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
ScopedVFYContext ctx(VFY_CreateContext(mPubKey, signature,
|
||||
mOidTag, nullptr));
|
||||
if (!ctx) {
|
||||
int err = PORT_GetError();
|
||||
if (err == SEC_ERROR_BAD_SIGNATURE) {
|
||||
mVerified = false;
|
||||
return NS_OK;
|
||||
if (mEcdsa) {
|
||||
// DER-decode the signature
|
||||
int signatureLength = PK11_SignatureLen(mPrivKey);
|
||||
ScopedSECItem rawSignature(DSAU_DecodeDerSigToLen(signature.get(),
|
||||
signatureLength));
|
||||
if (!rawSignature.get()) {
|
||||
return NS_ERROR_DOM_OPERATION_ERR;
|
||||
}
|
||||
return NS_ERROR_DOM_OPERATION_ERR;
|
||||
|
||||
ATTEMPT_BUFFER_ASSIGN(mSignature, rawSignature);
|
||||
} else {
|
||||
ATTEMPT_BUFFER_ASSIGN(mSignature, signature);
|
||||
}
|
||||
|
||||
rv = MapSECStatus(VFY_Begin(ctx));
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
|
||||
} else {
|
||||
ScopedSECItem signature;
|
||||
|
||||
rv = MapSECStatus(VFY_Update(ctx, mData.Elements(), mData.Length()));
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
|
||||
if (mEcdsa) {
|
||||
// DER-encode the signature
|
||||
ScopedSECItem rawSignature(mSignature.ToSECItem());
|
||||
if (!rawSignature.get()) {
|
||||
return NS_ERROR_DOM_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
rv = MapSECStatus(VFY_End(ctx));
|
||||
signature = (SECItem*) PORT_Alloc(sizeof(SECItem));
|
||||
if (!signature.get()) {
|
||||
return NS_ERROR_DOM_UNKNOWN_ERR;
|
||||
}
|
||||
rv = MapSECStatus(DSAU_EncodeDerSigWithLen(signature, rawSignature,
|
||||
rawSignature->len));
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
|
||||
} else {
|
||||
signature = mSignature.ToSECItem();
|
||||
if (!signature) {
|
||||
return NS_ERROR_DOM_UNKNOWN_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
rv = MapSECStatus(VFY_VerifyData(mData.Elements(), mData.Length(),
|
||||
mPubKey, signature, mOidTag, nullptr));
|
||||
mVerified = NS_SUCCEEDED(rv);
|
||||
}
|
||||
|
||||
@ -1661,12 +1719,23 @@ private:
|
||||
|
||||
virtual nsresult AfterCrypto() MOZ_OVERRIDE
|
||||
{
|
||||
// Check permissions for the requested operation
|
||||
if (mKey->GetKeyType() == CryptoKey::PRIVATE &&
|
||||
mKey->HasUsageOtherThan(CryptoKey::DERIVEBITS | CryptoKey::DERIVEKEY)) {
|
||||
return NS_ERROR_DOM_DATA_ERR;
|
||||
uint32_t privateAllowedUsages = 0, publicAllowedUsages = 0;
|
||||
if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_ECDH)) {
|
||||
privateAllowedUsages = CryptoKey::DERIVEBITS | CryptoKey::DERIVEKEY;
|
||||
publicAllowedUsages = CryptoKey::DERIVEBITS | CryptoKey::DERIVEKEY;
|
||||
} else if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA)) {
|
||||
privateAllowedUsages = CryptoKey::SIGN;
|
||||
publicAllowedUsages = CryptoKey::VERIFY;
|
||||
}
|
||||
|
||||
// Check permissions for the requested operation
|
||||
if ((mKey->GetKeyType() == CryptoKey::PRIVATE &&
|
||||
mKey->HasUsageOtherThan(privateAllowedUsages)) ||
|
||||
(mKey->GetKeyType() == CryptoKey::PUBLIC &&
|
||||
mKey->HasUsageOtherThan(publicAllowedUsages))) {
|
||||
return NS_ERROR_DOM_DATA_ERR;
|
||||
}
|
||||
|
||||
mKey->Algorithm().MakeEc(mAlgName, mNamedCurve);
|
||||
|
||||
if (mDataIsJwk && !JwkCompatible(mJwk, mKey)) {
|
||||
@ -1991,7 +2060,8 @@ public:
|
||||
mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
|
||||
return;
|
||||
}
|
||||
} else if (algName.EqualsLiteral(WEBCRYPTO_ALG_ECDH)) {
|
||||
} else if (algName.EqualsLiteral(WEBCRYPTO_ALG_ECDH) ||
|
||||
algName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA)) {
|
||||
RootedDictionary<EcKeyGenParams> params(aCx);
|
||||
mEarlyRv = Coerce(aCx, params, aAlgorithm);
|
||||
if (NS_FAILED(mEarlyRv)) {
|
||||
@ -2014,7 +2084,8 @@ public:
|
||||
}
|
||||
|
||||
// Set key usages.
|
||||
if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1)) {
|
||||
if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1) ||
|
||||
algName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA)) {
|
||||
privateAllowedUsages = CryptoKey::SIGN;
|
||||
publicAllowedUsages = CryptoKey::VERIFY;
|
||||
} else if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) {
|
||||
@ -2048,7 +2119,7 @@ public:
|
||||
}
|
||||
|
||||
// If no usages ended up being allowed, DataError
|
||||
if (!mKeyPair.mPrivateKey.get()->HasAnyUsage() ||
|
||||
if (!mKeyPair.mPublicKey.get()->HasAnyUsage() &&
|
||||
!mKeyPair.mPrivateKey.get()->HasAnyUsage()) {
|
||||
mEarlyRv = NS_ERROR_DOM_DATA_ERR;
|
||||
return;
|
||||
@ -2176,10 +2247,9 @@ public:
|
||||
case CKM_SHA256: mHashOidTag = SEC_OID_HMAC_SHA256; break;
|
||||
case CKM_SHA384: mHashOidTag = SEC_OID_HMAC_SHA384; break;
|
||||
case CKM_SHA512: mHashOidTag = SEC_OID_HMAC_SHA512; break;
|
||||
default: {
|
||||
default:
|
||||
mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ATTEMPT_BUFFER_INIT(mSalt, params.mSalt)
|
||||
@ -2544,8 +2614,10 @@ WebCryptoTask::CreateSignVerifyTask(JSContext* aCx,
|
||||
|
||||
if (algName.EqualsLiteral(WEBCRYPTO_ALG_HMAC)) {
|
||||
return new HmacTask(aCx, aAlgorithm, aKey, aSignature, aData, aSign);
|
||||
} else if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1)) {
|
||||
return new RsassaPkcs1Task(aCx, aAlgorithm, aKey, aSignature, aData, aSign);
|
||||
} else if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1) ||
|
||||
algName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA)) {
|
||||
return new AsymmetricSignVerifyTask(aCx, aAlgorithm, aKey, aSignature,
|
||||
aData, aSign);
|
||||
}
|
||||
|
||||
return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
@ -2618,7 +2690,8 @@ WebCryptoTask::CreateImportKeyTask(JSContext* aCx,
|
||||
algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) {
|
||||
return new ImportRsaKeyTask(aCx, aFormat, aKeyData, aAlgorithm,
|
||||
aExtractable, aKeyUsages);
|
||||
} else if (algName.EqualsLiteral(WEBCRYPTO_ALG_ECDH)) {
|
||||
} else if (algName.EqualsLiteral(WEBCRYPTO_ALG_ECDH) ||
|
||||
algName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA)) {
|
||||
return new ImportEcKeyTask(aCx, aFormat, aKeyData, aAlgorithm,
|
||||
aExtractable, aKeyUsages);
|
||||
} else {
|
||||
@ -2694,7 +2767,8 @@ WebCryptoTask::CreateGenerateKeyTask(JSContext* aCx,
|
||||
return new GenerateSymmetricKeyTask(aCx, aAlgorithm, aExtractable, aKeyUsages);
|
||||
} else if (algName.EqualsASCII(WEBCRYPTO_ALG_RSASSA_PKCS1) ||
|
||||
algName.EqualsASCII(WEBCRYPTO_ALG_RSA_OAEP) ||
|
||||
algName.EqualsASCII(WEBCRYPTO_ALG_ECDH)) {
|
||||
algName.EqualsASCII(WEBCRYPTO_ALG_ECDH) ||
|
||||
algName.EqualsASCII(WEBCRYPTO_ALG_ECDSA)) {
|
||||
return new GenerateAsymmetricKeyTask(aCx, aAlgorithm, aExtractable, aKeyUsages);
|
||||
} else {
|
||||
return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
|
@ -608,4 +608,54 @@ tv = {
|
||||
x: "XOe4bjsyZgQD5jcS7wmY3q4QJ_rsPBvp92-TTf61jpg",
|
||||
}
|
||||
},
|
||||
|
||||
// NIST ECDSA test vectors
|
||||
// http://csrc.nist.gov/groups/STM/cavp/index.html
|
||||
ecdsa_verify: {
|
||||
pub_jwk: {
|
||||
"kty": "EC",
|
||||
"crv": "P-521",
|
||||
|
||||
// 0061387fd6b95914e885f912edfbb5fb274655027f216c4091ca83e19336740fd8
|
||||
// 1aedfe047f51b42bdf68161121013e0d55b117a14e4303f926c8debb77a7fdaad1
|
||||
"x": "AGE4f9a5WRTohfkS7fu1-ydGVQJ_IWxAkcqD4ZM2dA_Y" +
|
||||
"Gu3-BH9RtCvfaBYRIQE-DVWxF6FOQwP5Jsjeu3en_arR",
|
||||
// 00e7d0c75c38626e895ca21526b9f9fdf84dcecb93f2b233390550d2b1463b7ee3
|
||||
// f58df7346435ff0434199583c97c665a97f12f706f2357da4b40288def888e59e6
|
||||
"y": "AOfQx1w4Ym6JXKIVJrn5_fhNzsuT8rIzOQVQ0rFGO37j" +
|
||||
"9Y33NGQ1_wQ0GZWDyXxmWpfxL3BvI1faS0Aoje-Ijlnm",
|
||||
},
|
||||
|
||||
"data": util.hex2abv(
|
||||
"9ecd500c60e701404922e58ab20cc002651fdee7cbc9336adda33e4c1088fab1" +
|
||||
"964ecb7904dc6856865d6c8e15041ccf2d5ac302e99d346ff2f686531d255216" +
|
||||
"78d4fd3f76bbf2c893d246cb4d7693792fe18172108146853103a51f824acc62" +
|
||||
"1cb7311d2463c3361ea707254f2b052bc22cb8012873dcbb95bf1a5cc53ab89f"
|
||||
),
|
||||
"sig": util.hex2abv(
|
||||
"004de826ea704ad10bc0f7538af8a3843f284f55c8b946af9235af5af74f2b76e0" +
|
||||
"99e4bc72fd79d28a380f8d4b4c919ac290d248c37983ba05aea42e2dd79fdd33e8" +
|
||||
"0087488c859a96fea266ea13bf6d114c429b163be97a57559086edb64aed4a1859" +
|
||||
"4b46fb9efc7fd25d8b2de8f09ca0587f54bd287299f47b2ff124aac566e8ee3b43"
|
||||
),
|
||||
|
||||
// Same as "sig", but with the last few octets set to 0
|
||||
"sig_tampered": util.hex2abv(
|
||||
"004de826ea704ad10bc0f7538af8a3843f284f55c8b946af9235af5af74f2b76e0" +
|
||||
"99e4bc72fd79d28a380f8d4b4c919ac290d248c37983ba05aea42e2dd79fdd33e8" +
|
||||
"0087488c859a96fea266ea13bf6d114c429b163be97a57559086edb64aed4a1859" +
|
||||
"4b46fb9efc7fd25d8b2de8f09ca0587f54bd287299f47b2ff124aac56600000000"
|
||||
)
|
||||
},
|
||||
|
||||
ecdsa_bad: {
|
||||
pub_jwk: {
|
||||
"kty": "EC",
|
||||
"crv": "P-521",
|
||||
"x": "BhOH_WuVkU6IX5Eu37tfsnRlUCfyFsQJHKg-GTNnQP2B" +
|
||||
"rt_gR_UbQr32gWESEBPg1VsRehTkMD-SbI3rt3p_2q0B",
|
||||
"y": "AUNouOdGgHsraPNhXNeNdhpGTd15GPyN9R0iWWL98ePc" +
|
||||
"JD4mUQD/DsEzNZ4zLkTdSa/Y5fOP6GEzVzQy0zwC+goD"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1308,6 +1308,32 @@ TestArray.addTest(
|
||||
doCheckRSASSA().then(error(that), complete(that));
|
||||
}
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"Test that we reject generating keys without any usage",
|
||||
function() {
|
||||
var that = this;
|
||||
var alg = {
|
||||
name: "RSA-OAEP",
|
||||
hash: "SHA-256",
|
||||
modulusLength: 2048,
|
||||
publicExponent: new Uint8Array([0x01, 0x00, 0x01])
|
||||
};
|
||||
|
||||
function generateKey(usages) {
|
||||
return crypto.subtle.generateKey(alg, false, usages);
|
||||
}
|
||||
|
||||
generateKey(["encrypt", "decrypt"]).then(function () {
|
||||
return generateKey(["encrypt"]);
|
||||
}).then(function () {
|
||||
return generateKey(["decrypt"]);
|
||||
}).then(function () {
|
||||
return generateKey(["sign"])
|
||||
}, error(that)).then(error(that), complete(that));
|
||||
}
|
||||
);
|
||||
/*]]>*/</script>
|
||||
</head>
|
||||
|
||||
|
162
dom/crypto/test/test_WebCrypto_ECDSA.html
Normal file
162
dom/crypto/test/test_WebCrypto_ECDSA.html
Normal file
@ -0,0 +1,162 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>WebCrypto Test Suite</title>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
|
||||
<link rel="stylesheet" href="./test_WebCrypto.css"/>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
|
||||
<!-- Utilities for manipulating ABVs -->
|
||||
<script src="util.js"></script>
|
||||
|
||||
<!-- A simple wrapper around IndexedDB -->
|
||||
<script src="simpledb.js"></script>
|
||||
|
||||
<!-- Test vectors drawn from the literature -->
|
||||
<script src="./test-vectors.js"></script>
|
||||
|
||||
<!-- General testing framework -->
|
||||
<script src="./test-array.js"></script>
|
||||
|
||||
<script>/*<![CDATA[*/
|
||||
"use strict";
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"Generate an ECDSA key for named curve P-256",
|
||||
function() {
|
||||
var that = this;
|
||||
var alg = { name: "ECDSA", namedCurve: "P-256" };
|
||||
crypto.subtle.generateKey(alg, false, ["sign", "verify"]).then(
|
||||
complete(that, function(x) {
|
||||
return exists(x.publicKey) &&
|
||||
(x.publicKey.algorithm.name == alg.name) &&
|
||||
(x.publicKey.algorithm.namedCurve == alg.namedCurve) &&
|
||||
(x.publicKey.type == "public") &&
|
||||
x.publicKey.extractable &&
|
||||
(x.publicKey.usages.length == 1) &&
|
||||
(x.publicKey.usages[0] == "verify") &&
|
||||
exists(x.privateKey) &&
|
||||
(x.privateKey.algorithm.name == alg.name) &&
|
||||
(x.privateKey.algorithm.namedCurve == alg.namedCurve) &&
|
||||
(x.privateKey.type == "private") &&
|
||||
!x.privateKey.extractable &&
|
||||
(x.privateKey.usages.length == 1) &&
|
||||
(x.privateKey.usages[0] == "sign")
|
||||
}),
|
||||
error(that)
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"ECDSA JWK import and verify a known-good signature",
|
||||
function() {
|
||||
var that = this;
|
||||
var alg = { name: "ECDSA", namedCurve: "P-256", hash: "SHA-256" };
|
||||
|
||||
function doVerify(x) {
|
||||
return crypto.subtle.verify(alg, x, tv.ecdsa_verify.sig, tv.ecdsa_verify.data);
|
||||
}
|
||||
|
||||
crypto.subtle.importKey("jwk", tv.ecdsa_verify.pub_jwk, alg, true, ["verify"])
|
||||
.then(doVerify)
|
||||
.then(complete(that), error(that))
|
||||
}
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"ECDSA JWK import and reject a known-bad signature",
|
||||
function() {
|
||||
var that = this;
|
||||
var alg = { name: "ECDSA", namedCurve: "P-256", hash: "SHA-256" };
|
||||
|
||||
function doVerify(x) {
|
||||
return crypto.subtle.verify(alg, x, tv.ecdsa_verify.sig_tampered,
|
||||
tv.ecdsa_verify.data);
|
||||
}
|
||||
|
||||
crypto.subtle.importKey("jwk", tv.ecdsa_verify.pub_jwk, alg, true, ["verify"])
|
||||
.then(doVerify)
|
||||
.then(complete(that, x => !x), error(that))
|
||||
}
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"ECDSA sign/verify round-trip",
|
||||
function() {
|
||||
var that = this;
|
||||
var alg = { name: "ECDSA", namedCurve: "P-521", hash: "SHA-512" };
|
||||
var pubKey;
|
||||
|
||||
|
||||
function doSign(keyPair) {
|
||||
pubKey = keyPair.publicKey;
|
||||
return crypto.subtle.sign(alg, keyPair.privateKey, tv.ecdsa_verify.data);
|
||||
}
|
||||
function doVerify(sig) {
|
||||
return crypto.subtle.verify(alg, pubKey, sig, tv.ecdsa_verify.data);
|
||||
}
|
||||
|
||||
crypto.subtle.generateKey(alg, true, ["sign", "verify"])
|
||||
.then(doSign)
|
||||
.then(doVerify)
|
||||
.then(complete(that), error(that))
|
||||
}
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"Verify that ECDSA import fails with a known-bad public key",
|
||||
function() {
|
||||
var that = this;
|
||||
var alg = { name: "ECDSA", namedCurve: "P-256", hash: "SHA-256" };
|
||||
|
||||
function doVerify(x) {
|
||||
return crypto.subtle.verify(alg, x, tv.ecdsa_verify.sig, tv.ecdsa_verify.data);
|
||||
}
|
||||
|
||||
crypto.subtle.importKey("jwk", tv.ecdsa_bad.pub_jwk, alg, true, ["verify"])
|
||||
.then(error(that), complete(that))
|
||||
}
|
||||
);
|
||||
|
||||
/*]]>*/</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="content">
|
||||
<div id="head">
|
||||
<b>Web</b>Crypto<br>
|
||||
</div>
|
||||
|
||||
<div id="start" onclick="start();">RUN ALL</div>
|
||||
|
||||
<div id="resultDiv" class="content">
|
||||
Summary:
|
||||
<span class="pass"><span id="passN">0</span> passed, </span>
|
||||
<span class="fail"><span id="failN">0</span> failed, </span>
|
||||
<span class="pending"><span id="pendingN">0</span> pending.</span>
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<table id="results">
|
||||
<tr>
|
||||
<th>Test</th>
|
||||
<th>Result</th>
|
||||
<th>Time</th>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="foot"></div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -76,6 +76,7 @@ Event::ConstructorInit(EventTarget* aOwner,
|
||||
}
|
||||
|
||||
mPrivateDataDuplicated = false;
|
||||
mWantsPopupControlCheck = false;
|
||||
|
||||
if (aEvent) {
|
||||
mEvent = aEvent;
|
||||
@ -655,12 +656,20 @@ PopupAllowedForEvent(const char *eventName)
|
||||
|
||||
// static
|
||||
PopupControlState
|
||||
Event::GetEventPopupControlState(WidgetEvent* aEvent)
|
||||
Event::GetEventPopupControlState(WidgetEvent* aEvent, nsIDOMEvent* aDOMEvent)
|
||||
{
|
||||
// generally if an event handler is running, new windows are disallowed.
|
||||
// check for exceptions:
|
||||
PopupControlState abuse = openAbused;
|
||||
|
||||
if (aDOMEvent && aDOMEvent->InternalDOMEvent()->GetWantsPopupControlCheck()) {
|
||||
nsAutoString type;
|
||||
aDOMEvent->GetType(type);
|
||||
if (PopupAllowedForEvent(NS_ConvertUTF16toUTF8(type).get())) {
|
||||
return openAllowed;
|
||||
}
|
||||
}
|
||||
|
||||
switch(aEvent->mClass) {
|
||||
case eBasicEventClass:
|
||||
// For these following events only allow popups if they're
|
||||
|
@ -30,6 +30,7 @@ namespace dom {
|
||||
class EventTarget;
|
||||
class ErrorEvent;
|
||||
class ProgressEvent;
|
||||
class WantsPopupControlCheck;
|
||||
|
||||
// Dummy class so we can cast through it to get from nsISupports to
|
||||
// Event subclasses with only two non-ambiguous static casts.
|
||||
@ -113,7 +114,8 @@ public:
|
||||
// Returns true if the event should be trusted.
|
||||
bool Init(EventTarget* aGlobal);
|
||||
|
||||
static PopupControlState GetEventPopupControlState(WidgetEvent* aEvent);
|
||||
static PopupControlState GetEventPopupControlState(WidgetEvent* aEvent,
|
||||
nsIDOMEvent* aDOMEvent = nullptr);
|
||||
|
||||
static void PopupAllowedEventsChanged();
|
||||
|
||||
@ -235,6 +237,17 @@ protected:
|
||||
void SetEventType(const nsAString& aEventTypeArg);
|
||||
already_AddRefed<nsIContent> GetTargetFromFrame();
|
||||
|
||||
friend class WantsPopupControlCheck;
|
||||
void SetWantsPopupControlCheck(bool aCheck)
|
||||
{
|
||||
mWantsPopupControlCheck = aCheck;
|
||||
}
|
||||
|
||||
bool GetWantsPopupControlCheck()
|
||||
{
|
||||
return IsTrusted() && mWantsPopupControlCheck;
|
||||
}
|
||||
|
||||
/**
|
||||
* IsChrome() returns true if aCx is chrome context or the event is created
|
||||
* in chrome's thread. Otherwise, false.
|
||||
@ -248,6 +261,28 @@ protected:
|
||||
bool mEventIsInternal;
|
||||
bool mPrivateDataDuplicated;
|
||||
bool mIsMainThreadEvent;
|
||||
// True when popup control check should rely on event.type, not
|
||||
// WidgetEvent.message.
|
||||
bool mWantsPopupControlCheck;
|
||||
};
|
||||
|
||||
class MOZ_STACK_CLASS WantsPopupControlCheck
|
||||
{
|
||||
public:
|
||||
WantsPopupControlCheck(nsIDOMEvent* aEvent) : mEvent(aEvent->InternalDOMEvent())
|
||||
{
|
||||
mOriginalWantsPopupControlCheck = mEvent->GetWantsPopupControlCheck();
|
||||
mEvent->SetWantsPopupControlCheck(mEvent->IsTrusted());
|
||||
}
|
||||
|
||||
~WantsPopupControlCheck()
|
||||
{
|
||||
mEvent->SetWantsPopupControlCheck(mOriginalWantsPopupControlCheck);
|
||||
}
|
||||
|
||||
private:
|
||||
Event* mEvent;
|
||||
bool mOriginalWantsPopupControlCheck;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -976,7 +976,7 @@ EventListenerManager::HandleEventInternal(nsPresContext* aPresContext,
|
||||
nsAutoTObserverArray<Listener, 2>::EndLimitedIterator iter(mListeners);
|
||||
Maybe<nsAutoPopupStatePusher> popupStatePusher;
|
||||
if (mIsMainThreadELM) {
|
||||
popupStatePusher.emplace(Event::GetEventPopupControlState(aEvent));
|
||||
popupStatePusher.emplace(Event::GetEventPopupControlState(aEvent, *aDOMEvent));
|
||||
}
|
||||
|
||||
bool hasListener = false;
|
||||
|
@ -944,16 +944,21 @@ EventStateManager::ExecuteAccessKey(nsTArray<uint32_t>& aAccessCharCodes,
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
EventStateManager::GetAccessKeyLabelPrefix(nsAString& aPrefix)
|
||||
// static
|
||||
void
|
||||
EventStateManager::GetAccessKeyLabelPrefix(Element* aElement, nsAString& aPrefix)
|
||||
{
|
||||
aPrefix.Truncate();
|
||||
nsAutoString separator, modifierText;
|
||||
nsContentUtils::GetModifierSeparatorText(separator);
|
||||
|
||||
nsCOMPtr<nsISupports> container = mPresContext->GetContainerWeak();
|
||||
nsCOMPtr<nsISupports> container = aElement->OwnerDoc()->GetDocShell();
|
||||
int32_t modifierMask = GetAccessModifierMaskFor(container);
|
||||
|
||||
if (modifierMask == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (modifierMask & NS_MODIFIER_CONTROL) {
|
||||
nsContentUtils::GetControlText(modifierText);
|
||||
aPrefix.Append(modifierText + separator);
|
||||
@ -974,7 +979,6 @@ EventStateManager::GetAccessKeyLabelPrefix(nsAString& aPrefix)
|
||||
nsContentUtils::GetShiftText(modifierText);
|
||||
aPrefix.Append(modifierText + separator);
|
||||
}
|
||||
return !aPrefix.IsEmpty();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -40,6 +40,7 @@ class WheelTransaction;
|
||||
|
||||
namespace dom {
|
||||
class DataTransfer;
|
||||
class Element;
|
||||
class TabParent;
|
||||
} // namespace dom
|
||||
|
||||
@ -169,7 +170,7 @@ public:
|
||||
*/
|
||||
uint32_t GetRegisteredAccessKey(nsIContent* aContent);
|
||||
|
||||
bool GetAccessKeyLabelPrefix(nsAString& aPrefix);
|
||||
static void GetAccessKeyLabelPrefix(dom::Element* aElement, nsAString& aPrefix);
|
||||
|
||||
nsresult SetCursor(int32_t aCursor, imgIContainer* aContainer,
|
||||
bool aHaveHotspot, float aHotspotX, float aHotspotY,
|
||||
|
@ -22,6 +22,7 @@ skip-if = buildapp == 'b2g'
|
||||
skip-if = buildapp == 'b2g'
|
||||
[test_bug288392.html]
|
||||
[test_bug299673-1.html]
|
||||
[test_bug1037990.html]
|
||||
[test_bug299673-2.html]
|
||||
[test_bug322588.html]
|
||||
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') || e10s #Bug 931116, b2g desktop specific, initial triage
|
||||
|
61
dom/events/test/test_bug1037990.html
Normal file
61
dom/events/test/test_bug1037990.html
Normal file
@ -0,0 +1,61 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1037990
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1037990</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=1037990">Mozilla Bug 1037990</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 1037990 **/
|
||||
|
||||
var pre, node, detachedAccess, attachedAcess;
|
||||
|
||||
node = document.createElement('a');
|
||||
node.href = 'http://example.org';
|
||||
node.accessKey = 'e';
|
||||
detachedAccess = node.accessKeyLabel;
|
||||
info('[window.document] detached: ' + detachedAccess);
|
||||
document.body.appendChild(node);
|
||||
attachedAcess = node.accessKeyLabel;
|
||||
info('[window.document] attached: ' + attachedAcess);
|
||||
is(detachedAccess, attachedAcess, "Both values are same for the window.document");
|
||||
|
||||
var parser=new DOMParser();
|
||||
var xmlDoc=parser.parseFromString("<root></root>","text/xml");
|
||||
var nn = xmlDoc.createElementNS('http://www.w3.org/1999/xhtml','a');
|
||||
nn.setAttribute('accesskey','t')
|
||||
detachedAccess = nn.accessKeyLabel;
|
||||
info('[xmlDoc] detached: ' + detachedAccess);
|
||||
var root = xmlDoc.getElementsByTagName('root')[0];
|
||||
root.appendChild(nn);
|
||||
attachedAcess = nn.accessKeyLabel;
|
||||
info('[xmlDoc] attached: ' + attachedAcess);
|
||||
is(detachedAccess, attachedAcess, "Both values are same for the xmlDoc");
|
||||
|
||||
var myDoc = new Document();
|
||||
var newnode = myDoc.createElementNS('http://www.w3.org/1999/xhtml','a');
|
||||
newnode.href = 'http://example.org';
|
||||
newnode.accessKey = 'f';
|
||||
detachedAccess = newnode.accessKeyLabel;
|
||||
info('[new document] detached: ' + detachedAccess);
|
||||
myDoc.appendChild(newnode);
|
||||
attachedAcess = newnode.accessKeyLabel;
|
||||
info('[new document] attached: ' + attachedAcess);
|
||||
is(detachedAccess, attachedAcess, "Both values are same for the new Document()");
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -6,95 +6,360 @@
|
||||
#include "Fetch.h"
|
||||
|
||||
#include "nsIStringStream.h"
|
||||
#include "nsIUnicodeDecoder.h"
|
||||
#include "nsIUnicodeEncoder.h"
|
||||
|
||||
#include "nsDOMString.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsStreamUtils.h"
|
||||
#include "nsStringStream.h"
|
||||
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/dom/EncodingUtils.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/Headers.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/Request.h"
|
||||
#include "mozilla/dom/Response.h"
|
||||
#include "mozilla/dom/URLSearchParams.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
namespace {
|
||||
nsresult
|
||||
ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrScalarValueStringOrURLSearchParams& aBodyInit,
|
||||
ExtractFromArrayBuffer(const ArrayBuffer& aBuffer,
|
||||
nsIInputStream** aStream)
|
||||
{
|
||||
aBuffer.ComputeLengthAndData();
|
||||
//XXXnsm reinterpret_cast<> is used in DOMParser, should be ok.
|
||||
return NS_NewByteInputStream(aStream,
|
||||
reinterpret_cast<char*>(aBuffer.Data()),
|
||||
aBuffer.Length(), NS_ASSIGNMENT_COPY);
|
||||
}
|
||||
|
||||
nsresult
|
||||
ExtractFromArrayBufferView(const ArrayBufferView& aBuffer,
|
||||
nsIInputStream** aStream)
|
||||
{
|
||||
aBuffer.ComputeLengthAndData();
|
||||
//XXXnsm reinterpret_cast<> is used in DOMParser, should be ok.
|
||||
return NS_NewByteInputStream(aStream,
|
||||
reinterpret_cast<char*>(aBuffer.Data()),
|
||||
aBuffer.Length(), NS_ASSIGNMENT_COPY);
|
||||
}
|
||||
|
||||
nsresult
|
||||
ExtractFromBlob(const File& aFile, nsIInputStream** aStream,
|
||||
nsCString& aContentType)
|
||||
{
|
||||
nsRefPtr<FileImpl> impl = aFile.Impl();
|
||||
nsresult rv = impl->GetInternalStream(aStream);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsString type;
|
||||
impl->GetType(type);
|
||||
aContentType = NS_ConvertUTF16toUTF8(type);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ExtractFromScalarValueString(const nsString& aStr,
|
||||
nsIInputStream** aStream,
|
||||
nsCString& aContentType)
|
||||
{
|
||||
nsCOMPtr<nsIUnicodeEncoder> encoder = EncodingUtils::EncoderForEncoding("UTF-8");
|
||||
if (!encoder) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
int32_t destBufferLen;
|
||||
nsresult rv = encoder->GetMaxLength(aStr.get(), aStr.Length(), &destBufferLen);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCString encoded;
|
||||
if (!encoded.SetCapacity(destBufferLen, fallible_t())) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
char* destBuffer = encoded.BeginWriting();
|
||||
int32_t srcLen = (int32_t) aStr.Length();
|
||||
int32_t outLen = destBufferLen;
|
||||
rv = encoder->Convert(aStr.get(), &srcLen, destBuffer, &outLen);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(outLen <= destBufferLen);
|
||||
encoded.SetLength(outLen);
|
||||
|
||||
aContentType = NS_LITERAL_CSTRING("text/plain;charset=UTF-8");
|
||||
|
||||
return NS_NewCStringInputStream(aStream, encoded);
|
||||
}
|
||||
|
||||
nsresult
|
||||
ExtractFromURLSearchParams(const URLSearchParams& aParams,
|
||||
nsIInputStream** aStream,
|
||||
nsCString& aContentType)
|
||||
{
|
||||
nsAutoString serialized;
|
||||
aParams.Stringify(serialized);
|
||||
aContentType = NS_LITERAL_CSTRING("application/x-www-form-urlencoded;charset=UTF-8");
|
||||
return NS_NewStringInputStream(aStream, serialized);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrBlobOrScalarValueStringOrURLSearchParams& aBodyInit,
|
||||
nsIInputStream** aStream,
|
||||
nsCString& aContentType)
|
||||
{
|
||||
MOZ_ASSERT(aStream);
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIInputStream> byteStream;
|
||||
if (aBodyInit.IsArrayBuffer()) {
|
||||
const ArrayBuffer& buf = aBodyInit.GetAsArrayBuffer();
|
||||
buf.ComputeLengthAndData();
|
||||
//XXXnsm reinterpret_cast<> is used in DOMParser, should be ok.
|
||||
rv = NS_NewByteInputStream(getter_AddRefs(byteStream),
|
||||
reinterpret_cast<char*>(buf.Data()),
|
||||
buf.Length(), NS_ASSIGNMENT_COPY);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
return ExtractFromArrayBuffer(buf, aStream);
|
||||
} else if (aBodyInit.IsArrayBufferView()) {
|
||||
const ArrayBufferView& buf = aBodyInit.GetAsArrayBufferView();
|
||||
buf.ComputeLengthAndData();
|
||||
//XXXnsm reinterpret_cast<> is used in DOMParser, should be ok.
|
||||
rv = NS_NewByteInputStream(getter_AddRefs(byteStream),
|
||||
reinterpret_cast<char*>(buf.Data()),
|
||||
buf.Length(), NS_ASSIGNMENT_COPY);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
return ExtractFromArrayBufferView(buf, aStream);
|
||||
} else if (aBodyInit.IsBlob()) {
|
||||
const File& blob = aBodyInit.GetAsBlob();
|
||||
return ExtractFromBlob(blob, aStream, aContentType);
|
||||
} else if (aBodyInit.IsScalarValueString()) {
|
||||
nsString str = aBodyInit.GetAsScalarValueString();
|
||||
|
||||
nsCOMPtr<nsIUnicodeEncoder> encoder = EncodingUtils::EncoderForEncoding("UTF-8");
|
||||
if (!encoder) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
int32_t destBufferLen;
|
||||
rv = encoder->GetMaxLength(str.get(), str.Length(), &destBufferLen);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCString encoded;
|
||||
if (!encoded.SetCapacity(destBufferLen, fallible_t())) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
char* destBuffer = encoded.BeginWriting();
|
||||
int32_t srcLen = (int32_t) str.Length();
|
||||
int32_t outLen = destBufferLen;
|
||||
rv = encoder->Convert(str.get(), &srcLen, destBuffer, &outLen);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(outLen <= destBufferLen);
|
||||
encoded.SetLength(outLen);
|
||||
rv = NS_NewCStringInputStream(getter_AddRefs(byteStream), encoded);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
aContentType = NS_LITERAL_CSTRING("text/plain;charset=UTF-8");
|
||||
nsAutoString str;
|
||||
str.Assign(aBodyInit.GetAsScalarValueString());
|
||||
return ExtractFromScalarValueString(str, aStream, aContentType);
|
||||
} else if (aBodyInit.IsURLSearchParams()) {
|
||||
URLSearchParams& params = aBodyInit.GetAsURLSearchParams();
|
||||
nsString serialized;
|
||||
params.Stringify(serialized);
|
||||
rv = NS_NewStringInputStream(getter_AddRefs(byteStream), serialized);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
aContentType = NS_LITERAL_CSTRING("application/x-www-form-urlencoded;charset=UTF-8");
|
||||
return ExtractFromURLSearchParams(params, aStream, aContentType);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(byteStream);
|
||||
byteStream.forget(aStream);
|
||||
return NS_OK;
|
||||
NS_NOTREACHED("Should never reach here");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ExtractByteStreamFromBody(const ArrayBufferOrArrayBufferViewOrBlobOrScalarValueStringOrURLSearchParams& aBodyInit,
|
||||
nsIInputStream** aStream,
|
||||
nsCString& aContentType)
|
||||
{
|
||||
MOZ_ASSERT(aStream);
|
||||
|
||||
if (aBodyInit.IsArrayBuffer()) {
|
||||
const ArrayBuffer& buf = aBodyInit.GetAsArrayBuffer();
|
||||
return ExtractFromArrayBuffer(buf, aStream);
|
||||
} else if (aBodyInit.IsArrayBufferView()) {
|
||||
const ArrayBufferView& buf = aBodyInit.GetAsArrayBufferView();
|
||||
return ExtractFromArrayBufferView(buf, aStream);
|
||||
} else if (aBodyInit.IsBlob()) {
|
||||
const File& blob = aBodyInit.GetAsBlob();
|
||||
return ExtractFromBlob(blob, aStream, aContentType);
|
||||
} else if (aBodyInit.IsScalarValueString()) {
|
||||
nsAutoString str;
|
||||
str.Assign(aBodyInit.GetAsScalarValueString());
|
||||
return ExtractFromScalarValueString(str, aStream, aContentType);
|
||||
} else if (aBodyInit.IsURLSearchParams()) {
|
||||
URLSearchParams& params = aBodyInit.GetAsURLSearchParams();
|
||||
return ExtractFromURLSearchParams(params, aStream, aContentType);
|
||||
}
|
||||
|
||||
NS_NOTREACHED("Should never reach here");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
namespace {
|
||||
nsresult
|
||||
DecodeUTF8(const nsCString& aBuffer, nsString& aDecoded)
|
||||
{
|
||||
nsCOMPtr<nsIUnicodeDecoder> decoder =
|
||||
EncodingUtils::DecoderForEncoding("UTF-8");
|
||||
if (!decoder) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
int32_t destBufferLen;
|
||||
nsresult rv =
|
||||
decoder->GetMaxLength(aBuffer.get(), aBuffer.Length(), &destBufferLen);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!aDecoded.SetCapacity(destBufferLen, fallible_t())) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
char16_t* destBuffer = aDecoded.BeginWriting();
|
||||
int32_t srcLen = (int32_t) aBuffer.Length();
|
||||
int32_t outLen = destBufferLen;
|
||||
rv = decoder->Convert(aBuffer.get(), &srcLen, destBuffer, &outLen);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(outLen <= destBufferLen);
|
||||
aDecoded.SetLength(outLen);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
already_AddRefed<Promise>
|
||||
FetchBody<Derived>::ConsumeBody(ConsumeType aType, ErrorResult& aRv)
|
||||
{
|
||||
nsRefPtr<Promise> promise = Promise::Create(DerivedClass()->GetParentObject(), aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (BodyUsed()) {
|
||||
aRv.ThrowTypeError(MSG_REQUEST_BODY_CONSUMED_ERROR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SetBodyUsed();
|
||||
|
||||
// While the spec says to do this asynchronously, all the body constructors
|
||||
// right now only accept bodies whose streams are backed by an in-memory
|
||||
// buffer that can be read without blocking. So I think this is fine.
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
DerivedClass()->GetBody(getter_AddRefs(stream));
|
||||
|
||||
if (!stream) {
|
||||
aRv = NS_NewByteInputStream(getter_AddRefs(stream), "", 0,
|
||||
NS_ASSIGNMENT_COPY);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
AutoJSAPI api;
|
||||
api.Init(DerivedClass()->GetParentObject());
|
||||
JSContext* cx = api.cx();
|
||||
|
||||
// We can make this assertion because for now we only support memory backed
|
||||
// structures for the body argument for a Request.
|
||||
MOZ_ASSERT(NS_InputStreamIsBuffered(stream));
|
||||
nsCString buffer;
|
||||
uint64_t len;
|
||||
aRv = stream->Available(&len);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
aRv = NS_ReadInputStreamToString(stream, buffer, len);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
buffer.SetLength(len);
|
||||
|
||||
switch (aType) {
|
||||
case CONSUME_ARRAYBUFFER: {
|
||||
JS::Rooted<JSObject*> arrayBuffer(cx);
|
||||
arrayBuffer =
|
||||
ArrayBuffer::Create(cx, buffer.Length(),
|
||||
reinterpret_cast<const uint8_t*>(buffer.get()));
|
||||
JS::Rooted<JS::Value> val(cx);
|
||||
val.setObjectOrNull(arrayBuffer);
|
||||
promise->MaybeResolve(cx, val);
|
||||
return promise.forget();
|
||||
}
|
||||
case CONSUME_BLOB: {
|
||||
// XXXnsm it is actually possible to avoid these duplicate allocations
|
||||
// for the Blob case by having the Blob adopt the stream's memory
|
||||
// directly, but I've not added a special case for now.
|
||||
//
|
||||
// FIXME(nsm): Use nsContentUtils::CreateBlobBuffer once blobs have been fixed on
|
||||
// workers.
|
||||
uint32_t blobLen = buffer.Length();
|
||||
void* blobData = moz_malloc(blobLen);
|
||||
nsRefPtr<File> blob;
|
||||
if (blobData) {
|
||||
memcpy(blobData, buffer.BeginReading(), blobLen);
|
||||
blob = File::CreateMemoryFile(DerivedClass()->GetParentObject(), blobData, blobLen,
|
||||
NS_ConvertUTF8toUTF16(mMimeType));
|
||||
} else {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
promise->MaybeResolve(blob);
|
||||
return promise.forget();
|
||||
}
|
||||
case CONSUME_JSON: {
|
||||
nsAutoString decoded;
|
||||
aRv = DecodeUTF8(buffer, decoded);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JS::Rooted<JS::Value> json(cx);
|
||||
if (!JS_ParseJSON(cx, decoded.get(), decoded.Length(), &json)) {
|
||||
JS::Rooted<JS::Value> exn(cx);
|
||||
if (JS_GetPendingException(cx, &exn)) {
|
||||
JS_ClearPendingException(cx);
|
||||
promise->MaybeReject(cx, exn);
|
||||
}
|
||||
}
|
||||
promise->MaybeResolve(cx, json);
|
||||
return promise.forget();
|
||||
}
|
||||
case CONSUME_TEXT: {
|
||||
nsAutoString decoded;
|
||||
aRv = DecodeUTF8(buffer, decoded);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
promise->MaybeResolve(decoded);
|
||||
return promise.forget();
|
||||
}
|
||||
}
|
||||
|
||||
NS_NOTREACHED("Unexpected consume body type");
|
||||
// Silence warnings.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template
|
||||
already_AddRefed<Promise>
|
||||
FetchBody<Request>::ConsumeBody(ConsumeType aType, ErrorResult& aRv);
|
||||
|
||||
template
|
||||
already_AddRefed<Promise>
|
||||
FetchBody<Response>::ConsumeBody(ConsumeType aType, ErrorResult& aRv);
|
||||
|
||||
template <class Derived>
|
||||
void
|
||||
FetchBody<Derived>::SetMimeType(ErrorResult& aRv)
|
||||
{
|
||||
// Extract mime type.
|
||||
nsTArray<nsCString> contentTypeValues;
|
||||
MOZ_ASSERT(DerivedClass()->GetInternalHeaders());
|
||||
DerivedClass()->GetInternalHeaders()->GetAll(NS_LITERAL_CSTRING("Content-Type"), contentTypeValues, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// HTTP ABNF states Content-Type may have only one value.
|
||||
// This is from the "parse a header value" of the fetch spec.
|
||||
if (contentTypeValues.Length() == 1) {
|
||||
mMimeType = contentTypeValues[0];
|
||||
ToLowerCase(mMimeType);
|
||||
}
|
||||
}
|
||||
|
||||
template
|
||||
void
|
||||
FetchBody<Request>::SetMimeType(ErrorResult& aRv);
|
||||
|
||||
template
|
||||
void
|
||||
FetchBody<Response>::SetMimeType(ErrorResult& aRv);
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -13,16 +13,93 @@ class nsIInputStream;
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class Promise;
|
||||
|
||||
/*
|
||||
* Creates an nsIInputStream based on the fetch specifications 'extract a byte
|
||||
* stream algorithm' - http://fetch.spec.whatwg.org/#concept-bodyinit-extract.
|
||||
* Stores content type in out param aContentType.
|
||||
*/
|
||||
nsresult
|
||||
ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrScalarValueStringOrURLSearchParams& aBodyInit,
|
||||
ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrBlobOrScalarValueStringOrURLSearchParams& aBodyInit,
|
||||
nsIInputStream** aStream,
|
||||
nsCString& aContentType);
|
||||
|
||||
/*
|
||||
* Non-owning version.
|
||||
*/
|
||||
nsresult
|
||||
ExtractByteStreamFromBody(const ArrayBufferOrArrayBufferViewOrBlobOrScalarValueStringOrURLSearchParams& aBodyInit,
|
||||
nsIInputStream** aStream,
|
||||
nsCString& aContentType);
|
||||
|
||||
template <class Derived>
|
||||
class FetchBody {
|
||||
public:
|
||||
bool
|
||||
BodyUsed() { return mBodyUsed; }
|
||||
|
||||
already_AddRefed<Promise>
|
||||
ArrayBuffer(ErrorResult& aRv)
|
||||
{
|
||||
return ConsumeBody(CONSUME_ARRAYBUFFER, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Blob(ErrorResult& aRv)
|
||||
{
|
||||
return ConsumeBody(CONSUME_BLOB, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Json(ErrorResult& aRv)
|
||||
{
|
||||
return ConsumeBody(CONSUME_JSON, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Text(ErrorResult& aRv)
|
||||
{
|
||||
return ConsumeBody(CONSUME_TEXT, aRv);
|
||||
}
|
||||
|
||||
protected:
|
||||
FetchBody()
|
||||
: mBodyUsed(false)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
SetBodyUsed()
|
||||
{
|
||||
mBodyUsed = true;
|
||||
}
|
||||
|
||||
void
|
||||
SetMimeType(ErrorResult& aRv);
|
||||
|
||||
private:
|
||||
enum ConsumeType
|
||||
{
|
||||
CONSUME_ARRAYBUFFER,
|
||||
CONSUME_BLOB,
|
||||
// FormData not supported right now,
|
||||
CONSUME_JSON,
|
||||
CONSUME_TEXT,
|
||||
};
|
||||
|
||||
Derived*
|
||||
DerivedClass() const
|
||||
{
|
||||
return static_cast<Derived*>(const_cast<FetchBody*>(this));
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
ConsumeBody(ConsumeType aType, ErrorResult& aRv);
|
||||
|
||||
bool mBodyUsed;
|
||||
nsCString mMimeType;
|
||||
};
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -10,13 +10,6 @@
|
||||
#include "mozilla/dom/WorkerPrivate.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
#include "nsCharSeparatedTokenizer.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsDOMString.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsReadableUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
@ -61,18 +54,19 @@ Headers::Constructor(const GlobalObject& aGlobal,
|
||||
const Optional<HeadersOrByteStringSequenceSequenceOrByteStringMozMap>& aInit,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsRefPtr<Headers> headers = new Headers(aGlobal.GetAsSupports());
|
||||
nsRefPtr<InternalHeaders> ih = new InternalHeaders();
|
||||
nsRefPtr<Headers> headers = new Headers(aGlobal.GetAsSupports(), ih);
|
||||
|
||||
if (!aInit.WasPassed()) {
|
||||
return headers.forget();
|
||||
}
|
||||
|
||||
if (aInit.Value().IsHeaders()) {
|
||||
headers->Fill(aInit.Value().GetAsHeaders(), aRv);
|
||||
ih->Fill(*aInit.Value().GetAsHeaders().mInternalHeaders, aRv);
|
||||
} else if (aInit.Value().IsByteStringSequenceSequence()) {
|
||||
headers->Fill(aInit.Value().GetAsByteStringSequenceSequence(), aRv);
|
||||
ih->Fill(aInit.Value().GetAsByteStringSequenceSequence(), aRv);
|
||||
} else if (aInit.Value().IsByteStringMozMap()) {
|
||||
headers->Fill(aInit.Value().GetAsByteStringMozMap(), aRv);
|
||||
ih->Fill(aInit.Value().GetAsByteStringMozMap(), aRv);
|
||||
}
|
||||
|
||||
if (aRv.Failed()) {
|
||||
@ -88,14 +82,15 @@ Headers::Constructor(const GlobalObject& aGlobal,
|
||||
const OwningHeadersOrByteStringSequenceSequenceOrByteStringMozMap& aInit,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsRefPtr<Headers> headers = new Headers(aGlobal.GetAsSupports());
|
||||
nsRefPtr<InternalHeaders> ih = new InternalHeaders();
|
||||
nsRefPtr<Headers> headers = new Headers(aGlobal.GetAsSupports(), ih);
|
||||
|
||||
if (aInit.IsHeaders()) {
|
||||
headers->Fill(aInit.GetAsHeaders(), aRv);
|
||||
ih->Fill(*(aInit.GetAsHeaders().get()->mInternalHeaders), aRv);
|
||||
} else if (aInit.IsByteStringSequenceSequence()) {
|
||||
headers->Fill(aInit.GetAsByteStringSequenceSequence(), aRv);
|
||||
ih->Fill(aInit.GetAsByteStringSequenceSequence(), aRv);
|
||||
} else if (aInit.IsByteStringMozMap()) {
|
||||
headers->Fill(aInit.GetAsByteStringMozMap(), aRv);
|
||||
ih->Fill(aInit.GetAsByteStringMozMap(), aRv);
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
@ -105,153 +100,6 @@ Headers::Constructor(const GlobalObject& aGlobal,
|
||||
return headers.forget();
|
||||
}
|
||||
|
||||
Headers::Headers(const Headers& aOther)
|
||||
: mOwner(aOther.mOwner)
|
||||
, mGuard(aOther.mGuard)
|
||||
{
|
||||
ErrorResult result;
|
||||
Fill(aOther, result);
|
||||
MOZ_ASSERT(!result.Failed());
|
||||
}
|
||||
|
||||
void
|
||||
Headers::Append(const nsACString& aName, const nsACString& aValue,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsAutoCString lowerName;
|
||||
ToLowerCase(aName, lowerName);
|
||||
|
||||
if (IsInvalidMutableHeader(lowerName, &aValue, aRv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
mList.AppendElement(Entry(lowerName, aValue));
|
||||
}
|
||||
|
||||
void
|
||||
Headers::Delete(const nsACString& aName, ErrorResult& aRv)
|
||||
{
|
||||
nsAutoCString lowerName;
|
||||
ToLowerCase(aName, lowerName);
|
||||
|
||||
if (IsInvalidMutableHeader(lowerName, nullptr, aRv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// remove in reverse order to minimize copying
|
||||
for (int32_t i = mList.Length() - 1; i >= 0; --i) {
|
||||
if (lowerName == mList[i].mName) {
|
||||
mList.RemoveElementAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Headers::Get(const nsACString& aName, nsCString& aValue, ErrorResult& aRv) const
|
||||
{
|
||||
nsAutoCString lowerName;
|
||||
ToLowerCase(aName, lowerName);
|
||||
|
||||
if (IsInvalidName(lowerName, aRv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < mList.Length(); ++i) {
|
||||
if (lowerName == mList[i].mName) {
|
||||
aValue = mList[i].mValue;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// No value found, so return null to content
|
||||
aValue.SetIsVoid(true);
|
||||
}
|
||||
|
||||
void
|
||||
Headers::GetAll(const nsACString& aName, nsTArray<nsCString>& aResults,
|
||||
ErrorResult& aRv) const
|
||||
{
|
||||
nsAutoCString lowerName;
|
||||
ToLowerCase(aName, lowerName);
|
||||
|
||||
if (IsInvalidName(lowerName, aRv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
aResults.SetLength(0);
|
||||
for (uint32_t i = 0; i < mList.Length(); ++i) {
|
||||
if (lowerName == mList[i].mName) {
|
||||
aResults.AppendElement(mList[i].mValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Headers::Has(const nsACString& aName, ErrorResult& aRv) const
|
||||
{
|
||||
nsAutoCString lowerName;
|
||||
ToLowerCase(aName, lowerName);
|
||||
|
||||
if (IsInvalidName(lowerName, aRv)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < mList.Length(); ++i) {
|
||||
if (lowerName == mList[i].mName) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
Headers::Set(const nsACString& aName, const nsACString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
nsAutoCString lowerName;
|
||||
ToLowerCase(aName, lowerName);
|
||||
|
||||
if (IsInvalidMutableHeader(lowerName, &aValue, aRv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t firstIndex = INT32_MAX;
|
||||
|
||||
// remove in reverse order to minimize copying
|
||||
for (int32_t i = mList.Length() - 1; i >= 0; --i) {
|
||||
if (lowerName == mList[i].mName) {
|
||||
firstIndex = std::min(firstIndex, i);
|
||||
mList.RemoveElementAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (firstIndex < INT32_MAX) {
|
||||
Entry* entry = mList.InsertElementAt(firstIndex);
|
||||
entry->mName = lowerName;
|
||||
entry->mValue = aValue;
|
||||
} else {
|
||||
mList.AppendElement(Entry(lowerName, aValue));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Headers::Clear()
|
||||
{
|
||||
mList.Clear();
|
||||
}
|
||||
|
||||
void
|
||||
Headers::SetGuard(HeadersGuardEnum aGuard, ErrorResult& aRv)
|
||||
{
|
||||
// Rather than re-validate all current headers, just require code to set
|
||||
// this prior to populating the Headers object. Allow setting immutable
|
||||
// late, though, as that is pretty much required to have a useful, immutable
|
||||
// headers object.
|
||||
if (aGuard != HeadersGuardEnum::Immutable && mList.Length() > 0) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
}
|
||||
mGuard = aGuard;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
Headers::WrapObject(JSContext* aCx)
|
||||
{
|
||||
@ -261,109 +109,5 @@ Headers::WrapObject(JSContext* aCx)
|
||||
Headers::~Headers()
|
||||
{
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
Headers::IsSimpleHeader(const nsACString& aName, const nsACString* aValue)
|
||||
{
|
||||
// Note, we must allow a null content-type value here to support
|
||||
// get("content-type"), but the IsInvalidValue() check will prevent null
|
||||
// from being set or appended.
|
||||
return aName.EqualsLiteral("accept") ||
|
||||
aName.EqualsLiteral("accept-language") ||
|
||||
aName.EqualsLiteral("content-language") ||
|
||||
(aName.EqualsLiteral("content-type") &&
|
||||
(!aValue || nsContentUtils::IsAllowedNonCorsContentType(*aValue)));
|
||||
}
|
||||
|
||||
//static
|
||||
bool
|
||||
Headers::IsInvalidName(const nsACString& aName, ErrorResult& aRv)
|
||||
{
|
||||
if (!NS_IsValidHTTPToken(aName)) {
|
||||
NS_ConvertUTF8toUTF16 label(aName);
|
||||
aRv.ThrowTypeError(MSG_INVALID_HEADER_NAME, &label);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
Headers::IsInvalidValue(const nsACString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
if (!NS_IsReasonableHTTPHeaderValue(aValue)) {
|
||||
NS_ConvertUTF8toUTF16 label(aValue);
|
||||
aRv.ThrowTypeError(MSG_INVALID_HEADER_VALUE, &label);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
Headers::IsImmutable(ErrorResult& aRv) const
|
||||
{
|
||||
if (mGuard == HeadersGuardEnum::Immutable) {
|
||||
aRv.ThrowTypeError(MSG_HEADERS_IMMUTABLE);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
Headers::IsForbiddenRequestHeader(const nsACString& aName) const
|
||||
{
|
||||
return mGuard == HeadersGuardEnum::Request &&
|
||||
nsContentUtils::IsForbiddenRequestHeader(aName);
|
||||
}
|
||||
|
||||
bool
|
||||
Headers::IsForbiddenRequestNoCorsHeader(const nsACString& aName,
|
||||
const nsACString* aValue) const
|
||||
{
|
||||
return mGuard == HeadersGuardEnum::Request_no_cors &&
|
||||
!IsSimpleHeader(aName, aValue);
|
||||
}
|
||||
|
||||
bool
|
||||
Headers::IsForbiddenResponseHeader(const nsACString& aName) const
|
||||
{
|
||||
return mGuard == HeadersGuardEnum::Response &&
|
||||
nsContentUtils::IsForbiddenResponseHeader(aName);
|
||||
}
|
||||
|
||||
void
|
||||
Headers::Fill(const Headers& aInit, ErrorResult& aRv)
|
||||
{
|
||||
const nsTArray<Entry>& list = aInit.mList;
|
||||
for (uint32_t i = 0; i < list.Length() && !aRv.Failed(); ++i) {
|
||||
const Entry& entry = list[i];
|
||||
Append(entry.mName, entry.mValue, aRv);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Headers::Fill(const Sequence<Sequence<nsCString>>& aInit, ErrorResult& aRv)
|
||||
{
|
||||
for (uint32_t i = 0; i < aInit.Length() && !aRv.Failed(); ++i) {
|
||||
const Sequence<nsCString>& tuple = aInit[i];
|
||||
if (tuple.Length() != 2) {
|
||||
aRv.ThrowTypeError(MSG_INVALID_HEADER_SEQUENCE);
|
||||
return;
|
||||
}
|
||||
Append(tuple[0], tuple[1], aRv);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Headers::Fill(const MozMap<nsCString>& aInit, ErrorResult& aRv)
|
||||
{
|
||||
nsTArray<nsString> keys;
|
||||
aInit.GetKeys(keys);
|
||||
for (uint32_t i = 0; i < keys.Length() && !aRv.Failed(); ++i) {
|
||||
Append(NS_ConvertUTF16toUTF8(keys[i]), aInit.Get(keys[i]), aRv);
|
||||
}
|
||||
}
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -13,6 +13,8 @@
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
#include "InternalHeaders.h"
|
||||
|
||||
class nsPIDOMWindow;
|
||||
|
||||
namespace mozilla {
|
||||
@ -24,38 +26,34 @@ namespace dom {
|
||||
template<typename T> class MozMap;
|
||||
class HeadersOrByteStringSequenceSequenceOrByteStringMozMap;
|
||||
|
||||
/**
|
||||
* This Headers class is only used to represent the content facing Headers
|
||||
* object. It is actually backed by an InternalHeaders implementation. Gecko
|
||||
* code should NEVER use this, except in the Request and Response
|
||||
* implementations, where they must always be created from the backing
|
||||
* InternalHeaders object.
|
||||
*/
|
||||
class Headers MOZ_FINAL : public nsISupports
|
||||
, public nsWrapperCache
|
||||
{
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Headers)
|
||||
|
||||
friend class Request;
|
||||
friend class Response;
|
||||
|
||||
private:
|
||||
struct Entry
|
||||
{
|
||||
Entry(const nsACString& aName, const nsACString& aValue)
|
||||
: mName(aName)
|
||||
, mValue(aValue)
|
||||
{ }
|
||||
|
||||
Entry() { }
|
||||
|
||||
nsCString mName;
|
||||
nsCString mValue;
|
||||
};
|
||||
|
||||
nsCOMPtr<nsISupports> mOwner;
|
||||
HeadersGuardEnum mGuard;
|
||||
nsTArray<Entry> mList;
|
||||
nsRefPtr<InternalHeaders> mInternalHeaders;
|
||||
|
||||
public:
|
||||
explicit Headers(nsISupports* aOwner, HeadersGuardEnum aGuard = HeadersGuardEnum::None)
|
||||
explicit Headers(nsISupports* aOwner, InternalHeaders* aInternalHeaders)
|
||||
: mOwner(aOwner)
|
||||
, mGuard(aGuard)
|
||||
, mInternalHeaders(aInternalHeaders)
|
||||
{
|
||||
}
|
||||
|
||||
explicit Headers(const Headers& aOther);
|
||||
explicit Headers(const Headers& aOther) MOZ_DELETE;
|
||||
|
||||
static bool PrefEnabled(JSContext* cx, JSObject* obj);
|
||||
|
||||
@ -70,56 +68,59 @@ public:
|
||||
ErrorResult& aRv);
|
||||
|
||||
void Append(const nsACString& aName, const nsACString& aValue,
|
||||
ErrorResult& aRv);
|
||||
void Delete(const nsACString& aName, ErrorResult& aRv);
|
||||
void Get(const nsACString& aName, nsCString& aValue, ErrorResult& aRv) const;
|
||||
void GetAll(const nsACString& aName, nsTArray<nsCString>& aResults,
|
||||
ErrorResult& aRv) const;
|
||||
bool Has(const nsACString& aName, ErrorResult& aRv) const;
|
||||
void Set(const nsACString& aName, const nsACString& aValue, ErrorResult& aRv);
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
mInternalHeaders->Append(aName, aValue, aRv);
|
||||
}
|
||||
|
||||
void Clear();
|
||||
void Delete(const nsACString& aName, ErrorResult& aRv)
|
||||
{
|
||||
mInternalHeaders->Delete(aName, aRv);
|
||||
}
|
||||
|
||||
void Get(const nsACString& aName, nsCString& aValue, ErrorResult& aRv) const
|
||||
{
|
||||
mInternalHeaders->Get(aName, aValue, aRv);
|
||||
}
|
||||
|
||||
void GetAll(const nsACString& aName, nsTArray<nsCString>& aResults,
|
||||
ErrorResult& aRv) const
|
||||
{
|
||||
mInternalHeaders->GetAll(aName, aResults, aRv);
|
||||
}
|
||||
|
||||
bool Has(const nsACString& aName, ErrorResult& aRv) const
|
||||
{
|
||||
return mInternalHeaders->Has(aName, aRv);
|
||||
}
|
||||
|
||||
void Set(const nsACString& aName, const nsACString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
mInternalHeaders->Set(aName, aValue, aRv);
|
||||
}
|
||||
|
||||
// ChromeOnly
|
||||
HeadersGuardEnum Guard() const { return mGuard; }
|
||||
void SetGuard(HeadersGuardEnum aGuard, ErrorResult& aRv);
|
||||
HeadersGuardEnum Guard() const
|
||||
{
|
||||
return mInternalHeaders->Guard();
|
||||
}
|
||||
|
||||
void SetGuard(HeadersGuardEnum aGuard, ErrorResult& aRv)
|
||||
{
|
||||
mInternalHeaders->SetGuard(aGuard, aRv);
|
||||
}
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx);
|
||||
nsISupports* GetParentObject() const { return mOwner; }
|
||||
|
||||
void Fill(const Headers& aInit, ErrorResult& aRv);
|
||||
private:
|
||||
// Since Headers is also an nsISupports, the above constructor can
|
||||
// accidentally be invoked as new Headers(Headers*[, implied None guard]) when
|
||||
// the intention is to use the copy constructor. Explicitly disallow it.
|
||||
Headers(Headers* aOther) MOZ_DELETE;
|
||||
|
||||
virtual ~Headers();
|
||||
|
||||
static bool IsSimpleHeader(const nsACString& aName,
|
||||
const nsACString* aValue = nullptr);
|
||||
static bool IsInvalidName(const nsACString& aName, ErrorResult& aRv);
|
||||
static bool IsInvalidValue(const nsACString& aValue, ErrorResult& aRv);
|
||||
bool IsImmutable(ErrorResult& aRv) const;
|
||||
bool IsForbiddenRequestHeader(const nsACString& aName) const;
|
||||
bool IsForbiddenRequestNoCorsHeader(const nsACString& aName,
|
||||
const nsACString* aValue = nullptr) const;
|
||||
bool IsForbiddenResponseHeader(const nsACString& aName) const;
|
||||
|
||||
bool IsInvalidMutableHeader(const nsACString& aName,
|
||||
const nsACString* aValue,
|
||||
ErrorResult& aRv) const
|
||||
InternalHeaders*
|
||||
GetInternalHeaders() const
|
||||
{
|
||||
return IsInvalidName(aName, aRv) ||
|
||||
(aValue && IsInvalidValue(*aValue, aRv)) ||
|
||||
IsImmutable(aRv) ||
|
||||
IsForbiddenRequestHeader(aName) ||
|
||||
IsForbiddenRequestNoCorsHeader(aName, aValue) ||
|
||||
IsForbiddenResponseHeader(aName);
|
||||
return mInternalHeaders;
|
||||
}
|
||||
|
||||
void Fill(const Sequence<Sequence<nsCString>>& aInit, ErrorResult& aRv);
|
||||
void Fill(const MozMap<nsCString>& aInit, ErrorResult& aRv);
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
272
dom/fetch/InternalHeaders.cpp
Normal file
272
dom/fetch/InternalHeaders.cpp
Normal file
@ -0,0 +1,272 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "mozilla/dom/InternalHeaders.h"
|
||||
|
||||
#include "mozilla/ErrorResult.h"
|
||||
|
||||
#include "nsCharSeparatedTokenizer.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsReadableUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
void
|
||||
InternalHeaders::Append(const nsACString& aName, const nsACString& aValue,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsAutoCString lowerName;
|
||||
ToLowerCase(aName, lowerName);
|
||||
|
||||
if (IsInvalidMutableHeader(lowerName, aValue, aRv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
mList.AppendElement(Entry(lowerName, aValue));
|
||||
}
|
||||
|
||||
void
|
||||
InternalHeaders::Delete(const nsACString& aName, ErrorResult& aRv)
|
||||
{
|
||||
nsAutoCString lowerName;
|
||||
ToLowerCase(aName, lowerName);
|
||||
|
||||
if (IsInvalidMutableHeader(lowerName, aRv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// remove in reverse order to minimize copying
|
||||
for (int32_t i = mList.Length() - 1; i >= 0; --i) {
|
||||
if (lowerName == mList[i].mName) {
|
||||
mList.RemoveElementAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
InternalHeaders::Get(const nsACString& aName, nsCString& aValue, ErrorResult& aRv) const
|
||||
{
|
||||
nsAutoCString lowerName;
|
||||
ToLowerCase(aName, lowerName);
|
||||
|
||||
if (IsInvalidName(lowerName, aRv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < mList.Length(); ++i) {
|
||||
if (lowerName == mList[i].mName) {
|
||||
aValue = mList[i].mValue;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// No value found, so return null to content
|
||||
aValue.SetIsVoid(true);
|
||||
}
|
||||
|
||||
void
|
||||
InternalHeaders::GetAll(const nsACString& aName, nsTArray<nsCString>& aResults,
|
||||
ErrorResult& aRv) const
|
||||
{
|
||||
nsAutoCString lowerName;
|
||||
ToLowerCase(aName, lowerName);
|
||||
|
||||
if (IsInvalidName(lowerName, aRv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
aResults.SetLength(0);
|
||||
for (uint32_t i = 0; i < mList.Length(); ++i) {
|
||||
if (lowerName == mList[i].mName) {
|
||||
aResults.AppendElement(mList[i].mValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
InternalHeaders::Has(const nsACString& aName, ErrorResult& aRv) const
|
||||
{
|
||||
nsAutoCString lowerName;
|
||||
ToLowerCase(aName, lowerName);
|
||||
|
||||
if (IsInvalidName(lowerName, aRv)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < mList.Length(); ++i) {
|
||||
if (lowerName == mList[i].mName) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
InternalHeaders::Set(const nsACString& aName, const nsACString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
nsAutoCString lowerName;
|
||||
ToLowerCase(aName, lowerName);
|
||||
|
||||
if (IsInvalidMutableHeader(lowerName, aValue, aRv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t firstIndex = INT32_MAX;
|
||||
|
||||
// remove in reverse order to minimize copying
|
||||
for (int32_t i = mList.Length() - 1; i >= 0; --i) {
|
||||
if (lowerName == mList[i].mName) {
|
||||
firstIndex = std::min(firstIndex, i);
|
||||
mList.RemoveElementAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (firstIndex < INT32_MAX) {
|
||||
Entry* entry = mList.InsertElementAt(firstIndex);
|
||||
entry->mName = lowerName;
|
||||
entry->mValue = aValue;
|
||||
} else {
|
||||
mList.AppendElement(Entry(lowerName, aValue));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
InternalHeaders::Clear()
|
||||
{
|
||||
mList.Clear();
|
||||
}
|
||||
|
||||
void
|
||||
InternalHeaders::SetGuard(HeadersGuardEnum aGuard, ErrorResult& aRv)
|
||||
{
|
||||
// Rather than re-validate all current headers, just require code to set
|
||||
// this prior to populating the InternalHeaders object. Allow setting immutable
|
||||
// late, though, as that is pretty much required to have a useful, immutable
|
||||
// headers object.
|
||||
if (aGuard != HeadersGuardEnum::Immutable && mList.Length() > 0) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
}
|
||||
mGuard = aGuard;
|
||||
}
|
||||
|
||||
InternalHeaders::~InternalHeaders()
|
||||
{
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
InternalHeaders::IsSimpleHeader(const nsACString& aName, const nsACString& aValue)
|
||||
{
|
||||
// Note, we must allow a null content-type value here to support
|
||||
// get("content-type"), but the IsInvalidValue() check will prevent null
|
||||
// from being set or appended.
|
||||
return aName.EqualsLiteral("accept") ||
|
||||
aName.EqualsLiteral("accept-language") ||
|
||||
aName.EqualsLiteral("content-language") ||
|
||||
(aName.EqualsLiteral("content-type") &&
|
||||
nsContentUtils::IsAllowedNonCorsContentType(aValue));
|
||||
}
|
||||
|
||||
//static
|
||||
bool
|
||||
InternalHeaders::IsInvalidName(const nsACString& aName, ErrorResult& aRv)
|
||||
{
|
||||
if (!NS_IsValidHTTPToken(aName)) {
|
||||
NS_ConvertUTF8toUTF16 label(aName);
|
||||
aRv.ThrowTypeError(MSG_INVALID_HEADER_NAME, &label);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
InternalHeaders::IsInvalidValue(const nsACString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
if (!NS_IsReasonableHTTPHeaderValue(aValue)) {
|
||||
NS_ConvertUTF8toUTF16 label(aValue);
|
||||
aRv.ThrowTypeError(MSG_INVALID_HEADER_VALUE, &label);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
InternalHeaders::IsImmutable(ErrorResult& aRv) const
|
||||
{
|
||||
if (mGuard == HeadersGuardEnum::Immutable) {
|
||||
aRv.ThrowTypeError(MSG_HEADERS_IMMUTABLE);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
InternalHeaders::IsForbiddenRequestHeader(const nsACString& aName) const
|
||||
{
|
||||
return mGuard == HeadersGuardEnum::Request &&
|
||||
nsContentUtils::IsForbiddenRequestHeader(aName);
|
||||
}
|
||||
|
||||
bool
|
||||
InternalHeaders::IsForbiddenRequestNoCorsHeader(const nsACString& aName) const
|
||||
{
|
||||
return mGuard == HeadersGuardEnum::Request_no_cors &&
|
||||
!IsSimpleHeader(aName, EmptyCString());
|
||||
}
|
||||
|
||||
bool
|
||||
InternalHeaders::IsForbiddenRequestNoCorsHeader(const nsACString& aName,
|
||||
const nsACString& aValue) const
|
||||
{
|
||||
return mGuard == HeadersGuardEnum::Request_no_cors &&
|
||||
!IsSimpleHeader(aName, aValue);
|
||||
}
|
||||
|
||||
bool
|
||||
InternalHeaders::IsForbiddenResponseHeader(const nsACString& aName) const
|
||||
{
|
||||
return mGuard == HeadersGuardEnum::Response &&
|
||||
nsContentUtils::IsForbiddenResponseHeader(aName);
|
||||
}
|
||||
|
||||
void
|
||||
InternalHeaders::Fill(const InternalHeaders& aInit, ErrorResult& aRv)
|
||||
{
|
||||
const nsTArray<Entry>& list = aInit.mList;
|
||||
for (uint32_t i = 0; i < list.Length() && !aRv.Failed(); ++i) {
|
||||
const Entry& entry = list[i];
|
||||
Append(entry.mName, entry.mValue, aRv);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
InternalHeaders::Fill(const Sequence<Sequence<nsCString>>& aInit, ErrorResult& aRv)
|
||||
{
|
||||
for (uint32_t i = 0; i < aInit.Length() && !aRv.Failed(); ++i) {
|
||||
const Sequence<nsCString>& tuple = aInit[i];
|
||||
if (tuple.Length() != 2) {
|
||||
aRv.ThrowTypeError(MSG_INVALID_HEADER_SEQUENCE);
|
||||
return;
|
||||
}
|
||||
Append(tuple[0], tuple[1], aRv);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
InternalHeaders::Fill(const MozMap<nsCString>& aInit, ErrorResult& aRv)
|
||||
{
|
||||
nsTArray<nsString> keys;
|
||||
aInit.GetKeys(keys);
|
||||
for (uint32_t i = 0; i < keys.Length() && !aRv.Failed(); ++i) {
|
||||
Append(NS_ConvertUTF16toUTF8(keys[i]), aInit.Get(keys[i]), aRv);
|
||||
}
|
||||
}
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
116
dom/fetch/InternalHeaders.h
Normal file
116
dom/fetch/InternalHeaders.h
Normal file
@ -0,0 +1,116 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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_InternalHeaders_h
|
||||
#define mozilla_dom_InternalHeaders_h
|
||||
|
||||
// needed for HeadersGuardEnum.
|
||||
#include "mozilla/dom/HeadersBinding.h"
|
||||
#include "mozilla/dom/UnionTypes.h"
|
||||
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
class nsPIDOMWindow;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class ErrorResult;
|
||||
|
||||
namespace dom {
|
||||
|
||||
template<typename T> class MozMap;
|
||||
class HeadersOrByteStringSequenceSequenceOrByteStringMozMap;
|
||||
|
||||
class InternalHeaders MOZ_FINAL
|
||||
{
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(InternalHeaders)
|
||||
|
||||
private:
|
||||
struct Entry
|
||||
{
|
||||
Entry(const nsACString& aName, const nsACString& aValue)
|
||||
: mName(aName)
|
||||
, mValue(aValue)
|
||||
{ }
|
||||
|
||||
Entry() { }
|
||||
|
||||
nsCString mName;
|
||||
nsCString mValue;
|
||||
};
|
||||
|
||||
HeadersGuardEnum mGuard;
|
||||
nsTArray<Entry> mList;
|
||||
|
||||
public:
|
||||
explicit InternalHeaders(HeadersGuardEnum aGuard = HeadersGuardEnum::None)
|
||||
: mGuard(aGuard)
|
||||
{
|
||||
}
|
||||
|
||||
explicit InternalHeaders(const InternalHeaders& aOther)
|
||||
: mGuard(aOther.mGuard)
|
||||
{
|
||||
ErrorResult result;
|
||||
Fill(aOther, result);
|
||||
MOZ_ASSERT(!result.Failed());
|
||||
}
|
||||
|
||||
void Append(const nsACString& aName, const nsACString& aValue,
|
||||
ErrorResult& aRv);
|
||||
void Delete(const nsACString& aName, ErrorResult& aRv);
|
||||
void Get(const nsACString& aName, nsCString& aValue, ErrorResult& aRv) const;
|
||||
void GetAll(const nsACString& aName, nsTArray<nsCString>& aResults,
|
||||
ErrorResult& aRv) const;
|
||||
bool Has(const nsACString& aName, ErrorResult& aRv) const;
|
||||
void Set(const nsACString& aName, const nsACString& aValue, ErrorResult& aRv);
|
||||
|
||||
void Clear();
|
||||
|
||||
HeadersGuardEnum Guard() const { return mGuard; }
|
||||
void SetGuard(HeadersGuardEnum aGuard, ErrorResult& aRv);
|
||||
|
||||
void Fill(const InternalHeaders& aInit, ErrorResult& aRv);
|
||||
void Fill(const Sequence<Sequence<nsCString>>& aInit, ErrorResult& aRv);
|
||||
void Fill(const MozMap<nsCString>& aInit, ErrorResult& aRv);
|
||||
private:
|
||||
virtual ~InternalHeaders();
|
||||
|
||||
static bool IsSimpleHeader(const nsACString& aName,
|
||||
const nsACString& aValue);
|
||||
static bool IsInvalidName(const nsACString& aName, ErrorResult& aRv);
|
||||
static bool IsInvalidValue(const nsACString& aValue, ErrorResult& aRv);
|
||||
bool IsImmutable(ErrorResult& aRv) const;
|
||||
bool IsForbiddenRequestHeader(const nsACString& aName) const;
|
||||
bool IsForbiddenRequestNoCorsHeader(const nsACString& aName) const;
|
||||
bool IsForbiddenRequestNoCorsHeader(const nsACString& aName,
|
||||
const nsACString& aValue) const;
|
||||
bool IsForbiddenResponseHeader(const nsACString& aName) const;
|
||||
|
||||
bool IsInvalidMutableHeader(const nsACString& aName,
|
||||
ErrorResult& aRv) const
|
||||
{
|
||||
return IsInvalidMutableHeader(aName, EmptyCString(), aRv);
|
||||
}
|
||||
|
||||
bool IsInvalidMutableHeader(const nsACString& aName,
|
||||
const nsACString& aValue,
|
||||
ErrorResult& aRv) const
|
||||
{
|
||||
return IsInvalidName(aName, aRv) ||
|
||||
IsInvalidValue(aValue, aRv) ||
|
||||
IsImmutable(aRv) ||
|
||||
IsForbiddenRequestHeader(aName) ||
|
||||
IsForbiddenRequestNoCorsHeader(aName, aValue) ||
|
||||
IsForbiddenResponseHeader(aName);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_InternalHeaders_h
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user