Merge m-c to b2g-inbound

This commit is contained in:
Carsten "Tomcat" Book 2014-10-16 16:16:53 +02:00
commit 2c80c4d658
418 changed files with 6612 additions and 7884 deletions

View File

@ -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;
}

View File

@ -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);

View File

@ -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&#38;ref=firefox_about&#38;utm_campaign=firefox_about&#38;tm_source=firefox&#38;tm_medium=referral&#38;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>

View File

@ -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);
}
};

View File

@ -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();
}

View File

@ -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>

View File

@ -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]

View File

@ -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,

View File

@ -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)

View File

@ -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) {

View File

@ -33,6 +33,9 @@ DIRS += [
'webide',
]
if CONFIG['MOZ_DEVTOOLS_PERFTOOLS']:
DIRS += ['performance']
EXTRA_COMPONENTS += [
'devtools-clhandler.js',
'devtools-clhandler.manifest',

View 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'
]

View 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;
})
};

View 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);
}

View 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>

View File

@ -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]

View File

@ -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();
}

View File

@ -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">

View File

@ -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

View File

@ -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;
}

View File

@ -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) {

View File

@ -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");

View File

@ -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

View File

@ -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)

View 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

View File

@ -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)

View 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;
}

View 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

View File

@ -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)

View File

@ -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

View File

@ -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 =========================================================

View File

@ -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);
}

View File

@ -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

View File

@ -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);

View File

@ -112,7 +112,6 @@ UNIFIED_SOURCES += [
'nsAttrValue.cpp',
'nsAttrValueOrString.cpp',
'nsCCUncollectableMarker.cpp',
'nsChannelPolicy.cpp',
'nsContentAreaDragDrop.cpp',
'nsContentIterator.cpp',
'nsContentList.cpp',

View File

@ -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"

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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___ */

View File

@ -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);
}

View File

@ -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);

View File

@ -1330,7 +1330,6 @@ nsExternalResourceMap::PendingLoad::StartLoad(nsIURI* aURI,
aRequestingNode,
nsILoadInfo::SEC_NORMAL,
nsIContentPolicy::TYPE_OTHER,
nullptr, // aChannelPolicy
loadGroup,
req); // aCallbacks

View File

@ -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 |

View File

@ -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 |

View File

@ -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);

View File

@ -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);

View File

@ -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]

View File

@ -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 |

View File

@ -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));

View File

@ -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);
}
}

View File

@ -1516,7 +1516,6 @@ nsHTMLDocument::Open(JSContext* cx,
callerDoc,
nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL,
nsIContentPolicy::TYPE_OTHER,
nullptr, // aChannelPolicy
group);
if (rv.Failed()) {

View File

@ -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()

View File

@ -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))

View File

@ -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();
}

View File

@ -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)

View File

@ -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

View File

@ -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]

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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();
}

View File

@ -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

View File

@ -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();

View File

@ -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)) {

View File

@ -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.

View File

@ -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);

View File

@ -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

View File

@ -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) {

View File

@ -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);

View File

@ -75,7 +75,7 @@ public:
void Delete(const nsAString& aName);
void Stringify(nsString& aRetval)
void Stringify(nsString& aRetval) const
{
Serialize(aRetval);
}

View File

@ -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.")

View File

@ -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;

View File

@ -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 {

View File

@ -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.

View File

@ -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);

View File

@ -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:

View File

@ -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);
}
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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,

View File

@ -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
{

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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"
}
}
}

View File

@ -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>

View 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>

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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,

View File

@ -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

View 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>

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View 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
View 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