Merge mozilla-central to autoland

This commit is contained in:
arthur.iakab 2018-01-26 02:31:18 +02:00
Родитель 21f1825514 94ab855658
Коммит 39d63fc827
190 изменённых файлов: 3059 добавлений и 1588 удалений

Просмотреть файл

@ -318,8 +318,8 @@
];
this.invoke = function insertReferredElm_invoke() {
this.containerNode.innerHTML =
"<span id='insertReferredElms_span'></span><input aria-labelledby='insertReferredElms_span'>";
this.containerNode.unsafeSetInnerHTML(
"<span id='insertReferredElms_span'></span><input aria-labelledby='insertReferredElms_span'>");
};
this.getID = function insertReferredElm_getID() {

Просмотреть файл

@ -1,18 +1,6 @@
<?xml version='1.0' encoding='UTF-8'?>
<blocklist lastupdate="1500496563565" xmlns="http://www.mozilla.org/2006/addons-blocklist">
<emItems>
<emItem blockID="i988" id="{b12785f5-d8d0-4530-a3ea-5c4263b85bef}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
<emItem blockID="i398" id="{377e5d4d-77e5-476a-8716-7e70a9272da0}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
<emItem blockID="i698" id="{6b2a75c8-6e2e-4267-b955-43e25b54e575}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
<emItem blockID="i1231" id="youtube@downloader.yt">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
@ -137,6 +125,10 @@
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
<emItem blockID="2d4fe65b-6c02-4461-baa8-dda52e688cf6" id="/^({618baeb9-e694-4c7b-9328-69f35b6a8839}|{b91fcda4-88b0-4a10-9015-9365e5340563}|{04150f98-2d7c-4ae2-8979-f5baa198a577}|{4b1050c6-9139-4126-9331-30a836e75db9}|{1e6f5a54-2c4f-4597-aa9e-3e278c617d38}|{e73854da-9503-423b-ab27-fafea2fbf443}|{a2427e23-d349-4b25-b5b8-46960b218079}|{f92c1155-97b3-40f4-9d5b-7efa897524bb}|{c8e14311-4b2d-4eb0-9a6b-062c6912f50e}|{45621564-b408-4c29-8515-4cf1f26e4bc3}|{27380afd-f42a-4c25-b57d-b9012e0d5d48})$/">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i524" id="/^({4e988b08-8c51-45c1-8d74-73e0c8724579}|{93ec97bf-fe43-4bca-a735-5c5d6a0a40c4}|{aed63b38-7428-4003-a052-ca6834d8bad3}|{0b5130a9-cc50-4ced-99d5-cda8cc12ae48}|{C4CFC0DE-134F-4466-B2A2-FF7C59A8BFAD})$/">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
@ -526,6 +518,10 @@
<prefs/>
<versionRange minVersion="0" maxVersion="2.0.6" severity="1"/>
</emItem>
<emItem blockID="750aa293-3742-46b5-8761-51536afecaef" id="/^({30972e0a-f613-4c46-8c87-2e59878e7180}|{0599211f-6314-4bf9-854b-84cb18da97f8}|{4414af84-1e1f-449b-ac85-b79f812eb69b}|{2a8bec00-0ab0-4b4d-bd3d-4f59eada8fd8}|{bea8866f-01f8-49e9-92cd-61e96c05d288}|{046258c9-75c5-429d-8d5b-386cfbadc39d}|{c5d359ff-ae01-4f67-a4f7-bf234b5afd6e}|{fdc0601f-1fbb-40a5-84e1-8bbe96b22502}|{85349ea6-2b5d-496a-9379-d4be82c2c13d}|{640c40e5-a881-4d16-a4d0-6aa788399dd2}|{d42328e1-9749-46ba-b35c-cce85ddd4ace})$/">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i768" id="{f2548724-373f-45fe-be6a-3a85e87b7711}">
<prefs>
<pref>browser.startup.homepage</pref>
@ -722,6 +718,10 @@
<prefs/>
<versionRange minVersion="2.2" maxVersion="2.2" severity="1"/>
</emItem>
<emItem blockID="9a3fd797-0ab8-4286-9a1b-2b6c97f9075b" id="/^({4dac7c77-e117-4cae-a9f0-6bd89e9e26ab}|{cc689da4-203f-4a0c-a7a6-a00a5abe74c5}|{0eb4672d-58a6-4230-b74c-50ca3716c4b0}|{06a71249-ef35-4f61-b2c8-85c3c6ee5617}|{5280684d-f769-43c9-8eaa-fb04f7de9199}|{c2341a34-a3a0-4234-90cf-74df1db0aa49}|{85e31e7e-3e3a-42d3-9b7b-0a2ff1818b33}|{b5a35d05-fa28-41b5-ae22-db1665f93f6b}|{1bd8ba17-b3ed-412e-88db-35bc4d8771d7}|{a18087bb-4980-4349-898c-ca1b7a0e59cd}|{488e190b-d1f6-4de8-bffb-0c90cc805b62})$/">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i109" id="{392e123b-b691-4a5e-b52f-c4c1027e749c}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
@ -1246,6 +1246,10 @@
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="5c092b0d-7205-43a1-aa75-b7a42372fb52" id="/^({2bb68b03-b528-4133-9fc4-4980fbb4e449}|{231e58ac-0f3c-460b-bb08-0e589360bec7}|{a506c5af-0f95-4107-86f8-3de05e2794c9}|{8886a262-1c25-490b-b797-2e750dd9f36b}|{65072bef-041f-492e-8a51-acca2aaeac70}|{6fa41039-572b-44a4-acd4-01fdaebf608d}|{87ba49bd-daba-4071-aedf-4f32a7e63dbe}|{95d58338-ba6a-40c8-93fd-05a34731dc0e}|{4cbef3f0-4205-4165-8871-2844f9737602}|{1855d130-4893-4c79-b4aa-cbdf6fee86d3}|{87dcb9bf-3a3e-4b93-9c85-ba750a55831a})$/">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="8088b39a-3e6d-4a17-a22f-3f95c0464bd6" id="{5b0f6d3c-10fd-414c-a135-dffd26d7de0f}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
@ -1398,6 +1402,10 @@
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
<emItem blockID="aae78cd5-6b26-472e-ab2d-db4105911250" id="/^({f6df4ef7-14bd-43b5-90c9-7bd02943789c}|{ccb7b5d6-a567-40a2-9686-a097a8b583dd}|{9b8df895-fcdd-452a-8c46-da5be345b5bc}|{5cf77367-b141-4ba4-ac2a-5b2ca3728e81}|{ada56fe6-f6df-4517-9ed0-b301686a34cc}|{95c7ae97-c87e-4827-a2b7-7b9934d7d642}|{e7b978ae-ffc2-4998-a99d-0f4e2f24da82}|{115a8321-4414-4f4c-aee6-9f812121b446}|{bf153de7-cdf2-4554-af46-29dabfb2aa2d}|{179710ba-0561-4551-8e8d-1809422cb09f}|{9d592fd5-e655-461a-9b28-9eba85d4c97f})$/">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i77" id="{fa277cfc-1d75-4949-a1f9-4ac8e41b2dfd}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
@ -1681,6 +1689,10 @@
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
<emItem blockID="c92f2a05-73eb-454e-9583-f6d2382d8bca" id="/^({abec23c3-478f-4a5b-8a38-68ccd500ec42}|{a83c1cbb-7a41-41e7-a2ae-58efcb4dc2e4}|{62237447-e365-487e-8fc3-64ddf37bdaed}|{b12cfdc7-3c69-43cb-a3fb-38981b68a087}|{1a927d5b-42e7-4407-828a-fdc441d0daae}|{dd1cb0ec-be2a-432b-9c90-d64c824ac371}|{82c8ced2-e08c-4d6c-a12b-3e8227d7fc2a}|{87c552f9-7dbb-421b-8deb-571d4a2d7a21})$/">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="595e0e53-b76b-4188-a160-66f29c636094" id="@68eba425-7a05-4d62-82b1-1d6d5a51716b">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
@ -2024,6 +2036,10 @@
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="a29aed6f-6546-4fa2-8131-df5c9a5427af" id="/^({d03b6b0f-4d44-4666-a6d6-f16ad9483593}|{767d394a-aa77-40c9-9365-c1916b4a2f84}|{a0ce2605-b5fc-4265-aa65-863354e85058}|{b7f366fa-6c66-46bf-8df2-797c5e52859f}|{4ad16913-e5cb-4292-974c-d557ef5ec5bb}|{3c3ef2a3-0440-4e77-9e3c-1ca8d48f895c}|{543f7503-3620-4f41-8f9e-c258fdff07e9}|{98363f8b-d070-47b6-acc6-65b80acac4f3}|{5af74f5a-652b-4b83-a2a9-f3d21c3c0010}|{484e0ba4-a20b-4404-bb1b-b93473782ae0}|{b99847d6-c932-4b52-9650-af83c9dae649})$/">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i656" id="hdv@vovcacik.addons.mozilla.org">
<prefs/>
<versionRange minVersion="102.0" maxVersion="102.0" severity="3"/>
@ -2171,6 +2187,18 @@
</targetApplication>
</versionRange>
</emItem>
<emItem blockID="i988" id="{b12785f5-d8d0-4530-a3ea-5c4263b85bef}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
<emItem blockID="i398" id="{377e5d4d-77e5-476a-8716-7e70a9272da0}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
<emItem blockID="i698" id="{6b2a75c8-6e2e-4267-b955-43e25b54e575}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
</emItems>
<pluginItems>
<pluginItem blockID="p416">
@ -2282,7 +2310,7 @@
<versionRange maxVersion="*" minVersion="0"/>
</pluginItem>
<pluginItem blockID="33147281-45b2-487e-9fea-f66c6517252d">
<match exp="Java\(TM\) Platform SE 8 U(7[6-9]|[8-9]\d|1([0-3]\d|40))(\s[^\d\._U]|$)" name="name"/>
<match exp="Java\(TM\) Platform SE 8 U(7[6-9]|[8-9]\d|1([0-5]\d|60))(\s[^\d\._U]|$)" name="name"/>
<match exp="npjp2\.dll" name="filename"/>
<infoURL>https://java.com/</infoURL>
<versionRange severity="0" vulnerabilitystatus="1"/>
@ -2624,7 +2652,7 @@
<versionRange severity="0" vulnerabilitystatus="1"/>
</pluginItem>
<pluginItem blockID="ab59635e-2e93-423a-9d57-871dde8ae675">
<match exp="Java(\(TM\))? Plug-in 11\.(7[6-9]|[8-9]\d|1([0-3]\d|40))(\.\d+)?([^\d\._]|$)" name="name"/>
<match exp="Java(\(TM\))? Plug-in 11\.(7[6-9]|[8-9]\d|1([0-5]\d|60))(\.\d+)?([^\d\._]|$)" name="name"/>
<match exp="libnpjp2\.so" name="filename"/>
<infoURL>https://java.com/</infoURL>
<versionRange severity="0" vulnerabilitystatus="1"/>
@ -2884,7 +2912,7 @@
<pluginItem blockID="f24ffd6f-e02b-4cf4-91d9-d54cd793e4bf">
<match exp="JavaAppletPlugin\.plugin" name="filename"/>
<infoURL>https://java.com/</infoURL>
<versionRange maxVersion="Java 8 Update 140" minVersion="Java 8 Update" severity="0" vulnerabilitystatus="1"/>
<versionRange maxVersion="Java 8 Update 160" minVersion="Java 8 Update" severity="0" vulnerabilitystatus="1"/>
</pluginItem>
<pluginItem blockID="p906">
<match exp="Java\(TM\) Platform SE 7 U(4[5-9]|(5|6)\d|7[0-8])(\s[^\d\._U]|$)" name="name"/>

Просмотреть файл

@ -136,7 +136,6 @@ var BrowserPageActions = {
if (action.subview) {
buttonNode.classList.add("subviewbutton-nav");
panelViewNode = this._makePanelViewNodeForAction(action, false);
this.multiViewNode._panelViews = null;
this.multiViewNode.appendChild(panelViewNode);
}
buttonNode.addEventListener("command", event => {
@ -236,6 +235,7 @@ var BrowserPageActions = {
if (action.subview) {
let multiViewNode = document.createElement("panelmultiview");
panelViewNode = this._makePanelViewNodeForAction(action, true);
multiViewNode.setAttribute("mainViewId", panelViewNode.id);
multiViewNode.appendChild(panelViewNode);
panelNode.appendChild(multiViewNode);
} else if (action.wantsIframe) {
@ -291,11 +291,15 @@ var BrowserPageActions = {
*
* @param action (PageActions.Action, optional)
* The action you want to anchor.
* @param event (DOM event, optional)
* This is used to display the feedback panel on the right node when
* the command can be invoked from both the main panel and another
* location, such as an activated action panel or a button.
* @return (DOM node, nonnull) The node to which the action should be
* anchored.
*/
panelAnchorNodeForAction(action, event) {
if (event && event.target.closest("panel")) {
if (event && event.target.closest("panel") == this.panelNode) {
return this.mainButtonNode;
}

Просмотреть файл

@ -41,6 +41,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
NewTabUtils: "resource://gre/modules/NewTabUtils.jsm",
PageActions: "resource:///modules/PageActions.jsm",
PageThumbs: "resource://gre/modules/PageThumbs.jsm",
PanelView: "resource:///modules/PanelMultiView.jsm",
PluralForm: "resource://gre/modules/PluralForm.jsm",
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
ProcessHangMonitor: "resource:///modules/ProcessHangMonitor.jsm",
@ -7144,21 +7145,19 @@ var gIdentityHandler = {
delete this._identityPopupMultiView;
return this._identityPopupMultiView = document.getElementById("identity-popup-multiView");
},
get _identityPopupMainView() {
delete this._identityPopupMainView;
return this._identityPopupMainView = document.getElementById("identity-popup-mainView");
},
get _identityPopupContentHosts() {
delete this._identityPopupContentHosts;
let selector = ".identity-popup-host";
return this._identityPopupContentHosts = [
...this._identityPopupMultiView._mainView.querySelectorAll(selector),
...document.querySelectorAll(selector)
];
return this._identityPopupContentHosts =
[...document.querySelectorAll(".identity-popup-host")];
},
get _identityPopupContentHostless() {
delete this._identityPopupContentHostless;
let selector = ".identity-popup-hostless";
return this._identityPopupContentHostless = [
...this._identityPopupMultiView._mainView.querySelectorAll(selector),
...document.querySelectorAll(selector)
];
return this._identityPopupContentHostless =
[...document.querySelectorAll(".identity-popup-hostless")];
},
get _identityPopupContentOwner() {
delete this._identityPopupContentOwner;
@ -7400,7 +7399,8 @@ var gIdentityHandler = {
if (this._identityPopup.state == "open") {
this.updateSitePermissions();
this._identityPopupMultiView.descriptionHeightWorkaround();
PanelView.forNode(this._identityPopupMainView)
.descriptionHeightWorkaround();
}
},
@ -8056,7 +8056,8 @@ var gIdentityHandler = {
SitePermissions.remove(gBrowser.currentURI, aPermission.id, browser);
this._permissionReloadHint.removeAttribute("hidden");
this._identityPopupMultiView.descriptionHeightWorkaround();
PanelView.forNode(this._identityPopupMainView)
.descriptionHeightWorkaround();
// Set telemetry values for clearing a permission
let histogram = Services.telemetry.getKeyedHistogramById("WEB_PERMISSION_CLEARED");

Просмотреть файл

@ -58,6 +58,7 @@ const EXPECTED_APPMENU_SUBVIEW_REFLOWS = [
{
stack: [
"descriptionHeightWorkaround@resource:///modules/PanelMultiView.jsm",
"set current@resource:///modules/PanelMultiView.jsm",
"hideAllViewsExcept@resource:///modules/PanelMultiView.jsm",
],

Просмотреть файл

@ -10,7 +10,7 @@ add_task(async function test_reserved_shortcuts() {
</keyset>`;
let container = document.createElement("box");
container.innerHTML = keyset;
container.unsafeSetInnerHTML(keyset);
document.documentElement.appendChild(container);
/* eslint-enable no-unsanitized/property */

Просмотреть файл

@ -131,6 +131,11 @@ add_task(async function copyURLFromPanel() {
// does not appear on about:blank for example.)
let url = "http://example.com/";
await BrowserTestUtils.withNewTab(url, async () => {
// Add action to URL bar.
let action = PageActions._builtInActions.find(a => a.id == "copyURL");
action.pinnedToUrlbar = true;
registerCleanupFunction(() => action.pinnedToUrlbar = false);
// Open the panel and click Copy URL.
await promisePageActionPanelOpen();
Assert.ok(true, "page action panel opened");
@ -147,6 +152,8 @@ add_task(async function copyURLFromPanel() {
Assert.equal(feedbackPanel.anchorNode.id, "pageActionButton", "Feedback menu should be anchored on the main Page Action button");
let feedbackHiddenPromise = promisePanelHidden("pageActionFeedback");
await feedbackHiddenPromise;
action.pinnedToUrlbar = false;
});
});
@ -170,6 +177,8 @@ add_task(async function copyURLFromURLBar() {
Assert.equal(panel.anchorNode.id, "pageAction-urlbar-copyURL", "Feedback menu should be anchored on the main URL bar button");
let feedbackHiddenPromise = promisePanelHidden("pageActionFeedback");
await feedbackHiddenPromise;
action.pinnedToUrlbar = false;
});
});

Просмотреть файл

@ -14,6 +14,7 @@ Cu.import("resource://gre/modules/AppConstants.jsm");
XPCOMUtils.defineLazyModuleGetters(this, {
BrowserUITelemetry: "resource:///modules/BrowserUITelemetry.jsm",
PanelView: "resource:///modules/PanelMultiView.jsm",
PlacesUtils: "resource://gre/modules/PlacesUtils.jsm",
PlacesUIUtils: "resource:///modules/PlacesUIUtils.jsm",
RecentlyClosedTabsAndWindowsMenuUtils: "resource:///modules/sessionstore/RecentlyClosedTabsAndWindowsMenuUtils.jsm",
@ -366,8 +367,8 @@ const CustomizableWidgets = [
}
}
this._tabsList.appendChild(fragment);
let panelView = this._tabsList.closest("panelview");
panelView.panelMultiView.descriptionHeightWorkaround(panelView);
PanelView.forNode(this._tabsList.closest("panelview"))
.descriptionHeightWorkaround();
}).catch(err => {
Cu.reportError(err);
}).then(() => {

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -163,19 +163,6 @@ const PanelUI = {
this.libraryView.removeEventListener("ViewShowing", this);
},
/**
* Customize mode extracts the mainView and puts it somewhere else while the
* user customizes. Upon completion, this function can be called to put the
* panel back to where it belongs in normal browsing mode.
*
* @param aMainView
* The mainView node to put back into place.
*/
setMainView(aMainView) {
this._ensureEventListenersAdded();
this.multiView.setMainView(aMainView);
},
/**
* Opens the menu panel if it's closed, or closes it if it's
* open.

Просмотреть файл

@ -30,7 +30,8 @@
<implementation>
<constructor><![CDATA[
const {PanelMultiView} = Components.utils.import("resource:///modules/PanelMultiView.jsm", {});
this.instance = new PanelMultiView(this);
this.instance = PanelMultiView.forNode(this);
this.instance.connect();
]]></constructor>
<destructor><![CDATA[

Просмотреть файл

@ -4,20 +4,15 @@
* Test keyboard navigation in the app menu panel.
*/
const {PanelMultiView} = Cu.import("resource:///modules/PanelMultiView.jsm", {});
const {PanelView} = Cu.import("resource:///modules/PanelMultiView.jsm", {});
const kHelpButtonId = "appMenu-help-button";
let gHelperInstance;
add_task(async function setup() {
gHelperInstance = new PanelMultiView(PanelUI.panel, true);
});
add_task(async function testUpDownKeys() {
let promise = promisePanelShown(window);
PanelUI.show();
await promise;
let buttons = gHelperInstance._getNavigableElements(PanelUI.mainView);
let buttons = PanelView.forNode(PanelUI.mainView).getNavigableElements();
for (let button of buttons) {
if (button.disabled)
@ -50,7 +45,7 @@ add_task(async function testEnterKeyBehaviors() {
PanelUI.show();
await promise;
let buttons = gHelperInstance._getNavigableElements(PanelUI.mainView);
let buttons = PanelView.forNode(PanelUI.mainView).getNavigableElements();
// Navigate to the 'Help' button, which points to a subview.
EventUtils.synthesizeKey("KEY_ArrowUp", { code: "ArrowUp" });
@ -67,7 +62,7 @@ add_task(async function testEnterKeyBehaviors() {
EventUtils.synthesizeKey("VK_RETURN", { code: "Enter" });
await promise;
let helpButtons = gHelperInstance._getNavigableElements(PanelUI.helpView);
let helpButtons = PanelView.forNode(PanelUI.helpView).getNavigableElements();
Assert.ok(helpButtons[0].classList.contains("subviewbutton-back"),
"First button in help view should be a back button");
@ -147,7 +142,7 @@ add_task(async function testTabKey() {
PanelUI.show();
await promise;
let buttons = gHelperInstance._getNavigableElements(PanelUI.mainView);
let buttons = PanelView.forNode(PanelUI.mainView).getNavigableElements();
for (let button of buttons) {
if (button.disabled)
@ -184,7 +179,7 @@ add_task(async function testInterleavedTabAndArrowKeys() {
PanelUI.show();
await promise;
let buttons = gHelperInstance._getNavigableElements(PanelUI.mainView);
let buttons = PanelView.forNode(PanelUI.mainView).getNavigableElements();
let tab = false;
for (let button of buttons) {
@ -211,7 +206,7 @@ add_task(async function testSpaceDownAfterTabNavigation() {
PanelUI.show();
await promise;
let buttons = gHelperInstance._getNavigableElements(PanelUI.mainView);
let buttons = PanelView.forNode(PanelUI.mainView).getNavigableElements();
let button;
for (button of buttons) {

Просмотреть файл

@ -407,13 +407,15 @@ var gPrivacyPane = {
document.getElementById("drmGroup").setAttribute("style", "display: none !important");
}
this.initDataCollection();
if (AppConstants.MOZ_CRASHREPORTER) {
this.initSubmitCrashes();
if (AppConstants.MOZ_DATA_REPORTING) {
this.initDataCollection();
if (AppConstants.MOZ_CRASHREPORTER) {
this.initSubmitCrashes();
}
this.initSubmitHealthReport();
setEventListener("submitHealthReportBox", "command",
gPrivacyPane.updateSubmitHealthReport);
}
this.initSubmitHealthReport();
setEventListener("submitHealthReportBox", "command",
gPrivacyPane.updateSubmitHealthReport);
this._initA11yState();
let signonBundle = document.getElementById("signonBundle");
let pkiBundle = document.getElementById("pkiBundle");

Просмотреть файл

@ -206,7 +206,6 @@ var SessionStorageInternal = {
let usage = window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils)
.getStorageUsage(storage);
Services.telemetry.getHistogramById("FX_SESSION_RESTORE_DOM_STORAGE_SIZE_ESTIMATE_CHARS").add(usage);
if (usage > Services.prefs.getIntPref(DOM_STORAGE_LIMIT_PREF)) {
return hostData;
}

Просмотреть файл

@ -620,7 +620,6 @@ var SessionStorageListener = {
let usage = content.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils)
.getStorageUsage(event.storageArea);
Services.telemetry.getHistogramById("FX_SESSION_RESTORE_DOM_STORAGE_SIZE_ESTIMATE_CHARS").add(usage);
// Don't store any data if we exceed the limit. Wipe any data we previously
// collected so that we don't confuse websites with partial state.

Просмотреть файл

@ -10,47 +10,6 @@ const URL = "http://mochi.test:8888/browser/" +
const OUTER_VALUE = "outer-value-" + RAND;
function getEstimateChars() {
let snap;
if (gMultiProcessBrowser) {
snap = Services.telemetry.snapshotHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
false /* subsession */,
false /* clear */).content.FX_SESSION_RESTORE_DOM_STORAGE_SIZE_ESTIMATE_CHARS;
} else {
snap = Services.telemetry.snapshotHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
false,
false).parent.FX_SESSION_RESTORE_DOM_STORAGE_SIZE_ESTIMATE_CHARS;
}
if (!snap) {
return 0;
}
return snap.counts[4];
}
// Test that we record the size of messages.
add_task(async function test_telemetry() {
Services.telemetry.canRecordExtended = true;
let prev = getEstimateChars();
let tab = BrowserTestUtils.addTab(gBrowser, URL);
let browser = tab.linkedBrowser;
await promiseBrowserLoaded(browser);
// Flush to make sure we submitted telemetry data.
await TabStateFlusher.flush(browser);
// There is no good way to make sure that the parent received the histogram entries from the child processes.
// Let's stick to the ugly, spinning the event loop until we have a good approach (Bug 1357509).
await BrowserTestUtils.waitForCondition(() => {
return getEstimateChars() > prev;
});
Assert.ok(true);
await promiseRemoveTab(tab);
Services.telemetry.canRecordExtended = false;
});
// Lower the size limit for DOM Storage content. Check that DOM Storage
// is not updated, but that other things remain updated.
add_task(async function test_large_content() {

Просмотреть файл

@ -75,7 +75,6 @@
.requests-list-column {
display: table-cell;
cursor: default;
text-align: center;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
@ -548,9 +547,6 @@
}
.requests-list-timings {
display: flex;
flex: none;
align-items: center;
transform: scaleX(var(--timings-scale));
}
@ -608,6 +604,7 @@
white-space: nowrap;
/* This node should not be scaled - apply a reversed transformation */
transform: scaleX(var(--timings-rev-scale));
text-align: left;
}
.requests-list-timings-total:dir(ltr) {

Просмотреть файл

@ -89,11 +89,14 @@ function requestsReducer(state = Requests(), action) {
...request,
...processNetworkUpdates(action.data),
};
let requestEndTime = request.startedMillis +
(request.eventTimings ? request.eventTimings.totalTime : 0);
return {
...state,
requests: mapSet(state.requests, action.id, request),
lastEndedMillis: lastEndedMillis,
lastEndedMillis: requestEndTime > lastEndedMillis ?
requestEndTime : lastEndedMillis,
};
}

Просмотреть файл

@ -27,8 +27,11 @@ const getWaterfallScale = createSelector(
timingMarkers.firstDocumentDOMContentLoadedTimestamp,
timingMarkers.firstDocumentLoadTimestamp);
const longestWidth = lastEventMillis - requests.firstStartedMillis;
// Reduce 20px for the last request's requests-list-timings-total
return Math.min(Math.max(
(ui.waterfallWidth - REQUESTS_WATERFALL.LABEL_WIDTH) / longestWidth, EPSILON), 1);
(ui.waterfallWidth - REQUESTS_WATERFALL.LABEL_WIDTH - 20) / longestWidth,
EPSILON), 1);
}
);

Просмотреть файл

@ -18,6 +18,12 @@ const { getToplevelWindow } = require("../utils/window");
const FRAME_SCRIPT = "resource://devtools/client/responsive.html/browser/content.js";
// Allow creation of HTML fragments without automatic sanitization, even
// though we're in a chrome-privileged document.
// This is, unfortunately, necessary in order to React to function
// correctly.
document.allowUnsafeHTML = true;
class Browser extends PureComponent {
/**
* This component is not allowed to depend directly on frequently changing

Просмотреть файл

@ -97,6 +97,10 @@ add_task(async function () {
await onPopupClose;
});
function stripNS(text) {
return text.replace(RegExp(' xmlns="http://www.w3.org/1999/xhtml"', "g"), "");
}
function checkActiveDescendant(popup, input) {
let activeElement = input.ownerDocument.activeElement;
let descendantId = activeElement.getAttribute("aria-activedescendant");
@ -105,6 +109,6 @@ function checkActiveDescendant(popup, input) {
ok(popupItem, "Active descendant is found in the popup list");
ok(cloneItem, "Active descendant is found in the list clone");
is(popupItem.outerHTML, cloneItem.outerHTML,
is(stripNS(popupItem.outerHTML), cloneItem.outerHTML,
"Cloned item has the same HTML as the original element");
}

Просмотреть файл

@ -498,10 +498,12 @@ exports.setContents = function(elem, contents) {
return;
}
if ('innerHTML' in elem) {
if ("unsafeSetInnerHTML" in elem) {
// FIXME: Stop relying on unsanitized HTML.
elem.unsafeSetInnerHTML(contents);
} else if ("innerHTML" in elem) {
elem.innerHTML = contents;
}
else {
} else {
try {
var ns = elem.ownerDocument.documentElement.namespaceURI;
if (!ns) {

Просмотреть файл

@ -18,7 +18,7 @@ add_task(function* () {
info("Create the test markup");
let div = document.createElement("div");
div.innerHTML =
div.unsafeSetInnerHTML(
`<div data-localization-bundle="devtools/client/locales/startup.properties">
<div id="d0" data-localization="content=inspector.someInvalidKey"></div>
<div id="d1" data-localization="content=inspector.label">Text will disappear</div>
@ -32,7 +32,7 @@ add_task(function* () {
<div id="d5" data-localization="content=toolbox.defaultTitle"></div>
</div>
</div>
`;
`);
info("Use localization helper to localize the test markup");
localizeMarkup(div);

Просмотреть файл

@ -10687,6 +10687,7 @@ nsDocShell::DoURILoad(nsIURI* aURI,
rv = NS_NewChannelInternal(getter_AddRefs(channel),
aURI,
loadInfo,
nullptr, // PerformanceStorage
nullptr, // loadGroup
static_cast<nsIInterfaceRequestor*>(this),
loadFlags);

Просмотреть файл

@ -109,6 +109,7 @@ SendPing(void* aClosure, nsIContent* aContent, nsIURI* aURI,
? nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED
: nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
nsIContentPolicy::TYPE_PING,
nullptr, // PerformanceStorage
nullptr, // aLoadGroup
nullptr, // aCallbacks
nsIRequest::LOAD_NORMAL, // aLoadFlags,

Просмотреть файл

@ -284,6 +284,13 @@ Attr::ComputeIndexOf(const nsINode* aPossibleChild) const
return -1;
}
nsresult
Attr::InsertChildBefore(nsIContent* aKid, nsIContent* aBeforeThis,
bool aNotify)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult
Attr::InsertChildAt_Deprecated(nsIContent* aKid, uint32_t aIndex,
bool aNotify)

Просмотреть файл

@ -64,6 +64,8 @@ public:
virtual uint32_t GetChildCount() const override;
virtual nsIContent *GetChildAt_Deprecated(uint32_t aIndex) const override;
virtual int32_t ComputeIndexOf(const nsINode* aPossibleChild) const override;
virtual nsresult InsertChildBefore(nsIContent* aKid, nsIContent* aBeforeThis,
bool aNotify) override;
virtual nsresult InsertChildAt_Deprecated(nsIContent* aKid, uint32_t aIndex,
bool aNotify) override;
virtual void RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify) override;

Просмотреть файл

@ -3927,6 +3927,12 @@ Element::SetInnerHTML(const nsAString& aInnerHTML, nsIPrincipal* aSubjectPrincip
SetInnerHTMLInternal(aInnerHTML, aError);
}
void
Element::UnsafeSetInnerHTML(const nsAString& aInnerHTML, ErrorResult& aError)
{
SetInnerHTMLInternal(aInnerHTML, aError, true);
}
void
Element::GetOuterHTML(nsAString& aOuterHTML)
{

Просмотреть файл

@ -1418,6 +1418,7 @@ public:
NS_IMETHOD GetInnerHTML(nsAString& aInnerHTML);
virtual void SetInnerHTML(const nsAString& aInnerHTML, nsIPrincipal* aSubjectPrincipal, ErrorResult& aError);
void UnsafeSetInnerHTML(const nsAString& aInnerHTML, ErrorResult& aError);
void GetOuterHTML(nsAString& aOuterHTML);
void SetOuterHTML(const nsAString& aOuterHTML, ErrorResult& aError);
void InsertAdjacentHTML(const nsAString& aPosition, const nsAString& aText,

Просмотреть файл

@ -1036,6 +1036,7 @@ EventSourceImpl::InitChannelAndRequestEventSource()
doc,
securityFlags,
nsIContentPolicy::TYPE_INTERNAL_EVENTSOURCE,
nullptr, // aPerformanceStorage
loadGroup,
nullptr, // aCallbacks
loadFlags); // aLoadFlags
@ -1046,6 +1047,7 @@ EventSourceImpl::InitChannelAndRequestEventSource()
mPrincipal,
securityFlags,
nsIContentPolicy::TYPE_INTERNAL_EVENTSOURCE,
nullptr, // aPerformanceStorage
nullptr, // loadGroup
nullptr, // aCallbacks
loadFlags); // aLoadFlags

Просмотреть файл

@ -1156,6 +1156,19 @@ nsIContent::SetXBLInsertionPoint(nsIContent* aContent)
}
}
nsresult
FragmentOrElement::InsertChildBefore(nsIContent* aKid,
nsIContent* aBeforeThis,
bool aNotify)
{
NS_PRECONDITION(aKid, "null ptr");
int32_t index = aBeforeThis ? ComputeIndexOf(aBeforeThis) : GetChildCount();
MOZ_ASSERT(index >= 0);
return doInsertChildAt(aKid, index, aNotify, mAttrsAndChildren);
}
nsresult
FragmentOrElement::InsertChildAt_Deprecated(nsIContent* aKid,
uint32_t aIndex,
@ -2274,7 +2287,8 @@ ContainsMarkup(const nsAString& aStr)
}
void
FragmentOrElement::SetInnerHTMLInternal(const nsAString& aInnerHTML, ErrorResult& aError)
FragmentOrElement::SetInnerHTMLInternal(const nsAString& aInnerHTML, ErrorResult& aError,
bool aNeverSanitize)
{
FragmentOrElement* target = this;
// Handle template case.
@ -2326,6 +2340,9 @@ FragmentOrElement::SetInnerHTMLInternal(const nsAString& aInnerHTML, ErrorResult
contextNameSpaceID = shadowRoot->GetHost()->GetNameSpaceID();
}
auto sanitize = (aNeverSanitize ? nsContentUtils::NeverSanitize
: nsContentUtils::SanitizeSystemPrivileged);
if (doc->IsHTMLDocument()) {
int32_t oldChildCount = target->GetChildCount();
aError = nsContentUtils::ParseFragmentHTML(aInnerHTML,
@ -2334,14 +2351,16 @@ FragmentOrElement::SetInnerHTMLInternal(const nsAString& aInnerHTML, ErrorResult
contextNameSpaceID,
doc->GetCompatibilityMode() ==
eCompatibility_NavQuirks,
true);
true,
sanitize);
mb.NodesAdded();
// HTML5 parser has notified, but not fired mutation events.
nsContentUtils::FireMutationEventsForDirectParsing(doc, target,
oldChildCount);
} else {
RefPtr<DocumentFragment> df =
nsContentUtils::CreateContextualFragment(target, aInnerHTML, true, aError);
nsContentUtils::CreateContextualFragment(target, aInnerHTML, true,
sanitize, aError);
if (!aError.Failed()) {
// Suppress assertion about node removal mutation events that can't have
// listeners anyway, because no one has had the chance to register mutation

Просмотреть файл

@ -120,6 +120,8 @@ public:
virtual uint32_t GetChildCount() const override;
virtual nsIContent *GetChildAt_Deprecated(uint32_t aIndex) const override;
virtual int32_t ComputeIndexOf(const nsINode* aPossibleChild) const override;
virtual nsresult InsertChildBefore(nsIContent* aKid, nsIContent* aBeforeThis,
bool aNotify) override;
virtual nsresult InsertChildAt_Deprecated(nsIContent* aKid, uint32_t aIndex,
bool aNotify) override;
virtual void RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify) override;
@ -332,7 +334,8 @@ public:
protected:
void GetMarkup(bool aIncludeSelf, nsAString& aMarkup);
void SetInnerHTMLInternal(const nsAString& aInnerHTML, ErrorResult& aError);
void SetInnerHTMLInternal(const nsAString& aInnerHTML, ErrorResult& aError,
bool aNeverSanitize = false);
// Override from nsINode
nsIContent::nsContentSlots* CreateSlots() override

Просмотреть файл

@ -1156,6 +1156,7 @@ Navigator::SendBeaconInternal(const nsAString& aUrl,
doc,
securityFlags,
nsIContentPolicy::TYPE_BEACON,
nullptr, // aPerformanceStorage
nullptr, // aLoadGroup
nullptr, // aCallbacks
loadFlags);

Просмотреть файл

@ -162,6 +162,7 @@
#include "nsIObserverService.h"
#include "nsIOfflineCacheUpdate.h"
#include "nsIParser.h"
#include "nsIParserUtils.h"
#include "nsIPermissionManager.h"
#include "nsIPluginHost.h"
#include "nsIRemoteBrowser.h"
@ -200,6 +201,7 @@
#include "nsTextFragment.h"
#include "nsTextNode.h"
#include "nsThreadUtils.h"
#include "nsTreeSanitizer.h"
#include "nsUnicodeProperties.h"
#include "nsURLHelper.h"
#include "nsViewManager.h"
@ -4959,6 +4961,7 @@ already_AddRefed<DocumentFragment>
nsContentUtils::CreateContextualFragment(nsINode* aContextNode,
const nsAString& aFragment,
bool aPreventScriptExecution,
SanitizeFragments aSanitize,
ErrorResult& aRv)
{
if (!aContextNode) {
@ -4994,14 +4997,16 @@ nsContentUtils::CreateContextualFragment(nsINode* aContextNode,
contextAsContent->GetNameSpaceID(),
(document->GetCompatibilityMode() ==
eCompatibility_NavQuirks),
aPreventScriptExecution);
aPreventScriptExecution,
aSanitize);
} else {
aRv = ParseFragmentHTML(aFragment, frag,
nsGkAtoms::body,
kNameSpaceID_XHTML,
(document->GetCompatibilityMode() ==
eCompatibility_NavQuirks),
aPreventScriptExecution);
aPreventScriptExecution,
aSanitize);
}
return frag.forget();
@ -5065,7 +5070,8 @@ nsContentUtils::CreateContextualFragment(nsINode* aContextNode,
nsCOMPtr<nsIDOMDocumentFragment> frag;
aRv = ParseFragmentXML(aFragment, document, tagStack,
aPreventScriptExecution, getter_AddRefs(frag));
aPreventScriptExecution, getter_AddRefs(frag),
aSanitize);
return frag.forget().downcast<DocumentFragment>();
}
@ -5092,7 +5098,8 @@ nsContentUtils::ParseFragmentHTML(const nsAString& aSourceBuffer,
nsAtom* aContextLocalName,
int32_t aContextNamespace,
bool aQuirks,
bool aPreventScriptExecution)
bool aPreventScriptExecution,
SanitizeFragments aSanitize)
{
AutoTimelineMarker m(aTargetNode->OwnerDoc()->GetDocShell(), "Parse HTML");
@ -5106,13 +5113,39 @@ nsContentUtils::ParseFragmentHTML(const nsAString& aSourceBuffer,
NS_ADDREF(sHTMLFragmentParser = new nsHtml5StringParser());
// Now sHTMLFragmentParser owns the object
}
nsIContent* target = aTargetNode;
// If this is a chrome-privileged document, create a fragment first, and
// sanitize it before insertion.
RefPtr<DocumentFragment> fragment;
if (aSanitize != NeverSanitize && !aTargetNode->OwnerDoc()->AllowUnsafeHTML()) {
fragment = new DocumentFragment(aTargetNode->OwnerDoc()->NodeInfoManager());
target = fragment;
}
nsresult rv =
sHTMLFragmentParser->ParseFragment(aSourceBuffer,
aTargetNode,
target,
aContextLocalName,
aContextNamespace,
aQuirks,
aPreventScriptExecution);
NS_ENSURE_SUCCESS(rv, rv);
if (fragment) {
// Don't fire mutation events for nodes removed by the sanitizer.
nsAutoScriptBlockerSuppressNodeRemoved scriptBlocker;
nsTreeSanitizer sanitizer(nsIParserUtils::SanitizerAllowStyle |
nsIParserUtils::SanitizerAllowComments);
sanitizer.Sanitize(fragment);
ErrorResult error;
aTargetNode->AppendChild(*fragment, error);
rv = error.StealNSResult();
}
return rv;
}
@ -5147,7 +5180,8 @@ nsContentUtils::ParseFragmentXML(const nsAString& aSourceBuffer,
nsIDocument* aDocument,
nsTArray<nsString>& aTagStack,
bool aPreventScriptExecution,
nsIDOMDocumentFragment** aReturn)
nsIDOMDocumentFragment** aReturn,
SanitizeFragments aSanitize)
{
AutoTimelineMarker m(aDocument->GetDocShell(), "Parse XML");
@ -5187,6 +5221,19 @@ nsContentUtils::ParseFragmentXML(const nsAString& aSourceBuffer,
sXMLFragmentParser->Reset();
// If this is a chrome-privileged document, sanitize the fragment before
// returning.
if (aSanitize != NeverSanitize && !aDocument->AllowUnsafeHTML()) {
// Don't fire mutation events for nodes removed by the sanitizer.
nsAutoScriptBlockerSuppressNodeRemoved scriptBlocker;
RefPtr<DocumentFragment> fragment = static_cast<DocumentFragment*>(*aReturn);
nsTreeSanitizer sanitizer(nsIParserUtils::SanitizerAllowStyle |
nsIParserUtils::SanitizerAllowComments);
sanitizer.Sanitize(fragment);
}
return rv;
}

Просмотреть файл

@ -1578,6 +1578,11 @@ public:
static bool IsValidNodeName(nsAtom *aLocalName, nsAtom *aPrefix,
int32_t aNamespaceID);
enum SanitizeFragments {
SanitizeSystemPrivileged,
NeverSanitize,
};
/**
* Creates a DocumentFragment from text using a context node to resolve
* namespaces.
@ -1591,6 +1596,8 @@ public:
* @param aFragment the string which is parsed to a DocumentFragment
* @param aReturn the resulting fragment
* @param aPreventScriptExecution whether to mark scripts as already started
* @param aSanitize whether the fragment should be sanitized prior to
* injection
*/
static nsresult CreateContextualFragment(nsINode* aContextNode,
const nsAString& aFragment,
@ -1599,7 +1606,16 @@ public:
static already_AddRefed<mozilla::dom::DocumentFragment>
CreateContextualFragment(nsINode* aContextNode, const nsAString& aFragment,
bool aPreventScriptExecution,
SanitizeFragments aSanitize,
mozilla::ErrorResult& aRv);
static already_AddRefed<mozilla::dom::DocumentFragment>
CreateContextualFragment(nsINode* aContextNode, const nsAString& aFragment,
bool aPreventScriptExecution,
mozilla::ErrorResult& aRv)
{
return CreateContextualFragment(aContextNode, aFragment, aPreventScriptExecution,
SanitizeSystemPrivileged, aRv);
}
/**
* Invoke the fragment parsing algorithm (innerHTML) using the HTML parser.
@ -1612,6 +1628,8 @@ public:
* @param aPreventScriptExecution true to prevent scripts from executing;
* don't set to false when parsing into a target node that has been
* bound to tree.
* @param aSanitize whether the fragment should be sanitized prior to
* injection
* @return NS_ERROR_DOM_INVALID_STATE_ERR if a re-entrant attempt to parse
* fragments is made, NS_ERROR_OUT_OF_MEMORY if aSourceBuffer is too
* long and NS_OK otherwise.
@ -1621,7 +1639,8 @@ public:
nsAtom* aContextLocalName,
int32_t aContextNamespace,
bool aQuirks,
bool aPreventScriptExecution);
bool aPreventScriptExecution,
SanitizeFragments aSanitize = SanitizeSystemPrivileged);
/**
* Invoke the fragment parsing algorithm (innerHTML) using the XML parser.
@ -1631,6 +1650,8 @@ public:
* @param aTagStack the namespace mapping context
* @param aPreventExecution whether to mark scripts as already started
* @param aReturn the result fragment
* @param aSanitize whether the fragment should be sanitized prior to
* injection
* @return NS_ERROR_DOM_INVALID_STATE_ERR if a re-entrant attempt to parse
* fragments is made, a return code from the XML parser.
*/
@ -1638,7 +1659,8 @@ public:
nsIDocument* aDocument,
nsTArray<nsString>& aTagStack,
bool aPreventScriptExecution,
nsIDOMDocumentFragment** aReturn);
nsIDOMDocumentFragment** aReturn,
SanitizeFragments aSanitize = SanitizeSystemPrivileged);
/**
* Parse a string into a document using the HTML parser.

Просмотреть файл

@ -1191,6 +1191,7 @@ nsExternalResourceMap::PendingLoad::StartLoad(nsIURI* aURI,
aRequestingNode,
nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS,
nsIContentPolicy::TYPE_OTHER,
nullptr, // aPerformanceStorage
loadGroup);
NS_ENSURE_SUCCESS(rv, rv);
@ -1483,6 +1484,7 @@ nsIDocument::nsIDocument()
mAllowPaymentRequest(false),
mEncodingMenuDisabled(false),
mIsSVGGlyphsDocument(false),
mAllowUnsafeHTML(false),
mIsScopedStyleEnabled(eScopedStyle_Unknown),
mCompatMode(eCompatibility_FullStandards),
mReadyState(ReadyState::READYSTATE_UNINITIALIZED),
@ -4362,6 +4364,21 @@ nsDocument::GetChildCount() const
return mChildren.ChildCount();
}
nsresult
nsDocument::InsertChildBefore(nsIContent* aKid, nsIContent* aBeforeThis,
bool aNotify)
{
if (aKid->IsElement() && GetRootElement()) {
NS_WARNING("Inserting root element when we already have one");
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
}
int32_t index = aBeforeThis ? ComputeIndexOf(aBeforeThis) : GetChildCount();
MOZ_ASSERT(index >= 0);
return doInsertChildAt(aKid, index, aNotify, mChildren);
}
nsresult
nsDocument::InsertChildAt_Deprecated(nsIContent* aKid, uint32_t aIndex,
bool aNotify)
@ -6187,6 +6204,13 @@ nsIDocument::CreateAttributeNS(const nsAString& aNamespaceURI,
return attribute.forget();
}
bool
nsIDocument::AllowUnsafeHTML() const
{
return (!nsContentUtils::IsSystemPrincipal(NodePrincipal()) ||
mAllowUnsafeHTML);
}
void
nsDocument::ScheduleSVGForPresAttrEvaluation(nsSVGElement* aSVG)
{
@ -6881,7 +6905,7 @@ nsDocument::SetTitle(const nsAString& aTitle)
if (!title) {
return NS_OK;
}
rootElement->InsertChildAt_Deprecated(title, 0, true);
rootElement->InsertChildBefore(title, rootElement->GetFirstChild(), true);
}
} else if (rootElement->IsHTMLElement()) {
if (!title) {

Просмотреть файл

@ -557,6 +557,8 @@ public:
virtual nsIContent *GetChildAt_Deprecated(uint32_t aIndex) const override;
virtual int32_t ComputeIndexOf(const nsINode* aPossibleChild) const override;
virtual uint32_t GetChildCount() const override;
virtual nsresult InsertChildBefore(nsIContent* aKid, nsIContent* aBeforeThis,
bool aNotify) override;
virtual nsresult InsertChildAt_Deprecated(nsIContent* aKid, uint32_t aIndex,
bool aNotify) override;
virtual void RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify) override;

Просмотреть файл

@ -651,6 +651,14 @@ nsGenericDOMDataNode::ComputeIndexOf(const nsINode* aPossibleChild) const
return -1;
}
nsresult
nsGenericDOMDataNode::InsertChildBefore(nsIContent* aKid,
nsIContent* aBeforeThis,
bool aNotify)
{
return NS_OK;
}
nsresult
nsGenericDOMDataNode::InsertChildAt_Deprecated(nsIContent* aKid,
uint32_t aIndex,
@ -755,11 +763,11 @@ nsGenericDOMDataNode::SplitData(uint32_t aOffset, nsIContent** aReturn,
nsCOMPtr<nsINode> parent = GetParentNode();
if (parent) {
int32_t insertionIndex = parent->ComputeIndexOf(this);
nsCOMPtr<nsIContent> beforeNode = this;
if (aCloneAfterOriginal) {
++insertionIndex;
beforeNode = beforeNode->GetNextSibling();
}
parent->InsertChildAt_Deprecated(newContent, insertionIndex, true);
parent->InsertChildBefore(newContent, beforeNode, true);
}
newContent.swap(*aReturn);

Просмотреть файл

@ -107,6 +107,8 @@ public:
virtual uint32_t GetChildCount() const override;
virtual nsIContent *GetChildAt_Deprecated(uint32_t aIndex) const override;
virtual int32_t ComputeIndexOf(const nsINode* aPossibleChild) const override;
virtual nsresult InsertChildBefore(nsIContent* aKid, nsIContent* aBeforeThis,
bool aNotify) override;
virtual nsresult InsertChildAt_Deprecated(nsIContent* aKid, uint32_t aIndex,
bool aNotify) override;
virtual void RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify) override;

Просмотреть файл

@ -2873,6 +2873,8 @@ public:
CreateAttributeNS(const nsAString& aNamespaceURI,
const nsAString& aQualifiedName,
mozilla::ErrorResult& rv);
void SetAllowUnsafeHTML(bool aAllow) { mAllowUnsafeHTML = aAllow; }
bool AllowUnsafeHTML() const;
void GetInputEncoding(nsAString& aInputEncoding) const;
already_AddRefed<mozilla::dom::Location> GetLocation() const;
void GetReferrer(nsAString& aReferrer) const;
@ -3556,6 +3558,10 @@ protected:
// True if this document is for an SVG-in-OpenType font.
bool mIsSVGGlyphsDocument : 1;
// True if unsafe HTML fragments should be allowed in chrome-privileged
// documents.
bool mAllowUnsafeHTML : 1;
// Whether <style scoped> support is enabled in this document.
enum { eScopedStyle_Unknown, eScopedStyle_Disabled, eScopedStyle_Enabled };
unsigned int mIsScopedStyleEnabled : 2;

Просмотреть файл

@ -717,6 +717,29 @@ public:
return isShadowRoot;
}
/**
* Insert a content node before another or at the end.
* This method handles calling BindToTree on the child appropriately.
*
* @param aKid the content to insert
* @param aBeforeThis an existing node. Use nullptr if you want to
* add aKid at the end.
* @param aNotify whether to notify the document (current document for
* nsIContent, and |this| for nsIDocument) that the insert has
* occurred
*
* @throws NS_ERROR_DOM_HIERARCHY_REQUEST_ERR if one attempts to have more
* than one element node as a child of a document. Doing this will also
* assert -- you shouldn't be doing it! Check with
* nsIDocument::GetRootElement() first if you're not sure. Apart from this
* one constraint, this doesn't do any checking on whether aKid is a valid
* child of |this|.
*
* @throws NS_ERROR_OUT_OF_MEMORY in some cases (from BindToTree).
*/
virtual nsresult InsertChildBefore(nsIContent* aKid, nsIContent* aBeforeThis,
bool aNotify) = 0;
/**
* Insert a content node at a particular index. This method handles calling
* BindToTree on the child appropriately.

Просмотреть файл

@ -2509,6 +2509,7 @@ nsObjectLoadingContent::OpenChannel()
thisContent,
securityFlags,
contentPolicyType,
nullptr, // aPerformanceStorage
group, // aLoadGroup
shim, // aCallbacks
nsIChannel::LOAD_CALL_CONTENT_SNIFFERS |

Просмотреть файл

@ -321,6 +321,7 @@ nsSyncLoadService::LoadDocument(nsIURI *aURI,
aLoaderPrincipal,
aSecurityFlags,
aContentPolicyType,
nullptr, // PerformanceStorage
aLoadGroup);
NS_ENSURE_SUCCESS(rv, rv);

Просмотреть файл

@ -25,6 +25,7 @@ support-files =
[test_copypaste.xul]
subsuite = clipboard
[test_domrequesthelper.xul]
[test_fragment_sanitization.xul]
[test_messagemanager_principal.html]
[test_messagemanager_send_principal.html]
skip-if = buildapp == 'mulet'

Просмотреть файл

@ -20,6 +20,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=683852
/** Test for Bug 683852 **/
SimpleTest.waitForExplicitFinish();
const NS_HTML = "http://www.w3.org/1999/xhtml";
function startTest() {
is(document.contains(document), true, "Document should contain itself!");
@ -48,7 +50,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=683852
document.documentElement.appendChild(pi);
document.contains(pi, true, "Document should contain processing instruction");
var df = document.createRange().createContextualFragment("<div>foo</div>");
var df = document.createRange().createContextualFragment(`<div xmlns="${NS_HTML}">foo</div>`);
is(df.contains(df.firstChild), true, "Document fragment should contain its child");
is(df.contains(df.firstChild.firstChild), true,
"Document fragment should contain its descendant");

Просмотреть файл

@ -0,0 +1,101 @@
<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1432966
-->
<window title="Mozilla Bug 1432966"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"/>
<script type="application/javascript"><![CDATA[
var { classes: Cc, interfaces: Ci } = Components;
const NS_HTML = "http://www.w3.org/1999/xhtml";
function awaitLoad(frame) {
return new Promise(resolve => {
frame.addEventListener("load", resolve, {once: true});
});
}
async function testFrame(frame, html, expected = html) {
document.querySelector("body").appendChild(frame);
await awaitLoad(frame);
// Remove the xmlns attributes that will be automatically added when we're
// in an XML document, and break the comparison.
function unNS(text) {
return text.replace(RegExp(` xmlns="${NS_HTML}"`, "g"), "");
}
let doc = frame.contentDocument;
let body = doc.body || doc.documentElement;
let div = doc.createElementNS(NS_HTML, "div");
body.appendChild(div);
div.innerHTML = html;
is(unNS(div.innerHTML), expected, "innerHTML value");
div.innerHTML = "<div></div>";
div.firstChild.outerHTML = html;
is(unNS(div.innerHTML), expected, "outerHTML value");
div.textContent = "";
div.insertAdjacentHTML("beforeend", html);
is(unNS(div.innerHTML), expected, "insertAdjacentHTML('beforeend') value");
div.innerHTML = "<a>foo</a>";
div.firstChild.insertAdjacentHTML("afterend", html);
is(unNS(div.innerHTML), "<a>foo</a>" + expected, "insertAdjacentHTML('afterend') value");
frame.remove();
}
add_task(async function test_fragment_sanitization() {
const XUL_URL = "chrome://global/content/win.xul";
const HTML_URL = "chrome://mochitests/content/chrome/dom/base/test/file_empty.html";
const HTML = '<a onclick="foo()" href="javascript:foo"><script>bar()<\/script>Meh.</a><a href="http://foo/"></a>';
const SANITIZED = '<a>Meh.</a><a href="http://foo/"></a>';
info("Test content HTML document");
{
let frame = document.createElementNS(NS_HTML, "iframe");
frame.src = "http://example.com/";
await testFrame(frame, HTML);
}
info("Test chrome HTML document");
{
let frame = document.createElementNS(NS_HTML, "iframe");
frame.src = HTML_URL;
await testFrame(frame, HTML, SANITIZED);
}
info("Test chrome XUL document");
{
let frame = document.createElementNS(NS_HTML, "iframe");
frame.src = XUL_URL;
await testFrame(frame, HTML, SANITIZED);
}
});
]]></script>
<description style="-moz-user-focus: normal; -moz-user-select: text;"><![CDATA[
hello
world
]]></description>
<body xmlns="http://www.w3.org/1999/xhtml">
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1432966"
target="_blank">Mozilla Bug 1432966</a>
</body>
</window>

Просмотреть файл

@ -18,6 +18,7 @@ NS_IMPL_CYCLE_COLLECTING_ADDREF(ConsoleInstance)
NS_IMPL_CYCLE_COLLECTING_RELEASE(ConsoleInstance)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ConsoleInstance)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_END

Просмотреть файл

@ -426,7 +426,9 @@ public:
// We don't track if a worker is spawned from a tracking script for now,
// so pass false as the last argument to FetchDriver().
fetch = new FetchDriver(mRequest, principal, loadGroup,
workerPrivate->MainThreadEventTarget(), false);
workerPrivate->MainThreadEventTarget(),
workerPrivate->GetPerformanceStorage(),
false);
nsAutoCString spec;
if (proxy->GetWorkerPrivate()->GetBaseURI()) {
proxy->GetWorkerPrivate()->GetBaseURI()->GetAsciiSpec(spec);
@ -530,7 +532,9 @@ FetchRequest(nsIGlobalObject* aGlobal, const RequestOrUSVString& aInput,
new MainThreadFetchResolver(p, observer, signal, request->MozErrors());
RefPtr<FetchDriver> fetch =
new FetchDriver(r, principal, loadGroup,
aGlobal->EventTargetFor(TaskCategory::Other), isTrackingFetch);
aGlobal->EventTargetFor(TaskCategory::Other),
nullptr, // PerformanceStorage
isTrackingFetch);
fetch->SetDocument(doc);
resolver->SetLoadGroup(loadGroup);
aRv = fetch->Fetch(signal, resolver);

Просмотреть файл

@ -31,6 +31,7 @@
#include "nsHttpChannel.h"
#include "mozilla/dom/File.h"
#include "mozilla/dom/PerformanceStorage.h"
#include "mozilla/dom/workers/Workers.h"
#include "mozilla/EventStateManager.h"
#include "mozilla/ipc/PBackgroundSharedTypes.h"
@ -325,13 +326,17 @@ NS_IMPL_ISUPPORTS(FetchDriver,
nsIStreamListener, nsIChannelEventSink, nsIInterfaceRequestor,
nsIThreadRetargetableStreamListener)
FetchDriver::FetchDriver(InternalRequest* aRequest, nsIPrincipal* aPrincipal,
nsILoadGroup* aLoadGroup, nsIEventTarget* aMainThreadEventTarget,
FetchDriver::FetchDriver(InternalRequest* aRequest,
nsIPrincipal* aPrincipal,
nsILoadGroup* aLoadGroup,
nsIEventTarget* aMainThreadEventTarget,
PerformanceStorage* aPerformanceStorage,
bool aIsTrackingFetch)
: mPrincipal(aPrincipal)
, mLoadGroup(aLoadGroup)
, mRequest(aRequest)
, mMainThreadEventTarget(aMainThreadEventTarget)
, mPerformanceStorage(aPerformanceStorage)
, mNeedToObserveOnDataAvailable(false)
, mIsTrackingFetch(aIsTrackingFetch)
#ifdef DEBUG
@ -516,6 +521,7 @@ FetchDriver::HttpFetch(const nsACString& aPreferredAlternativeDataType)
mDocument,
secFlags,
mRequest->ContentPolicyType(),
nullptr, /* aPerformanceStorage */
mLoadGroup,
nullptr, /* aCallbacks */
loadFlags,
@ -528,6 +534,7 @@ FetchDriver::HttpFetch(const nsACString& aPreferredAlternativeDataType)
mController,
secFlags,
mRequest->ContentPolicyType(),
mPerformanceStorage,
mLoadGroup,
nullptr, /* aCallbacks */
loadFlags,
@ -538,6 +545,7 @@ FetchDriver::HttpFetch(const nsACString& aPreferredAlternativeDataType)
mPrincipal,
secFlags,
mRequest->ContentPolicyType(),
mPerformanceStorage,
mLoadGroup,
nullptr, /* aCallbacks */
loadFlags,

Просмотреть файл

@ -32,6 +32,7 @@ namespace dom {
class InternalRequest;
class InternalResponse;
class PerformanceStorage;
/**
* Provides callbacks to be called when response is available or on error.
@ -109,6 +110,7 @@ public:
nsIPrincipal* aPrincipal,
nsILoadGroup* aLoadGroup,
nsIEventTarget* aMainThreadEventTarget,
PerformanceStorage* aPerformanceStorage,
bool aIsTrackingFetch);
nsresult Fetch(AbortSignal* aSignal,
@ -147,6 +149,10 @@ private:
nsCOMPtr<nsIChannel> mChannel;
nsAutoPtr<SRICheckDataVerifier> mSRIDataVerifier;
nsCOMPtr<nsIEventTarget> mMainThreadEventTarget;
// This is set only when Fetch is used in workers.
RefPtr<PerformanceStorage> mPerformanceStorage;
SRIMetadata mSRIMetadata;
nsCString mWorkerScript;

Просмотреть файл

@ -139,6 +139,39 @@ HTMLFieldSetElement::SubmitNamesValues(HTMLFormSubmission* aFormSubmission)
return NS_OK;
}
nsresult
HTMLFieldSetElement::InsertChildBefore(nsIContent* aChild,
nsIContent* aBeforeThis,
bool aNotify)
{
bool firstLegendHasChanged = false;
if (aChild->IsHTMLElement(nsGkAtoms::legend)) {
if (!mFirstLegend) {
mFirstLegend = aChild;
// We do not want to notify the first time mFirstElement is set.
} else {
// If mFirstLegend is before aIndex, we do not change it.
// Otherwise, mFirstLegend is now aChild.
int32_t index = aBeforeThis ? ComputeIndexOf(aBeforeThis) : GetChildCount();
if (index <= ComputeIndexOf(mFirstLegend)) {
mFirstLegend = aChild;
firstLegendHasChanged = true;
}
}
}
nsresult rv =
nsGenericHTMLFormElement::InsertChildBefore(aChild, aBeforeThis, aNotify);
NS_ENSURE_SUCCESS(rv, rv);
if (firstLegendHasChanged) {
NotifyElementsForFirstLegendChange(aNotify);
}
return rv;
}
nsresult
HTMLFieldSetElement::InsertChildAt_Deprecated(nsIContent* aChild,
uint32_t aIndex,

Просмотреть файл

@ -41,6 +41,8 @@ public:
nsIPrincipal* aSubjectPrincipal,
bool aNotify) override;
virtual nsresult InsertChildBefore(nsIContent* aChild, nsIContent* aBeforeThis,
bool aNotify) override;
virtual nsresult InsertChildAt_Deprecated(nsIContent* aChild, uint32_t aIndex,
bool aNotify) override;
virtual void RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify) override;

Просмотреть файл

@ -1218,6 +1218,7 @@ public:
triggeringPrincipal,
securityFlags,
contentPolicyType,
nullptr, // aPerformanceStorage
loadGroup,
nullptr, // aCallbacks
nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE_IF_BUSY |

Просмотреть файл

@ -74,6 +74,21 @@ HTMLOptGroupElement::GetSelect()
return parent;
}
nsresult
HTMLOptGroupElement::InsertChildBefore(nsIContent* aKid,
nsIContent* aBeforeThis,
bool aNotify)
{
int32_t index = aBeforeThis ? ComputeIndexOf(aBeforeThis) : GetChildCount();
SafeOptionListMutation safeMutation(GetSelect(), this, aKid, index, aNotify);
nsresult rv =
nsGenericHTMLElement::InsertChildBefore(aKid, aBeforeThis, aNotify);
if (NS_FAILED(rv)) {
safeMutation.MutationFailed();
}
return rv;
}
nsresult
HTMLOptGroupElement::InsertChildAt_Deprecated(nsIContent* aKid,
uint32_t aIndex,

Просмотреть файл

@ -25,6 +25,8 @@ public:
NS_DECL_ISUPPORTS_INHERITED
// nsINode
virtual nsresult InsertChildBefore(nsIContent* aKid, nsIContent* aBeforeThis,
bool aNotify) override;
virtual nsresult InsertChildAt_Deprecated(nsIContent* aKid, uint32_t aIndex,
bool aNotify) override;
virtual void RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify) override;

Просмотреть файл

@ -82,6 +82,37 @@ HTMLPictureElement::RemoveChildNode(nsIContent* aKid, bool aNotify)
nsGenericHTMLElement::RemoveChildNode(aKid, aNotify);
}
nsresult
HTMLPictureElement::InsertChildBefore(nsIContent* aKid, nsIContent* aBeforeThis,
bool aNotify)
{
nsresult rv =
nsGenericHTMLElement::InsertChildBefore(aKid, aBeforeThis, aNotify);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(aKid, rv);
if (aKid->IsHTMLElement(nsGkAtoms::img)) {
HTMLImageElement* img = HTMLImageElement::FromContent(aKid);
if (img) {
img->PictureSourceAdded(aKid->AsContent());
}
} else if (aKid->IsHTMLElement(nsGkAtoms::source)) {
// Find all img siblings after this <source> to notify them of its insertion
nsCOMPtr<nsIContent> nextSibling = aKid->GetNextSibling();
if (nextSibling && nextSibling->GetParentNode() == this) {
do {
HTMLImageElement* img = HTMLImageElement::FromContent(nextSibling);
if (img) {
img->PictureSourceAdded(aKid->AsContent());
}
} while ( (nextSibling = nextSibling->GetNextSibling()) );
}
}
return rv;
}
nsresult
HTMLPictureElement::InsertChildAt_Deprecated(nsIContent* aKid, uint32_t aIndex, bool aNotify)
{

Просмотреть файл

@ -25,7 +25,10 @@ public:
bool aPreallocateChildren) const override;
virtual void RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify) override;
virtual void RemoveChildNode(nsIContent* aKid, bool aNotify) override;
virtual nsresult InsertChildAt_Deprecated(nsIContent* aKid, uint32_t aIndex, bool aNotify) override;
virtual nsresult InsertChildBefore(nsIContent* aKid, nsIContent* aBeforeThis,
bool aNotify) override;
virtual nsresult InsertChildAt_Deprecated(nsIContent* aKid, uint32_t aIndex,
bool aNotify) override;
protected:
virtual ~HTMLPictureElement();

Просмотреть файл

@ -203,6 +203,22 @@ HTMLSelectElement::GetAutocompleteInfo(AutocompleteInfo& aInfo)
true);
}
nsresult
HTMLSelectElement::InsertChildBefore(nsIContent* aKid,
nsIContent* aBeforeThis,
bool aNotify)
{
int32_t index = aBeforeThis ? ComputeIndexOf(aBeforeThis) : GetChildCount();
SafeOptionListMutation safeMutation(this, this, aKid, index, aNotify);
nsresult rv =
nsGenericHTMLFormElementWithState::InsertChildBefore(aKid, aBeforeThis,
aNotify);
if (NS_FAILED(rv)) {
safeMutation.MutationFailed();
}
return rv;
}
nsresult
HTMLSelectElement::InsertChildAt_Deprecated(nsIContent* aKid,
uint32_t aIndex,

Просмотреть файл

@ -291,6 +291,8 @@ public:
EventChainPostVisitor& aVisitor) override;
virtual bool IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable, int32_t* aTabIndex) override;
virtual nsresult InsertChildBefore(nsIContent* aKid, nsIContent* aBeforeThis,
bool aNotify) override;
virtual nsresult InsertChildAt_Deprecated(nsIContent* aKid, uint32_t aIndex,
bool aNotify) override;
virtual void RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify) override;

Просмотреть файл

@ -327,6 +327,7 @@ HTMLTrackElement::LoadResource()
static_cast<Element*>(this),
secFlags,
nsIContentPolicy::TYPE_INTERNAL_TRACK,
nullptr, // PerformanceStorage
loadGroup,
nullptr, // aCallbacks
nsIRequest::LOAD_NORMAL | nsIChannel::LOAD_CLASSIFY_URI);

Просмотреть файл

@ -175,8 +175,7 @@ protected:
void UpdateChildCounts() override;
void NotifyInsert(nsIContent* aContent,
nsIContent* aChildContent,
int32_t aIndexInContainer);
nsIContent* aChildContent);
void NotifyRootInsertion();
};
@ -329,10 +328,7 @@ SinkContext::DidAddContent(nsIContent* aContent)
mStack[mStackPos - 1].mNumFlushed <
mStack[mStackPos - 1].mContent->GetChildCount()) {
nsIContent* parent = mStack[mStackPos - 1].mContent;
int32_t childIndex = mStack[mStackPos - 1].mInsertionPoint - 1;
NS_ASSERTION(parent->GetChildAt_Deprecated(childIndex) == aContent,
"Flushing the wrong child.");
mSink->NotifyInsert(parent, aContent, childIndex);
mSink->NotifyInsert(parent, aContent);
mStack[mStackPos - 1].mNumFlushed = parent->GetChildCount();
} else if (mSink->IsTimeToNotify()) {
FlushTags();
@ -397,7 +393,9 @@ SinkContext::Node::Add(nsIContent *child)
if (mInsertionPoint != -1) {
NS_ASSERTION(mNumFlushed == mContent->GetChildCount(),
"Inserting multiple children without flushing.");
mContent->InsertChildAt_Deprecated(child, mInsertionPoint++, false);
nsCOMPtr<nsIContent> nodeToInsertBefore =
mContent->GetChildAt_Deprecated(mInsertionPoint++);
mContent->InsertChildBefore(child, nodeToInsertBefore, false);
} else {
mContent->AppendChildTo(child, false);
}
@ -529,7 +527,7 @@ SinkContext::FlushTags()
NS_ASSERTION(!(mStackPos > (stackPos + 1)) ||
(child == mStack[stackPos + 1].mContent),
"Flushing the wrong child.");
mSink->NotifyInsert(content, child, childIndex);
mSink->NotifyInsert(content, child);
} else {
mSink->NotifyAppend(content, mStack[stackPos].mNumFlushed);
}
@ -849,7 +847,7 @@ HTMLContentSink::OpenBody()
uint32_t oldUpdates = mUpdatesInNotification;
mUpdatesInNotification = 0;
if (insertionPoint != -1) {
NotifyInsert(parent, mBody, insertionPoint - 1);
NotifyInsert(parent, mBody);
} else {
NotifyAppend(parent, numFlushed);
}
@ -947,8 +945,7 @@ HTMLContentSink::CloseHeadContext()
void
HTMLContentSink::NotifyInsert(nsIContent* aContent,
nsIContent* aChildContent,
int32_t aIndexInContainer)
nsIContent* aChildContent)
{
if (aContent && aContent->GetUncomposedDoc() != mDocument) {
// aContent is not actually in our document anymore.... Just bail out of
@ -983,9 +980,7 @@ HTMLContentSink::NotifyRootInsertion()
// document; in those cases we just want to put all the attrs on one
// tag.
mNotifiedRootInsertion = true;
int32_t index = mDocument->ComputeIndexOf(mRoot);
NS_ASSERTION(index != -1, "mRoot not child of document?");
NotifyInsert(nullptr, mRoot, index);
NotifyInsert(nullptr, mRoot);
// Now update the notification information in all our
// contexts, since we just inserted the root and notified on

Просмотреть файл

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

Просмотреть файл

@ -726,6 +726,7 @@ ChannelMediaResource::RecreateChannel()
triggeringPrincipal,
securityFlags,
contentPolicyType,
nullptr, // aPerformanceStorage
loadGroup,
nullptr, // aCallbacks
loadFlags);

Просмотреть файл

@ -237,7 +237,6 @@ Performance::ClearUserEntries(const Optional<nsAString>& aEntryName,
void
Performance::ClearResourceTimings()
{
MOZ_ASSERT(NS_IsMainThread());
mResourceEntries.Clear();
}
@ -431,13 +430,14 @@ void
Performance::InsertResourceEntry(PerformanceEntry* aEntry)
{
MOZ_ASSERT(aEntry);
MOZ_ASSERT(mResourceEntries.Length() < mResourceTimingBufferSize);
MOZ_ASSERT(mResourceEntries.Length() <= mResourceTimingBufferSize);
// We won't add an entry when 'privacy.resistFingerprint' is true.
if (nsContentUtils::ShouldResistFingerprinting()) {
return;
}
// Don't add the entry if the buffer is full
if (mResourceEntries.Length() >= mResourceTimingBufferSize) {
return;
}

Просмотреть файл

@ -13,7 +13,6 @@
#include "nsDOMNavigationTiming.h"
class nsITimedChannel;
class nsIHttpChannel;
namespace mozilla {
@ -25,6 +24,7 @@ class PerformanceEntry;
class PerformanceNavigation;
class PerformanceObserver;
class PerformanceService;
class PerformanceStorage;
class PerformanceTiming;
namespace workers {
@ -61,8 +61,7 @@ public:
const Optional<nsAString>& aEntryType,
nsTArray<RefPtr<PerformanceEntry>>& aRetval);
virtual void AddEntry(nsIHttpChannel* channel,
nsITimedChannel* timedChannel) = 0;
virtual PerformanceStorage* AsPerformanceStorage() = 0;
void ClearResourceTimings();
@ -101,11 +100,15 @@ public:
virtual nsITimedChannel* GetChannel() const = 0;
virtual TimeStamp CreationTimeStamp() const = 0;
void MemoryPressure();
size_t SizeOfUserEntries(mozilla::MallocSizeOf aMallocSizeOf) const;
size_t SizeOfResourceEntries(mozilla::MallocSizeOf aMallocSizeOf) const;
void InsertResourceEntry(PerformanceEntry* aEntry);
protected:
Performance();
explicit Performance(nsPIDOMWindowInner* aWindow);
@ -113,7 +116,6 @@ protected:
virtual ~Performance();
virtual void InsertUserEntry(PerformanceEntry* aEntry);
void InsertResourceEntry(PerformanceEntry* aEntry);
void ClearUserEntries(const Optional<nsAString>& aEntryName,
const nsAString& aEntryType);
@ -123,8 +125,6 @@ protected:
virtual void DispatchBufferFullEvent() = 0;
virtual TimeStamp CreationTimeStamp() const = 0;
virtual DOMHighResTimeStamp CreationTime() const = 0;
virtual bool IsPerformanceTimingAttribute(const nsAString& aName)
@ -138,11 +138,6 @@ protected:
return 0;
}
bool IsResourceEntryLimitReached() const
{
return mResourceEntries.Length() >= mResourceTimingBufferSize;
}
void LogEntry(PerformanceEntry* aEntry, const nsACString& aOwner) const;
void TimingNotification(PerformanceEntry* aEntry, const nsACString& aOwner,
uint64_t epoch);

Просмотреть файл

@ -118,64 +118,24 @@ PerformanceMainThread::AddEntry(nsIHttpChannel* channel,
{
MOZ_ASSERT(NS_IsMainThread());
// Check if resource timing is prefed off.
if (!nsContentUtils::IsResourceTimingEnabled()) {
nsAutoString initiatorType;
nsAutoString entryName;
UniquePtr<PerformanceTimingData> performanceTimingData(
PerformanceTimingData::Create(timedChannel, channel, 0, initiatorType,
entryName));
if (!performanceTimingData) {
return;
}
// Don't add the entry if the buffer is full
if (IsResourceEntryLimitReached()) {
return;
}
// The PerformanceResourceTiming object will use the PerformanceTimingData
// object to get all the required timings.
RefPtr<PerformanceResourceTiming> performanceEntry =
new PerformanceResourceTiming(Move(performanceTimingData), this,
entryName);
if (channel && timedChannel) {
nsAutoCString name;
nsAutoString initiatorType;
nsCOMPtr<nsIURI> originalURI;
timedChannel->GetInitiatorType(initiatorType);
// According to the spec, "The name attribute must return the resolved URL
// of the requested resource. This attribute must not change even if the
// fetch redirected to a different URL."
channel->GetOriginalURI(getter_AddRefs(originalURI));
originalURI->GetSpec(name);
NS_ConvertUTF8toUTF16 entryName(name);
bool reportTiming = true;
timedChannel->GetReportResourceTiming(&reportTiming);
if (!reportTiming) {
#ifdef DEBUG_jwatt
NS_WARNING(
nsPrintfCString("Not reporting CORS resource: %s", name.get()).get());
#endif
return;
}
// The nsITimedChannel argument will be used to gather all the timings.
// The nsIHttpChannel argument will be used to check if any cross-origin
// redirects occurred.
// The last argument is the "zero time" (offset). Since we don't want
// any offset for the resource timing, this will be set to "0" - the
// resource timing returns a relative timing (no offset).
RefPtr<PerformanceTiming> performanceTiming =
new PerformanceTiming(this, timedChannel, channel,
0);
// The PerformanceResourceTiming object will use the PerformanceTiming
// object to get all the required timings.
RefPtr<PerformanceResourceTiming> performanceEntry =
new PerformanceResourceTiming(performanceTiming, this, entryName, channel);
// If the initiator type had no valid value, then set it to the default
// ("other") value.
if (initiatorType.IsEmpty()) {
initiatorType = NS_LITERAL_STRING("other");
}
performanceEntry->SetInitiatorType(initiatorType);
InsertResourceEntry(performanceEntry);
}
performanceEntry->SetInitiatorType(initiatorType);
InsertResourceEntry(performanceEntry);
}
// To be removed once bug 1124165 lands
@ -325,11 +285,15 @@ void
PerformanceMainThread::EnsureDocEntry()
{
if (!mDocEntry && nsContentUtils::IsPerformanceNavigationTimingEnabled()) {
UniquePtr<PerformanceTimingData> timing(
new PerformanceTimingData(mChannel, nullptr, 0));
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(mChannel);
RefPtr<PerformanceTiming> timing =
new PerformanceTiming(this, mChannel, nullptr, 0);
mDocEntry = new PerformanceNavigationTiming(timing, this,
httpChannel);
if (httpChannel) {
timing->SetPropertiesFromHttpChannel(httpChannel);
}
mDocEntry = new PerformanceNavigationTiming(Move(timing), this);
}
}

Просмотреть файл

@ -8,11 +8,13 @@
#define mozilla_dom_PerformanceMainThread_h
#include "Performance.h"
#include "PerformanceStorage.h"
namespace mozilla {
namespace dom {
class PerformanceMainThread final : public Performance
, public PerformanceStorage
{
public:
PerformanceMainThread(nsPIDOMWindowInner* aWindow,
@ -23,6 +25,11 @@ public:
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(PerformanceMainThread,
Performance)
PerformanceStorage* AsPerformanceStorage() override
{
return this;
}
virtual PerformanceTiming* Timing() override;
virtual PerformanceNavigation* Navigation() override;

Просмотреть файл

@ -36,7 +36,7 @@ PerformanceNavigation::WrapObject(JSContext *cx,
uint16_t
PerformanceNavigation::RedirectCount() const
{
return GetPerformanceTiming()->GetRedirectCount();
return GetPerformanceTiming()->Data()->GetRedirectCount();
}
} // dom namespace

Просмотреть файл

@ -24,55 +24,55 @@ PerformanceNavigationTiming::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aG
DOMHighResTimeStamp
PerformanceNavigationTiming::UnloadEventStart() const
{
return mTiming->GetDOMTiming()->GetUnloadEventStartHighRes();
return mPerformance->GetDOMTiming()->GetUnloadEventStartHighRes();
}
DOMHighResTimeStamp
PerformanceNavigationTiming::UnloadEventEnd() const
{
return mTiming->GetDOMTiming()->GetUnloadEventEndHighRes();
return mPerformance->GetDOMTiming()->GetUnloadEventEndHighRes();
}
DOMHighResTimeStamp
PerformanceNavigationTiming::DomInteractive() const
{
return mTiming->GetDOMTiming()->GetDomInteractiveHighRes();
return mPerformance->GetDOMTiming()->GetDomInteractiveHighRes();
}
DOMHighResTimeStamp
PerformanceNavigationTiming::DomContentLoadedEventStart() const
{
return mTiming->GetDOMTiming()->GetDomContentLoadedEventStartHighRes();
return mPerformance->GetDOMTiming()->GetDomContentLoadedEventStartHighRes();
}
DOMHighResTimeStamp
PerformanceNavigationTiming::DomContentLoadedEventEnd() const
{
return mTiming->GetDOMTiming()->GetDomContentLoadedEventEndHighRes();
return mPerformance->GetDOMTiming()->GetDomContentLoadedEventEndHighRes();
}
DOMHighResTimeStamp
PerformanceNavigationTiming::DomComplete() const
{
return mTiming->GetDOMTiming()->GetDomCompleteHighRes();
return mPerformance->GetDOMTiming()->GetDomCompleteHighRes();
}
DOMHighResTimeStamp
PerformanceNavigationTiming::LoadEventStart() const
{
return mTiming->GetDOMTiming()->GetLoadEventStartHighRes();
return mPerformance->GetDOMTiming()->GetLoadEventStartHighRes();
}
DOMHighResTimeStamp
PerformanceNavigationTiming::LoadEventEnd() const
{
return mTiming->GetDOMTiming()->GetLoadEventEndHighRes();
return mPerformance->GetDOMTiming()->GetLoadEventEndHighRes();
}
NavigationType
PerformanceNavigationTiming::Type() const
{
switch(mTiming->GetDOMTiming()->GetType()) {
switch(mPerformance->GetDOMTiming()->GetType()) {
case nsDOMNavigationTiming::TYPE_NAVIGATE:
return NavigationType::Navigate;
break;
@ -92,5 +92,5 @@ PerformanceNavigationTiming::Type() const
uint16_t
PerformanceNavigationTiming::RedirectCount() const
{
return mTiming->GetRedirectCount();
return mTimingData->GetRedirectCount();
}

Просмотреть файл

@ -29,11 +29,10 @@ public:
// so that timestamps are relative to startTime, as opposed to the
// performance.timing object for which timestamps are absolute and has a
// zeroTime initialized to navigationStart
explicit PerformanceNavigationTiming(PerformanceTiming* aPerformanceTiming,
Performance* aPerformance,
nsIHttpChannel* aChannel)
: PerformanceResourceTiming(aPerformanceTiming, aPerformance,
NS_LITERAL_STRING("document"), aChannel) {
PerformanceNavigationTiming(UniquePtr<PerformanceTimingData>&& aPerformanceTiming,
Performance* aPerformance)
: PerformanceResourceTiming(Move(aPerformanceTiming), aPerformance,
NS_LITERAL_STRING("document")) {
SetEntryType(NS_LITERAL_STRING("navigation"));
SetInitiatorType(NS_LITERAL_STRING("navigation"));
}

Просмотреть файл

@ -11,7 +11,7 @@ using namespace mozilla::dom;
NS_IMPL_CYCLE_COLLECTION_INHERITED(PerformanceResourceTiming,
PerformanceEntry,
mTiming)
mPerformance)
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(PerformanceResourceTiming,
PerformanceEntry)
@ -23,45 +23,14 @@ NS_INTERFACE_MAP_END_INHERITING(PerformanceEntry)
NS_IMPL_ADDREF_INHERITED(PerformanceResourceTiming, PerformanceEntry)
NS_IMPL_RELEASE_INHERITED(PerformanceResourceTiming, PerformanceEntry)
PerformanceResourceTiming::PerformanceResourceTiming(PerformanceTiming* aPerformanceTiming,
PerformanceResourceTiming::PerformanceResourceTiming(UniquePtr<PerformanceTimingData>&& aPerformanceTiming,
Performance* aPerformance,
const nsAString& aName,
nsIHttpChannel* aChannel)
: PerformanceEntry(aPerformance->GetParentObject(), aName, NS_LITERAL_STRING("resource")),
mTiming(aPerformanceTiming),
mEncodedBodySize(0),
mTransferSize(0),
mDecodedBodySize(0)
const nsAString& aName)
: PerformanceEntry(aPerformance->GetParentObject(), aName, NS_LITERAL_STRING("resource"))
, mTimingData(Move(aPerformanceTiming))
, mPerformance(aPerformance)
{
MOZ_ASSERT(aPerformance, "Parent performance object should be provided");
SetPropertiesFromChannel(aChannel);
}
void
PerformanceResourceTiming::SetPropertiesFromChannel(nsIHttpChannel* aChannel)
{
if (!aChannel) {
return;
}
nsAutoCString protocol;
Unused << aChannel->GetProtocolVersion(protocol);
SetNextHopProtocol(NS_ConvertUTF8toUTF16(protocol));
uint64_t encodedBodySize = 0;
Unused << aChannel->GetEncodedBodySize(&encodedBodySize);
SetEncodedBodySize(encodedBodySize);
uint64_t transferSize = 0;
Unused << aChannel->GetTransferSize(&transferSize);
SetTransferSize(transferSize);
uint64_t decodedBodySize = 0;
Unused << aChannel->GetDecodedBodySize(&decodedBodySize);
if (decodedBodySize == 0) {
decodedBodySize = encodedBodySize;
}
SetDecodedBodySize(decodedBodySize);
}
PerformanceResourceTiming::~PerformanceResourceTiming()
@ -78,13 +47,14 @@ PerformanceResourceTiming::StartTime() const
// Ignore zero values. The RedirectStart and WorkerStart values
// can come from earlier redirected channels prior to the AsyncOpen
// time being recorded.
DOMHighResTimeStamp redirect = mTiming->RedirectStartHighRes();
DOMHighResTimeStamp redirect =
mTimingData->RedirectStartHighRes(mPerformance);
redirect = redirect ? redirect : DBL_MAX;
DOMHighResTimeStamp worker = mTiming->WorkerStartHighRes();
DOMHighResTimeStamp worker = mTimingData->WorkerStartHighRes(mPerformance);
worker = worker ? worker : DBL_MAX;
DOMHighResTimeStamp asyncOpen = mTiming->AsyncOpenHighRes();
DOMHighResTimeStamp asyncOpen = mTimingData->AsyncOpenHighRes(mPerformance);
return std::min(asyncOpen, std::min(redirect, worker));
}
@ -106,5 +76,7 @@ PerformanceResourceTiming::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSize
{
return PerformanceEntry::SizeOfExcludingThis(aMallocSizeOf) +
mInitiatorType.SizeOfExcludingThisIfUnshared(aMallocSizeOf) +
mNextHopProtocol.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
(mTimingData
? mTimingData->NextHopProtocol().SizeOfExcludingThisIfUnshared(aMallocSizeOf)
: 0);
}

Просмотреть файл

@ -7,9 +7,8 @@
#ifndef mozilla_dom_PerformanceResourceTiming_h___
#define mozilla_dom_PerformanceResourceTiming_h___
#include "mozilla/UniquePtr.h"
#include "nsCOMPtr.h"
#include "nsIChannel.h"
#include "nsITimedChannel.h"
#include "Performance.h"
#include "PerformanceEntry.h"
#include "PerformanceTiming.h"
@ -28,10 +27,9 @@ public:
PerformanceResourceTiming,
PerformanceEntry)
PerformanceResourceTiming(PerformanceTiming* aPerformanceTiming,
PerformanceResourceTiming(UniquePtr<PerformanceTimingData>&& aPerformanceTimingData,
Performance* aPerformance,
const nsAString& aName,
nsIHttpChannel* aChannel = nullptr);
const nsAString& aName);
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
@ -55,88 +53,85 @@ public:
void GetNextHopProtocol(nsAString& aNextHopProtocol) const
{
aNextHopProtocol = mNextHopProtocol;
}
void SetNextHopProtocol(const nsAString& aNextHopProtocol)
{
mNextHopProtocol = aNextHopProtocol;
if (mTimingData) {
aNextHopProtocol = mTimingData->NextHopProtocol();
}
}
DOMHighResTimeStamp WorkerStart() const {
return mTiming
? mTiming->WorkerStartHighRes()
return mTimingData
? mTimingData->WorkerStartHighRes(mPerformance)
: 0;
}
DOMHighResTimeStamp FetchStart() const {
return mTiming
? mTiming->FetchStartHighRes()
return mTimingData
? mTimingData->FetchStartHighRes(mPerformance)
: 0;
}
DOMHighResTimeStamp RedirectStart() const {
// We have to check if all the redirect URIs had the same origin (since
// there is no check in RedirectEndHighRes())
return mTiming && mTiming->ShouldReportCrossOriginRedirect()
? mTiming->RedirectStartHighRes()
return mTimingData && mTimingData->ShouldReportCrossOriginRedirect()
? mTimingData->RedirectStartHighRes(mPerformance)
: 0;
}
DOMHighResTimeStamp RedirectEnd() const {
// We have to check if all the redirect URIs had the same origin (since
// there is no check in RedirectEndHighRes())
return mTiming && mTiming->ShouldReportCrossOriginRedirect()
? mTiming->RedirectEndHighRes()
return mTimingData && mTimingData->ShouldReportCrossOriginRedirect()
? mTimingData->RedirectEndHighRes(mPerformance)
: 0;
}
DOMHighResTimeStamp DomainLookupStart() const {
return mTiming && mTiming->TimingAllowed()
? mTiming->DomainLookupStartHighRes()
return mTimingData && mTimingData->TimingAllowed()
? mTimingData->DomainLookupStartHighRes(mPerformance)
: 0;
}
DOMHighResTimeStamp DomainLookupEnd() const {
return mTiming && mTiming->TimingAllowed()
? mTiming->DomainLookupEndHighRes()
return mTimingData && mTimingData->TimingAllowed()
? mTimingData->DomainLookupEndHighRes(mPerformance)
: 0;
}
DOMHighResTimeStamp ConnectStart() const {
return mTiming && mTiming->TimingAllowed()
? mTiming->ConnectStartHighRes()
return mTimingData && mTimingData->TimingAllowed()
? mTimingData->ConnectStartHighRes(mPerformance)
: 0;
}
DOMHighResTimeStamp ConnectEnd() const {
return mTiming && mTiming->TimingAllowed()
? mTiming->ConnectEndHighRes()
return mTimingData && mTimingData->TimingAllowed()
? mTimingData->ConnectEndHighRes(mPerformance)
: 0;
}
DOMHighResTimeStamp RequestStart() const {
return mTiming && mTiming->TimingAllowed()
? mTiming->RequestStartHighRes()
return mTimingData && mTimingData->TimingAllowed()
? mTimingData->RequestStartHighRes(mPerformance)
: 0;
}
DOMHighResTimeStamp ResponseStart() const {
return mTiming && mTiming->TimingAllowed()
? mTiming->ResponseStartHighRes()
return mTimingData && mTimingData->TimingAllowed()
? mTimingData->ResponseStartHighRes(mPerformance)
: 0;
}
DOMHighResTimeStamp ResponseEnd() const {
return mTiming
? mTiming->ResponseEndHighRes()
return mTimingData
? mTimingData->ResponseEndHighRes(mPerformance)
: 0;
}
DOMHighResTimeStamp SecureConnectionStart() const
{
return mTiming && mTiming->TimingAllowed()
? mTiming->SecureConnectionStartHighRes()
return mTimingData && mTimingData->TimingAllowed()
? mTimingData->SecureConnectionStartHighRes(mPerformance)
: 0;
}
@ -147,32 +142,17 @@ public:
uint64_t TransferSize() const
{
return mTiming && mTiming->TimingAllowed() ? mTransferSize : 0;
return mTimingData ? mTimingData->TransferSize() : 0;
}
uint64_t EncodedBodySize() const
{
return mTiming && mTiming->TimingAllowed() ? mEncodedBodySize : 0;
return mTimingData ? mTimingData->EncodedBodySize() : 0;
}
uint64_t DecodedBodySize() const
{
return mTiming && mTiming->TimingAllowed() ? mDecodedBodySize : 0;
}
void SetEncodedBodySize(uint64_t aEncodedBodySize)
{
mEncodedBodySize = aEncodedBodySize;
}
void SetTransferSize(uint64_t aTransferSize)
{
mTransferSize = aTransferSize;
}
void SetDecodedBodySize(uint64_t aDecodedBodySize)
{
mDecodedBodySize = aDecodedBodySize;
return mTimingData ? mTimingData->DecodedBodySize() : 0;
}
size_t
@ -180,17 +160,13 @@ public:
protected:
virtual ~PerformanceResourceTiming();
void SetPropertiesFromChannel(nsIHttpChannel* aChannel);
size_t
SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
nsString mInitiatorType;
nsString mNextHopProtocol;
RefPtr<PerformanceTiming> mTiming;
uint64_t mEncodedBodySize;
uint64_t mTransferSize;
uint64_t mDecodedBodySize;
UniquePtr<PerformanceTimingData> mTimingData;
RefPtr<Performance> mPerformance;
};
} // namespace dom

Просмотреть файл

@ -0,0 +1,35 @@
/* -*- 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_PerformanceStorage_h
#define mozilla_dom_PerformanceStorage_h
#include "nsISupportsImpl.h"
class nsIHttpChannel;
class nsITimedChannel;
namespace mozilla {
namespace dom {
class PerformanceTimingData;
class PerformanceStorage
{
public:
NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
virtual void AddEntry(nsIHttpChannel* aChannel,
nsITimedChannel* aTimedChannel) = 0;
protected:
virtual ~PerformanceStorage() {}
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_PerformanceStorage_h

Просмотреть файл

@ -0,0 +1,271 @@
/* -*- 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 "PerformanceStorageWorker.h"
#include "WorkerPrivate.h"
#include "WorkerHolder.h"
namespace mozilla {
namespace dom {
using namespace workers;
class PerformanceProxyData
{
public:
PerformanceProxyData(UniquePtr<PerformanceTimingData>&& aData,
const nsAString& aInitiatorType,
const nsAString& aEntryName)
: mData(Move(aData))
, mInitiatorType(aInitiatorType)
, mEntryName(aEntryName)
{}
UniquePtr<PerformanceTimingData> mData;
nsString mInitiatorType;
nsString mEntryName;
};
namespace {
// This runnable calls InitializeOnWorker() on the worker thread. Here a
// workerHolder is used to monitor when the worker thread is starting the
// shutdown procedure.
// Here we use control runnable because this code must be executed also when in
// a sync event loop.
class PerformanceStorageInitializer final : public WorkerControlRunnable
{
RefPtr<PerformanceStorageWorker> mStorage;
public:
PerformanceStorageInitializer(WorkerPrivate* aWorkerPrivate,
PerformanceStorageWorker* aStorage)
: WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount)
, mStorage(aStorage)
{}
bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
{
mStorage->InitializeOnWorker();
return true;
}
nsresult
Cancel() override
{
mStorage->ShutdownOnWorker();
return WorkerRunnable::Cancel();
}
bool
PreDispatch(WorkerPrivate* aWorkerPrivate) override
{
return true;
}
void
PostDispatch(WorkerPrivate* aWorkerPrivate, bool aDispatchResult) override
{}
};
// Here we use control runnable because this code must be executed also when in
// a sync event loop
class PerformanceEntryAdder final : public WorkerControlRunnable
{
public:
PerformanceEntryAdder(WorkerPrivate* aWorkerPrivate,
PerformanceStorageWorker* aStorage,
UniquePtr<PerformanceProxyData>&& aData)
: WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount)
, mStorage(aStorage)
, mData(Move(aData))
{}
bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
{
mStorage->AddEntryOnWorker(Move(mData));
return true;
}
nsresult
Cancel() override
{
mStorage->ShutdownOnWorker();
return WorkerRunnable::Cancel();
}
bool
PreDispatch(WorkerPrivate* aWorkerPrivate) override
{
return true;
}
void
PostDispatch(WorkerPrivate* aWorkerPrivate, bool aDispatchResult) override
{}
private:
RefPtr<PerformanceStorageWorker> mStorage;
UniquePtr<PerformanceProxyData> mData;
};
class PerformanceStorageWorkerHolder final : public WorkerHolder
{
RefPtr<PerformanceStorageWorker> mStorage;
public:
explicit PerformanceStorageWorkerHolder(PerformanceStorageWorker* aStorage)
: WorkerHolder("PerformanceStorageWorkerHolder",
WorkerHolder::AllowIdleShutdownStart)
, mStorage(aStorage)
{}
bool
Notify(Status aStatus) override
{
if (mStorage) {
RefPtr<PerformanceStorageWorker> storage;
storage.swap(mStorage);
storage->ShutdownOnWorker();
}
return true;
}
};
} // anonymous
/* static */ already_AddRefed<PerformanceStorageWorker>
PerformanceStorageWorker::Create(WorkerPrivate* aWorkerPrivate)
{
MOZ_ASSERT(NS_IsMainThread());
RefPtr<PerformanceStorageWorker> storage =
new PerformanceStorageWorker(aWorkerPrivate);
RefPtr<PerformanceStorageInitializer> r =
new PerformanceStorageInitializer(aWorkerPrivate, storage);
if (NS_WARN_IF(!r->Dispatch())) {
return nullptr;
}
return storage.forget();
}
PerformanceStorageWorker::PerformanceStorageWorker(WorkerPrivate* aWorkerPrivate)
: mMutex("PerformanceStorageWorker::mMutex")
, mWorkerPrivate(aWorkerPrivate)
, mState(eInitializing)
{
}
PerformanceStorageWorker::~PerformanceStorageWorker() = default;
void
PerformanceStorageWorker::AddEntry(nsIHttpChannel* aChannel,
nsITimedChannel* aTimedChannel)
{
MOZ_ASSERT(NS_IsMainThread());
MutexAutoLock lock(mMutex);
if (mState == eTerminated) {
return;
}
nsAutoString initiatorType;
nsAutoString entryName;
UniquePtr<PerformanceTimingData> performanceTimingData(
PerformanceTimingData::Create(aTimedChannel, aChannel, 0, initiatorType,
entryName));
if (!performanceTimingData) {
return;
}
UniquePtr<PerformanceProxyData> data(
new PerformanceProxyData(Move(performanceTimingData), initiatorType,
entryName));
RefPtr<PerformanceEntryAdder> r =
new PerformanceEntryAdder(mWorkerPrivate, this, Move(data));
Unused << NS_WARN_IF(!r->Dispatch());
}
void
PerformanceStorageWorker::InitializeOnWorker()
{
MutexAutoLock lock(mMutex);
MOZ_ASSERT(mState == eInitializing);
MOZ_ASSERT(mWorkerPrivate);
mWorkerPrivate->AssertIsOnWorkerThread();
mWorkerHolder.reset(new PerformanceStorageWorkerHolder(this));
if (!mWorkerHolder->HoldWorker(mWorkerPrivate, Canceling)) {
MutexAutoUnlock lock(mMutex);
ShutdownOnWorker();
return;
}
// We are ready to accept entries.
mState = eReady;
}
void
PerformanceStorageWorker::ShutdownOnWorker()
{
MutexAutoLock lock(mMutex);
if (mState == eTerminated) {
return;
}
MOZ_ASSERT(mWorkerPrivate);
mWorkerPrivate->AssertIsOnWorkerThread();
mState = eTerminated;
mWorkerHolder = nullptr;
mWorkerPrivate = nullptr;
}
void
PerformanceStorageWorker::AddEntryOnWorker(UniquePtr<PerformanceProxyData>&& aData)
{
RefPtr<Performance> performance;
UniquePtr<PerformanceProxyData> data = Move(aData);
{
MutexAutoLock lock(mMutex);
if (mState == eTerminated) {
return;
}
MOZ_ASSERT(mWorkerPrivate);
mWorkerPrivate->AssertIsOnWorkerThread();
MOZ_ASSERT(mState == eReady);
WorkerGlobalScope* scope = mWorkerPrivate->GlobalScope();
performance = scope->GetPerformance();
}
if (NS_WARN_IF(!performance)) {
return;
}
RefPtr<PerformanceResourceTiming> performanceEntry =
new PerformanceResourceTiming(Move(data->mData), performance,
data->mEntryName);
performanceEntry->SetInitiatorType(data->mInitiatorType);
performance->InsertResourceEntry(performanceEntry);
}
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,64 @@
/* -*- 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_PerformanceStorageWorker_h
#define mozilla_dom_PerformanceStorageWorker_h
#include "PerformanceStorage.h"
namespace mozilla {
namespace dom {
namespace workers {
class WorkerHolder;
class WorkerPrivate;
}
class PerformanceProxyData;
class PerformanceStorageWorker final : public PerformanceStorage
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PerformanceStorageWorker, override)
static already_AddRefed<PerformanceStorageWorker>
Create(workers::WorkerPrivate* aWorkerPrivate);
void InitializeOnWorker();
void ShutdownOnWorker();
void AddEntry(nsIHttpChannel* aChannel,
nsITimedChannel* aTimedChannel) override;
void AddEntryOnWorker(UniquePtr<PerformanceProxyData>&& aData);
private:
explicit PerformanceStorageWorker(workers::WorkerPrivate* aWorkerPrivate);
~PerformanceStorageWorker();
Mutex mMutex;
// Protected by mutex.
// This raw pointer is nullified when the WorkerHolder communicates the
// shutting down of the worker thread.
workers::WorkerPrivate* mWorkerPrivate;
// Protected by mutex.
enum {
eInitializing,
eReady,
eTerminated,
} mState;
// Touched on worker-thread only.
UniquePtr<WorkerHolder> mWorkerHolder;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_PerformanceStorageWorker_h

Просмотреть файл

@ -20,39 +20,105 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PerformanceTiming, mPerformance)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(PerformanceTiming, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(PerformanceTiming, Release)
/* static */ PerformanceTimingData*
PerformanceTimingData::Create(nsITimedChannel* aTimedChannel,
nsIHttpChannel* aChannel,
DOMHighResTimeStamp aZeroTime,
nsAString& aInitiatorType,
nsAString& aEntryName)
{
MOZ_ASSERT(NS_IsMainThread());
// Check if resource timing is prefed off.
if (!nsContentUtils::IsResourceTimingEnabled()) {
return nullptr;
}
if (!aChannel || !aTimedChannel) {
return nullptr;
}
bool reportTiming = true;
aTimedChannel->GetReportResourceTiming(&reportTiming);
if (!reportTiming) {
return nullptr;
}
aTimedChannel->GetInitiatorType(aInitiatorType);
// If the initiator type had no valid value, then set it to the default
// ("other") value.
if (aInitiatorType.IsEmpty()) {
aInitiatorType = NS_LITERAL_STRING("other");
}
// According to the spec, "The name attribute must return the resolved URL
// of the requested resource. This attribute must not change even if the
// fetch redirected to a different URL."
nsCOMPtr<nsIURI> originalURI;
aChannel->GetOriginalURI(getter_AddRefs(originalURI));
nsAutoCString name;
originalURI->GetSpec(name);
aEntryName = NS_ConvertUTF8toUTF16(name);
// The nsITimedChannel argument will be used to gather all the timings.
// The nsIHttpChannel argument will be used to check if any cross-origin
// redirects occurred.
// The last argument is the "zero time" (offset). Since we don't want
// any offset for the resource timing, this will be set to "0" - the
// resource timing returns a relative timing (no offset).
return new PerformanceTimingData(aTimedChannel, aChannel, 0);
}
PerformanceTiming::PerformanceTiming(Performance* aPerformance,
nsITimedChannel* aChannel,
nsIHttpChannel* aHttpChannel,
DOMHighResTimeStamp aZeroTime)
: mPerformance(aPerformance),
mFetchStart(0.0),
mZeroTime(nsRFPService::ReduceTimePrecisionAsMSecs(aZeroTime)),
mRedirectCount(0),
mTimingAllowed(true),
mAllRedirectsSameOrigin(true),
mInitialized(!!aChannel),
mReportCrossOriginRedirect(true)
: mPerformance(aPerformance)
{
MOZ_ASSERT(aPerformance, "Parent performance object should be provided");
mTimingData.reset(new PerformanceTimingData(aChannel, aHttpChannel,
aZeroTime));
// Non-null aHttpChannel implies that this PerformanceTiming object is being
// used for subresources, which is irrelevant to this probe.
if (!aHttpChannel &&
nsContentUtils::IsPerformanceTimingEnabled() &&
IsTopLevelContentDocument()) {
Telemetry::Accumulate(Telemetry::TIME_TO_RESPONSE_START_MS,
mTimingData->ResponseStartHighRes(aPerformance) -
mTimingData->ZeroTime());
}
}
// Copy the timing info from the channel so we don't need to keep the channel
// alive just to get the timestamps.
PerformanceTimingData::PerformanceTimingData(nsITimedChannel* aChannel,
nsIHttpChannel* aHttpChannel,
DOMHighResTimeStamp aZeroTime)
: mZeroTime(0.0)
, mFetchStart(0.0)
, mEncodedBodySize(0)
, mTransferSize(0)
, mDecodedBodySize(0)
, mRedirectCount(0)
, mAllRedirectsSameOrigin(true)
, mReportCrossOriginRedirect(true)
, mSecureConnection(false)
, mTimingAllowed(true)
, mInitialized(false)
{
mInitialized = !!aChannel;
mZeroTime = nsRFPService::ReduceTimePrecisionAsMSecs(aZeroTime);
if (!nsContentUtils::IsPerformanceTimingEnabled() ||
nsContentUtils::ShouldResistFingerprinting()) {
mZeroTime = 0;
}
// The aHttpChannel argument is null if this PerformanceTiming object is
// being used for navigation timing (which is only relevant for documents).
// It has a non-null value if this PerformanceTiming object is being used
// for resource timing, which can include document loads, both toplevel and
// in subframes, and resources linked from a document.
if (aHttpChannel) {
mTimingAllowed = CheckAllowedOrigin(aHttpChannel, aChannel);
bool redirectsPassCheck = false;
aChannel->GetAllRedirectsPassTimingAllowCheck(&redirectsPassCheck);
mReportCrossOriginRedirect = mTimingAllowed && redirectsPassCheck;
}
mSecureConnection = false;
nsCOMPtr<nsIURI> uri;
if (aHttpChannel) {
aHttpChannel->GetURI(getter_AddRefs(uri));
@ -69,23 +135,7 @@ PerformanceTiming::PerformanceTiming(Performance* aPerformance,
mSecureConnection = false;
}
}
InitializeTimingInfo(aChannel);
// Non-null aHttpChannel implies that this PerformanceTiming object is being
// used for subresources, which is irrelevant to this probe.
if (!aHttpChannel &&
nsContentUtils::IsPerformanceTimingEnabled() &&
IsTopLevelContentDocument()) {
Telemetry::Accumulate(Telemetry::TIME_TO_RESPONSE_START_MS,
ResponseStartHighRes() - mZeroTime);
}
}
// Copy the timing info from the channel so we don't need to keep the channel
// alive just to get the timestamps.
void
PerformanceTiming::InitializeTimingInfo(nsITimedChannel* aChannel)
{
if (aChannel) {
aChannel->GetAsyncOpen(&mAsyncOpen);
aChannel->GetAllRedirectsSameOrigin(&mAllRedirectsSameOrigin);
@ -110,11 +160,11 @@ PerformanceTiming::InitializeTimingInfo(nsITimedChannel* aChannel)
aChannel->GetHandleFetchEventEnd(&mWorkerResponseEnd);
// The performance timing api essentially requires that the event timestamps
// have a strict relation with each other. The truth, however, is the browser
// engages in a number of speculative activities that sometimes mean connections
// and lookups begin at different times. Workaround that here by clamping
// these values to what we expect FetchStart to be. This means the later of
// AsyncOpen or WorkerStart times.
// have a strict relation with each other. The truth, however, is the
// browser engages in a number of speculative activities that sometimes mean
// connections and lookups begin at different times. Workaround that here by
// clamping these values to what we expect FetchStart to be. This means the
// later of AsyncOpen or WorkerStart times.
if (!mAsyncOpen.IsNull()) {
// We want to clamp to the expected FetchStart value. This is later of
// the AsyncOpen and WorkerStart values.
@ -145,6 +195,37 @@ PerformanceTiming::InitializeTimingInfo(nsITimedChannel* aChannel)
}
}
}
// The aHttpChannel argument is null if this PerformanceTiming object is
// being used for navigation timing (which is only relevant for documents).
// It has a non-null value if this PerformanceTiming object is being used
// for resource timing, which can include document loads, both toplevel and
// in subframes, and resources linked from a document.
if (aHttpChannel) {
mTimingAllowed = CheckAllowedOrigin(aHttpChannel, aChannel);
bool redirectsPassCheck = false;
aChannel->GetAllRedirectsPassTimingAllowCheck(&redirectsPassCheck);
mReportCrossOriginRedirect = mTimingAllowed && redirectsPassCheck;
SetPropertiesFromHttpChannel(aHttpChannel);
}
}
void
PerformanceTimingData::SetPropertiesFromHttpChannel(nsIHttpChannel* aHttpChannel)
{
MOZ_ASSERT(aHttpChannel);
nsAutoCString protocol;
Unused << aHttpChannel->GetProtocolVersion(protocol);
mNextHopProtocol = NS_ConvertUTF8toUTF16(protocol);
Unused << aHttpChannel->GetEncodedBodySize(&mEncodedBodySize);
Unused << aHttpChannel->GetTransferSize(&mTransferSize);
Unused << aHttpChannel->GetDecodedBodySize(&mDecodedBodySize);
if (mDecodedBodySize == 0) {
mDecodedBodySize = mEncodedBodySize;
}
}
PerformanceTiming::~PerformanceTiming()
@ -152,8 +233,10 @@ PerformanceTiming::~PerformanceTiming()
}
DOMHighResTimeStamp
PerformanceTiming::FetchStartHighRes()
PerformanceTimingData::FetchStartHighRes(Performance* aPerformance)
{
MOZ_ASSERT(aPerformance);
if (!mFetchStart) {
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
nsContentUtils::ShouldResistFingerprinting()) {
@ -163,9 +246,9 @@ PerformanceTiming::FetchStartHighRes()
"valid if the performance timing is enabled");
if (!mAsyncOpen.IsNull()) {
if (!mWorkerRequestStart.IsNull() && mWorkerRequestStart > mAsyncOpen) {
mFetchStart = TimeStampToDOMHighRes(mWorkerRequestStart);
mFetchStart = TimeStampToDOMHighRes(aPerformance, mWorkerRequestStart);
} else {
mFetchStart = TimeStampToDOMHighRes(mAsyncOpen);
mFetchStart = TimeStampToDOMHighRes(aPerformance, mAsyncOpen);
}
}
}
@ -175,12 +258,12 @@ PerformanceTiming::FetchStartHighRes()
DOMTimeMilliSec
PerformanceTiming::FetchStart()
{
return static_cast<int64_t>(FetchStartHighRes());
return static_cast<int64_t>(mTimingData->FetchStartHighRes(mPerformance));
}
bool
PerformanceTiming::CheckAllowedOrigin(nsIHttpChannel* aResourceChannel,
nsITimedChannel* aChannel)
PerformanceTimingData::CheckAllowedOrigin(nsIHttpChannel* aResourceChannel,
nsITimedChannel* aChannel)
{
if (!IsInitialized()) {
return false;
@ -208,14 +291,8 @@ PerformanceTiming::CheckAllowedOrigin(nsIHttpChannel* aResourceChannel,
return aChannel->TimingAllowCheck(principal);
}
bool
PerformanceTiming::TimingAllowed() const
{
return mTimingAllowed;
}
uint8_t
PerformanceTiming::GetRedirectCount() const
PerformanceTimingData::GetRedirectCount() const
{
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
nsContentUtils::ShouldResistFingerprinting()) {
@ -228,7 +305,7 @@ PerformanceTiming::GetRedirectCount() const
}
bool
PerformanceTiming::ShouldReportCrossOriginRedirect() const
PerformanceTimingData::ShouldReportCrossOriginRedirect() const
{
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
nsContentUtils::ShouldResistFingerprinting()) {
@ -242,23 +319,29 @@ PerformanceTiming::ShouldReportCrossOriginRedirect() const
}
DOMHighResTimeStamp
PerformanceTiming::AsyncOpenHighRes()
PerformanceTimingData::AsyncOpenHighRes(Performance* aPerformance)
{
MOZ_ASSERT(aPerformance);
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
nsContentUtils::ShouldResistFingerprinting() || mAsyncOpen.IsNull()) {
return mZeroTime;
}
return nsRFPService::ReduceTimePrecisionAsMSecs(TimeStampToDOMHighRes(mAsyncOpen));
return nsRFPService::ReduceTimePrecisionAsMSecs(
TimeStampToDOMHighRes(aPerformance, mAsyncOpen));
}
DOMHighResTimeStamp
PerformanceTiming::WorkerStartHighRes()
PerformanceTimingData::WorkerStartHighRes(Performance* aPerformance)
{
MOZ_ASSERT(aPerformance);
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
nsContentUtils::ShouldResistFingerprinting() || mWorkerStart.IsNull()) {
return mZeroTime;
}
return nsRFPService::ReduceTimePrecisionAsMSecs(TimeStampToDOMHighRes(mWorkerStart));
return nsRFPService::ReduceTimePrecisionAsMSecs(
TimeStampToDOMHighRes(aPerformance, mWorkerStart));
}
/**
@ -272,25 +355,28 @@ PerformanceTiming::WorkerStartHighRes()
* @return a valid timing if the Performance Timing is enabled
*/
DOMHighResTimeStamp
PerformanceTiming::RedirectStartHighRes()
PerformanceTimingData::RedirectStartHighRes(Performance* aPerformance)
{
MOZ_ASSERT(aPerformance);
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
nsContentUtils::ShouldResistFingerprinting()) {
return mZeroTime;
}
return TimeStampToReducedDOMHighResOrFetchStart(mRedirectStart);
return TimeStampToReducedDOMHighResOrFetchStart(aPerformance, mRedirectStart);
}
DOMTimeMilliSec
PerformanceTiming::RedirectStart()
{
if (!IsInitialized()) {
if (!mTimingData->IsInitialized()) {
return 0;
}
// We have to check if all the redirect URIs had the same origin (since there
// is no check in RedirectStartHighRes())
if (mAllRedirectsSameOrigin && mRedirectCount) {
return static_cast<int64_t>(RedirectStartHighRes());
if (mTimingData->AllRedirectsSameOrigin() &&
mTimingData->RedirectCountReal()) {
return static_cast<int64_t>(mTimingData->RedirectStartHighRes(mPerformance));
}
return 0;
}
@ -306,85 +392,99 @@ PerformanceTiming::RedirectStart()
* @return a valid timing if the Performance Timing is enabled
*/
DOMHighResTimeStamp
PerformanceTiming::RedirectEndHighRes()
PerformanceTimingData::RedirectEndHighRes(Performance* aPerformance)
{
MOZ_ASSERT(aPerformance);
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
nsContentUtils::ShouldResistFingerprinting()) {
return mZeroTime;
}
return TimeStampToReducedDOMHighResOrFetchStart(mRedirectEnd);
return TimeStampToReducedDOMHighResOrFetchStart(aPerformance, mRedirectEnd);
}
DOMTimeMilliSec
PerformanceTiming::RedirectEnd()
{
if (!IsInitialized()) {
if (!mTimingData->IsInitialized()) {
return 0;
}
// We have to check if all the redirect URIs had the same origin (since there
// is no check in RedirectEndHighRes())
if (mAllRedirectsSameOrigin && mRedirectCount) {
return static_cast<int64_t>(RedirectEndHighRes());
if (mTimingData->AllRedirectsSameOrigin() &&
mTimingData->RedirectCountReal()) {
return static_cast<int64_t>(mTimingData->RedirectEndHighRes(mPerformance));
}
return 0;
}
DOMHighResTimeStamp
PerformanceTiming::DomainLookupStartHighRes()
PerformanceTimingData::DomainLookupStartHighRes(Performance* aPerformance)
{
MOZ_ASSERT(aPerformance);
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
nsContentUtils::ShouldResistFingerprinting()) {
return mZeroTime;
}
return TimeStampToReducedDOMHighResOrFetchStart(mDomainLookupStart);
return TimeStampToReducedDOMHighResOrFetchStart(aPerformance,
mDomainLookupStart);
}
DOMTimeMilliSec
PerformanceTiming::DomainLookupStart()
{
return static_cast<int64_t>(DomainLookupStartHighRes());
return static_cast<int64_t>(mTimingData->DomainLookupStartHighRes(mPerformance));
}
DOMHighResTimeStamp
PerformanceTiming::DomainLookupEndHighRes()
PerformanceTimingData::DomainLookupEndHighRes(Performance* aPerformance)
{
MOZ_ASSERT(aPerformance);
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
nsContentUtils::ShouldResistFingerprinting()) {
return mZeroTime;
}
// Bug 1155008 - nsHttpTransaction is racy. Return DomainLookupStart when null
return mDomainLookupEnd.IsNull() ? DomainLookupStartHighRes()
: nsRFPService::ReduceTimePrecisionAsMSecs(
TimeStampToDOMHighRes(mDomainLookupEnd));
return mDomainLookupEnd.IsNull()
? DomainLookupStartHighRes(aPerformance)
: nsRFPService::ReduceTimePrecisionAsMSecs(
TimeStampToDOMHighRes(aPerformance, mDomainLookupEnd));
}
DOMTimeMilliSec
PerformanceTiming::DomainLookupEnd()
{
return static_cast<int64_t>(DomainLookupEndHighRes());
return static_cast<int64_t>(mTimingData->DomainLookupEndHighRes(mPerformance));
}
DOMHighResTimeStamp
PerformanceTiming::ConnectStartHighRes()
PerformanceTimingData::ConnectStartHighRes(Performance* aPerformance)
{
MOZ_ASSERT(aPerformance);
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
nsContentUtils::ShouldResistFingerprinting()) {
return mZeroTime;
}
return mConnectStart.IsNull() ? DomainLookupEndHighRes()
: nsRFPService::ReduceTimePrecisionAsMSecs(
TimeStampToDOMHighRes(mConnectStart));
return mConnectStart.IsNull()
? DomainLookupEndHighRes(aPerformance)
: nsRFPService::ReduceTimePrecisionAsMSecs(
TimeStampToDOMHighRes(aPerformance, mConnectStart));
}
DOMTimeMilliSec
PerformanceTiming::ConnectStart()
{
return static_cast<int64_t>(ConnectStartHighRes());
return static_cast<int64_t>(mTimingData->ConnectStartHighRes(mPerformance));
}
DOMHighResTimeStamp
PerformanceTiming::SecureConnectionStartHighRes()
PerformanceTimingData::SecureConnectionStartHighRes(Performance* aPerformance)
{
MOZ_ASSERT(aPerformance);
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
nsContentUtils::ShouldResistFingerprinting()) {
return mZeroTime;
@ -392,39 +492,45 @@ PerformanceTiming::SecureConnectionStartHighRes()
return !mSecureConnection
? 0 // We use 0 here, because mZeroTime is sometimes set to the navigation
// start time.
: (mSecureConnectionStart.IsNull() ? mZeroTime
: nsRFPService::ReduceTimePrecisionAsMSecs(
TimeStampToDOMHighRes(mSecureConnectionStart)));
: (mSecureConnectionStart.IsNull()
? mZeroTime
: nsRFPService::ReduceTimePrecisionAsMSecs(
TimeStampToDOMHighRes(aPerformance, mSecureConnectionStart)));
}
DOMTimeMilliSec
PerformanceTiming::SecureConnectionStart()
{
return static_cast<int64_t>(SecureConnectionStartHighRes());
return static_cast<int64_t>(mTimingData->SecureConnectionStartHighRes(mPerformance));
}
DOMHighResTimeStamp
PerformanceTiming::ConnectEndHighRes()
PerformanceTimingData::ConnectEndHighRes(Performance* aPerformance)
{
MOZ_ASSERT(aPerformance);
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
nsContentUtils::ShouldResistFingerprinting()) {
return mZeroTime;
}
// Bug 1155008 - nsHttpTransaction is racy. Return ConnectStart when null
return mConnectEnd.IsNull() ? ConnectStartHighRes()
: nsRFPService::ReduceTimePrecisionAsMSecs(
TimeStampToDOMHighRes(mConnectEnd));
return mConnectEnd.IsNull()
? ConnectStartHighRes(aPerformance)
: nsRFPService::ReduceTimePrecisionAsMSecs(
TimeStampToDOMHighRes(aPerformance, mConnectEnd));
}
DOMTimeMilliSec
PerformanceTiming::ConnectEnd()
{
return static_cast<int64_t>(ConnectEndHighRes());
return static_cast<int64_t>(mTimingData->ConnectEndHighRes(mPerformance));
}
DOMHighResTimeStamp
PerformanceTiming::RequestStartHighRes()
PerformanceTimingData::RequestStartHighRes(Performance* aPerformance)
{
MOZ_ASSERT(aPerformance);
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
nsContentUtils::ShouldResistFingerprinting()) {
return mZeroTime;
@ -434,18 +540,20 @@ PerformanceTiming::RequestStartHighRes()
mRequestStart = mWorkerRequestStart;
}
return TimeStampToReducedDOMHighResOrFetchStart(mRequestStart);
return TimeStampToReducedDOMHighResOrFetchStart(aPerformance, mRequestStart);
}
DOMTimeMilliSec
PerformanceTiming::RequestStart()
{
return static_cast<int64_t>(RequestStartHighRes());
return static_cast<int64_t>(mTimingData->RequestStartHighRes(mPerformance));
}
DOMHighResTimeStamp
PerformanceTiming::ResponseStartHighRes()
PerformanceTimingData::ResponseStartHighRes(Performance* aPerformance)
{
MOZ_ASSERT(aPerformance);
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
nsContentUtils::ShouldResistFingerprinting()) {
return mZeroTime;
@ -459,18 +567,20 @@ PerformanceTiming::ResponseStartHighRes()
(!mRequestStart.IsNull() && mResponseStart < mRequestStart)) {
mResponseStart = mRequestStart;
}
return TimeStampToReducedDOMHighResOrFetchStart(mResponseStart);
return TimeStampToReducedDOMHighResOrFetchStart(aPerformance, mResponseStart);
}
DOMTimeMilliSec
PerformanceTiming::ResponseStart()
{
return static_cast<int64_t>(ResponseStartHighRes());
return static_cast<int64_t>(mTimingData->ResponseStartHighRes(mPerformance));
}
DOMHighResTimeStamp
PerformanceTiming::ResponseEndHighRes()
PerformanceTimingData::ResponseEndHighRes(Performance* aPerformance)
{
MOZ_ASSERT(aPerformance);
if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized() ||
nsContentUtils::ShouldResistFingerprinting()) {
return mZeroTime;
@ -483,21 +593,16 @@ PerformanceTiming::ResponseEndHighRes()
mResponseEnd = mWorkerResponseEnd;
}
// Bug 1155008 - nsHttpTransaction is racy. Return ResponseStart when null
return mResponseEnd.IsNull() ? ResponseStartHighRes()
: nsRFPService::ReduceTimePrecisionAsMSecs(
TimeStampToDOMHighRes(mResponseEnd));
return mResponseEnd.IsNull()
? ResponseStartHighRes(aPerformance)
: nsRFPService::ReduceTimePrecisionAsMSecs(
TimeStampToDOMHighRes(aPerformance, mResponseEnd));
}
DOMTimeMilliSec
PerformanceTiming::ResponseEnd()
{
return static_cast<int64_t>(ResponseEndHighRes());
}
bool
PerformanceTiming::IsInitialized() const
{
return mInitialized;
return static_cast<int64_t>(mTimingData->ResponseEndHighRes(mPerformance));
}
JSObject*

Просмотреть файл

@ -20,6 +20,204 @@ class nsITimedChannel;
namespace mozilla {
namespace dom {
class PerformanceTiming;
class PerformanceTimingData final
{
friend class PerformanceTiming;
public:
// This can return null.
static PerformanceTimingData*
Create(nsITimedChannel* aChannel,
nsIHttpChannel* aHttpChannel,
DOMHighResTimeStamp aZeroTime,
nsAString& aInitiatorType,
nsAString& aEntryName);
PerformanceTimingData(nsITimedChannel* aChannel,
nsIHttpChannel* aHttpChannel,
DOMHighResTimeStamp aZeroTime);
void
SetPropertiesFromHttpChannel(nsIHttpChannel* aHttpChannel);
bool IsInitialized() const
{
return mInitialized;
}
const nsString& NextHopProtocol() const
{
return mNextHopProtocol;
}
uint64_t TransferSize() const
{
return mTimingAllowed ? mTransferSize : 0;
}
uint64_t EncodedBodySize() const
{
return mTimingAllowed ? mEncodedBodySize : 0;
}
uint64_t DecodedBodySize() const
{
return mTimingAllowed ? mDecodedBodySize : 0;
}
/**
* @param aStamp
* The TimeStamp recorded for a specific event. This TimeStamp can
* be null.
* @return the duration of an event with a given TimeStamp, relative to the
* navigationStart TimeStamp (the moment the user landed on the
* page), if the given TimeStamp is valid. Otherwise, it will return
* the FetchStart timing value.
*/
inline DOMHighResTimeStamp
TimeStampToReducedDOMHighResOrFetchStart(Performance* aPerformance,
TimeStamp aStamp)
{
MOZ_ASSERT(aPerformance);
return (!aStamp.IsNull())
? nsRFPService::ReduceTimePrecisionAsMSecs(
TimeStampToDOMHighRes(aPerformance, aStamp))
: FetchStartHighRes(aPerformance);
}
/**
* The nsITimedChannel records an absolute timestamp for each event.
* The nsDOMNavigationTiming will record the moment when the user landed on
* the page. This is a window.performance unique timestamp, so it can be used
* for all the events (navigation timing and resource timing events).
*
* The algorithm operates in 2 steps:
* 1. The first step is to subtract the two timestamps: the argument (the
* event's timestamp) and the navigation start timestamp. This will result in
* a relative timestamp of the event (relative to the navigation start -
* window.performance.timing.navigationStart).
* 2. The second step is to add any required offset (the mZeroTime). For now,
* this offset value is either 0 (for the resource timing), or equal to
* "performance.navigationStart" (for navigation timing).
* For the resource timing, mZeroTime is set to 0, causing the result to be a
* relative time.
* For the navigation timing, mZeroTime is set to "performance.navigationStart"
* causing the result be an absolute time.
*
* @param aStamp
* The TimeStamp recorded for a specific event. This TimeStamp can't
* be null.
* @return number of milliseconds value as one of:
* - relative to the navigation start time, time the user has landed on the
* page
* - an absolute wall clock time since the unix epoch
*/
inline DOMHighResTimeStamp
TimeStampToDOMHighRes(Performance* aPerformance, TimeStamp aStamp) const
{
MOZ_ASSERT(aPerformance);
MOZ_ASSERT(!aStamp.IsNull());
TimeDuration duration = aStamp - aPerformance->CreationTimeStamp();
return duration.ToMilliseconds() + mZeroTime;
}
// The last channel's AsyncOpen time. This may occur before the FetchStart
// in some cases.
DOMHighResTimeStamp AsyncOpenHighRes(Performance* aPerformance);
// High resolution (used by resource timing)
DOMHighResTimeStamp WorkerStartHighRes(Performance* aPerformance);
DOMHighResTimeStamp FetchStartHighRes(Performance* aPerformance);
DOMHighResTimeStamp RedirectStartHighRes(Performance* aPerformance);
DOMHighResTimeStamp RedirectEndHighRes(Performance* aPerformance);
DOMHighResTimeStamp DomainLookupStartHighRes(Performance* aPerformance);
DOMHighResTimeStamp DomainLookupEndHighRes(Performance* aPerformance);
DOMHighResTimeStamp ConnectStartHighRes(Performance* aPerformance);
DOMHighResTimeStamp SecureConnectionStartHighRes(Performance* aPerformance);
DOMHighResTimeStamp ConnectEndHighRes(Performance* aPerformance);
DOMHighResTimeStamp RequestStartHighRes(Performance* aPerformance);
DOMHighResTimeStamp ResponseStartHighRes(Performance* aPerformance);
DOMHighResTimeStamp ResponseEndHighRes(Performance* aPerformance);
DOMHighResTimeStamp ZeroTime() const { return mZeroTime; }
uint8_t RedirectCountReal() const { return mRedirectCount; }
uint8_t GetRedirectCount() const;
bool AllRedirectsSameOrigin() const { return mAllRedirectsSameOrigin; }
// If this is false the values of redirectStart/End will be 0 This is false if
// no redirects occured, or if any of the responses failed the
// timing-allow-origin check in HttpBaseChannel::TimingAllowCheck
bool ShouldReportCrossOriginRedirect() const;
// Cached result of CheckAllowedOrigin. If false, security sensitive
// attributes of the resourceTiming object will be set to 0
bool TimingAllowed() const
{
return mTimingAllowed;
}
private:
// Checks if the resource is either same origin as the page that started
// the load, or if the response contains the Timing-Allow-Origin header
// with a value of * or matching the domain of the loading Principal
bool CheckAllowedOrigin(nsIHttpChannel* aResourceChannel,
nsITimedChannel* aChannel);
nsString mNextHopProtocol;
TimeStamp mAsyncOpen;
TimeStamp mRedirectStart;
TimeStamp mRedirectEnd;
TimeStamp mDomainLookupStart;
TimeStamp mDomainLookupEnd;
TimeStamp mConnectStart;
TimeStamp mSecureConnectionStart;
TimeStamp mConnectEnd;
TimeStamp mRequestStart;
TimeStamp mResponseStart;
TimeStamp mCacheReadStart;
TimeStamp mResponseEnd;
TimeStamp mCacheReadEnd;
// ServiceWorker interception timing information
TimeStamp mWorkerStart;
TimeStamp mWorkerRequestStart;
TimeStamp mWorkerResponseEnd;
// This is an offset that will be added to each timing ([ms] resolution).
// There are only 2 possible values: (1) logicaly equal to navigationStart
// TimeStamp (results are absolute timstamps - wallclock); (2) "0" (results
// are relative to the navigation start).
DOMHighResTimeStamp mZeroTime;
DOMHighResTimeStamp mFetchStart;
uint64_t mEncodedBodySize;
uint64_t mTransferSize;
uint64_t mDecodedBodySize;
uint8_t mRedirectCount;
bool mAllRedirectsSameOrigin;
// If the resourceTiming object should have non-zero redirectStart and
// redirectEnd attributes. It is false if there were no redirects, or if any
// of the responses didn't pass the timing-allow-check
bool mReportCrossOriginRedirect;
bool mSecureConnection;
bool mTimingAllowed;
bool mInitialized;
};
// Script "performance.timing" object
class PerformanceTiming final : public nsWrapperCache
{
@ -60,57 +258,6 @@ public:
return mPerformance;
}
/**
* @param aStamp
* The TimeStamp recorded for a specific event. This TimeStamp can
* be null.
* @return the duration of an event with a given TimeStamp, relative to the
* navigationStart TimeStamp (the moment the user landed on the
* page), if the given TimeStamp is valid. Otherwise, it will return
* the FetchStart timing value.
*/
inline DOMHighResTimeStamp TimeStampToReducedDOMHighResOrFetchStart(TimeStamp aStamp)
{
return (!aStamp.IsNull())
? nsRFPService::ReduceTimePrecisionAsMSecs(TimeStampToDOMHighRes(aStamp))
: FetchStartHighRes();
}
/**
* The nsITimedChannel records an absolute timestamp for each event.
* The nsDOMNavigationTiming will record the moment when the user landed on
* the page. This is a window.performance unique timestamp, so it can be used
* for all the events (navigation timing and resource timing events).
*
* The algorithm operates in 2 steps:
* 1. The first step is to subtract the two timestamps: the argument (the
* envet's timesramp) and the navigation start timestamp. This will result in
* a relative timestamp of the event (relative to the navigation start -
* window.performance.timing.navigationStart).
* 2. The second step is to add any required offset (the mZeroTime). For now,
* this offset value is either 0 (for the resource timing), or equal to
* "performance.navigationStart" (for navigation timing).
* For the resource timing, mZeroTime is set to 0, causing the result to be a
* relative time.
* For the navigation timing, mZeroTime is set to "performance.navigationStart"
* causing the result be an absolute time.
*
* @param aStamp
* The TimeStamp recorded for a specific event. This TimeStamp can't
* be null.
* @return number of milliseconds value as one of:
* - relative to the navigation start time, time the user has landed on the
* page
* - an absolute wall clock time since the unix epoch
*/
inline DOMHighResTimeStamp TimeStampToDOMHighRes(TimeStamp aStamp) const
{
MOZ_ASSERT(!aStamp.IsNull());
TimeDuration duration =
aStamp - GetDOMTiming()->GetNavigationStartTimeStamp();
return duration.ToMilliseconds() + mZeroTime;
}
virtual JSObject* WrapObject(JSContext *cx,
JS::Handle<JSObject*> aGivenProto) override;
@ -145,40 +292,6 @@ public:
GetDOMTiming()->GetUnloadEventEnd());
}
uint8_t GetRedirectCount() const;
// Checks if the resource is either same origin as the page that started
// the load, or if the response contains the Timing-Allow-Origin header
// with a value of * or matching the domain of the loading Principal
bool CheckAllowedOrigin(nsIHttpChannel* aResourceChannel, nsITimedChannel* aChannel);
// Cached result of CheckAllowedOrigin. If false, security sensitive
// attributes of the resourceTiming object will be set to 0
bool TimingAllowed() const;
// If this is false the values of redirectStart/End will be 0
// This is false if no redirects occured, or if any of the responses failed
// the timing-allow-origin check in HttpBaseChannel::TimingAllowCheck
bool ShouldReportCrossOriginRedirect() const;
// The last channel's AsyncOpen time. This may occur before the FetchStart
// in some cases.
DOMHighResTimeStamp AsyncOpenHighRes();
// High resolution (used by resource timing)
DOMHighResTimeStamp WorkerStartHighRes();
DOMHighResTimeStamp FetchStartHighRes();
DOMHighResTimeStamp RedirectStartHighRes();
DOMHighResTimeStamp RedirectEndHighRes();
DOMHighResTimeStamp DomainLookupStartHighRes();
DOMHighResTimeStamp DomainLookupEndHighRes();
DOMHighResTimeStamp ConnectStartHighRes();
DOMHighResTimeStamp SecureConnectionStartHighRes();
DOMHighResTimeStamp ConnectEndHighRes();
DOMHighResTimeStamp RequestStartHighRes();
DOMHighResTimeStamp ResponseStartHighRes();
DOMHighResTimeStamp ResponseEndHighRes();
// Low resolution (used by navigation timing)
DOMTimeMilliSec FetchStart();
DOMTimeMilliSec RedirectStart();
@ -272,53 +385,19 @@ public:
GetDOMTiming()->GetTimeToNonBlankPaint());
}
PerformanceTimingData* Data() const
{
return mTimingData.get();
}
private:
~PerformanceTiming();
bool IsInitialized() const;
void InitializeTimingInfo(nsITimedChannel* aChannel);
bool IsTopLevelContentDocument() const;
RefPtr<Performance> mPerformance;
DOMHighResTimeStamp mFetchStart;
// This is an offset that will be added to each timing ([ms] resolution).
// There are only 2 possible values: (1) logicaly equal to navigationStart
// TimeStamp (results are absolute timstamps - wallclock); (2) "0" (results
// are relative to the navigation start).
DOMHighResTimeStamp mZeroTime;
TimeStamp mAsyncOpen;
TimeStamp mRedirectStart;
TimeStamp mRedirectEnd;
TimeStamp mDomainLookupStart;
TimeStamp mDomainLookupEnd;
TimeStamp mConnectStart;
TimeStamp mSecureConnectionStart;
TimeStamp mConnectEnd;
TimeStamp mRequestStart;
TimeStamp mResponseStart;
TimeStamp mCacheReadStart;
TimeStamp mResponseEnd;
TimeStamp mCacheReadEnd;
// ServiceWorker interception timing information
TimeStamp mWorkerStart;
TimeStamp mWorkerRequestStart;
TimeStamp mWorkerResponseEnd;
uint8_t mRedirectCount;
bool mTimingAllowed;
bool mAllRedirectsSameOrigin;
bool mInitialized;
// If the resourceTiming object should have non-zero redirectStart and
// redirectEnd attributes. It is false if there were no redirects, or if
// any of the responses didn't pass the timing-allow-check
bool mReportCrossOriginRedirect;
bool mSecureConnection;
UniquePtr<PerformanceTimingData> mTimingData;
};
} // namespace dom

Просмотреть файл

@ -21,6 +21,12 @@ class PerformanceWorker final : public Performance
public:
explicit PerformanceWorker(workers::WorkerPrivate* aWorkerPrivate);
PerformanceStorage* AsPerformanceStorage() override
{
MOZ_CRASH("This should not be called on workers.");
return nullptr;
}
virtual PerformanceTiming* Timing() override
{
MOZ_CRASH("This should not be called on workers.");
@ -33,12 +39,6 @@ public:
return nullptr;
}
virtual void AddEntry(nsIHttpChannel* channel,
nsITimedChannel* timedChannel) override
{
MOZ_CRASH("This should not be called on workers.");
}
TimeStamp CreationTimeStamp() const override;
DOMHighResTimeStamp CreationTime() const override;
@ -68,7 +68,7 @@ protected:
void DispatchBufferFullEvent() override
{
MOZ_CRASH("This should not be called on workers.");
// Nothing to do here. See bug 1432758.
}
private:

Просмотреть файл

@ -18,6 +18,8 @@ EXPORTS.mozilla.dom += [
'PerformanceObserverEntryList.h',
'PerformanceResourceTiming.h',
'PerformanceService.h',
'PerformanceStorage.h',
'PerformanceStorageWorker.h',
'PerformanceTiming.h',
]
@ -33,6 +35,7 @@ UNIFIED_SOURCES += [
'PerformanceObserverEntryList.cpp',
'PerformanceResourceTiming.cpp',
'PerformanceService.cpp',
'PerformanceStorageWorker.cpp',
'PerformanceTiming.cpp',
'PerformanceWorker.cpp',
]

Просмотреть файл

@ -0,0 +1 @@
/* Nothing here */

Просмотреть файл

@ -6,6 +6,9 @@ support-files =
worker_performance_user_timing.js
worker_performance_observer.js
sharedworker_performance_user_timing.js
test_worker_performance_entries.js
test_worker_performance_entries.sjs
empty.js
[test_performance_observer.html]
[test_performance_user_timing.html]
@ -14,3 +17,4 @@ support-files =
[test_sharedWorker_performance_user_timing.html]
[test_worker_performance_now.html]
[test_timeOrigin.html]
[test_worker_performance_entries.html]

Просмотреть файл

@ -0,0 +1,31 @@
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<!DOCTYPE HTML>
<html>
<head>
<title>PerformanceResouceTiming in workers</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
var worker = new Worker('test_worker_performance_entries.js');
worker.onmessage = function(event) {
if (event.data.type == "check") {
ok(event.data.status, event.data.msg);
return;
}
if (event.data.type == "finish") {
SimpleTest.finish();
return;
}
ok(false, "?!?");
}
</script>
</body>
</html>

Просмотреть файл

@ -0,0 +1,102 @@
function ok(a, msg) {
postMessage({type: "check", status: !!a, msg });
}
function is(a, b, msg) {
ok(a === b, msg);
}
function finish(a, msg) {
postMessage({type: "finish" });
}
function check(resource, initiatorType, protocol) {
let entries = performance.getEntries();
ok(entries.length == 1, "We have an entry");
ok(entries[0] instanceof PerformanceEntry,
"The entry is a PerformanceEntry");
ok(entries[0].name.endsWith(resource), "The entry has been found!");
is(entries[0].entryType, "resource", "Correct EntryType");
ok(entries[0].startTime > 0, "We have a startTime");
ok(entries[0].duration > 0, "We have a duration");
ok(entries[0] instanceof PerformanceResourceTiming,
"The entry is a PerformanceResourceTiming");
is(entries[0].initiatorType, initiatorType, "Correct initiatorType");
is(entries[0].nextHopProtocol, protocol, "Correct protocol");
performance.clearResourceTimings();
}
function simple_checks() {
ok("performance" in self, "We have self.performance");
performance.clearResourceTimings();
next();
}
function fetch_request() {
fetch("test_worker_performance_entries.sjs")
.then(r => r.blob())
.then(blob => {
check("test_worker_performance_entries.sjs", "fetch", "http/1.1");
})
.then(next);
}
function xhr_request() {
let xhr = new XMLHttpRequest();
xhr.open("GET", "test_worker_performance_entries.sjs");
xhr.send();
xhr.onload = () => {
check("test_worker_performance_entries.sjs", "xmlhttprequest", "http/1.1");
next();
}
}
function sync_xhr_request() {
let xhr = new XMLHttpRequest();
xhr.open("GET", "test_worker_performance_entries.sjs", false);
xhr.send();
check("test_worker_performance_entries.sjs", "xmlhttprequest", "http/1.1");
next();
}
function import_script() {
importScripts(["empty.js"]);
check("empty.js", "other", "http/1.1");
next();
}
function redirect() {
fetch("test_worker_performance_entries.sjs?redirect")
.then(r => r.text())
.then(text => {
is(text, "Hello world \\o/", "The redirect worked correctly");
check("test_worker_performance_entries.sjs?redirect", "fetch", "http/1.1");
})
.then(next);
}
let tests = [
simple_checks,
fetch_request,
xhr_request,
sync_xhr_request,
import_script,
redirect,
];
function next() {
if (!tests.length) {
finish();
return;
}
let test = tests.shift();
test();
}
next();

Просмотреть файл

@ -0,0 +1,12 @@
function handleRequest(request, response)
{
response.setHeader("Content-Type", "text/html");
if (request.queryString == "redirect") {
response.setStatusLine(request.httpVersion, 302, "See Other");
response.setHeader("Location", "test_worker_performance_entries.sjs?ok");
} else {
response.setStatusLine(request.httpVersion, 200, "OK");
response.write("Hello world \\o/");
}
}

Просмотреть файл

@ -3173,6 +3173,7 @@ nsresult nsPluginHost::NewPluginURLStream(const nsString& aURL,
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS |
nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL,
nsIContentPolicy::TYPE_OBJECT_SUBREQUEST,
nullptr, // aPerformanceStorage
nullptr, // aLoadGroup
listenerPeer,
nsIRequest::LOAD_NORMAL | nsIChannel::LOAD_CLASSIFY_URI |

Просмотреть файл

@ -1065,6 +1065,7 @@ ScriptLoader::StartLoad(ScriptLoadRequest* aRequest)
aRequest->mTriggeringPrincipal,
securityFlags,
contentPolicyType,
nullptr, // aPerformanceStorage
loadGroup,
prompter,
nsIRequest::LOAD_NORMAL |

Просмотреть файл

@ -1073,6 +1073,7 @@ nsCSPContext::SendReports(
doc,
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
nsIContentPolicy::TYPE_CSP_REPORT,
nullptr, // aPerformanceStorage
nullptr, // aLoadGroup
nullptr, // aCallbacks
loadFlags);
@ -1083,6 +1084,7 @@ nsCSPContext::SendReports(
mLoadingPrincipal,
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
nsIContentPolicy::TYPE_CSP_REPORT,
nullptr, // PerformanceStorage
nullptr, // aLoadGroup
nullptr, // aCallbacks
loadFlags);

Просмотреть файл

@ -34,6 +34,23 @@ namespace dom {
//----------------------------------------------------------------------
// nsISupports methods:
nsresult
SVGDocument::InsertChildBefore(nsIContent* aKid, nsIContent* aBeforeThis,
bool aNotify)
{
if (aKid->IsElement() && !aKid->IsSVGElement()) {
// We can get here when well formed XML with a non-SVG root element is
// served with the SVG MIME type, for example. In that case we need to load
// the non-SVG UA sheets or else we can get bugs like bug 1016145. Note
// that we have to do this _before_ the XMLDocument::InsertChildBefore,
// since that can try to construct frames, and we need to have the sheets
// loaded by then.
EnsureNonSVGUserAgentStyleSheetsLoaded();
}
return XMLDocument::InsertChildBefore(aKid, aBeforeThis, aNotify);
}
nsresult
SVGDocument::InsertChildAt_Deprecated(nsIContent* aKid, uint32_t aIndex,
bool aNotify)

Просмотреть файл

@ -29,6 +29,8 @@ public:
mType = eSVG;
}
virtual nsresult InsertChildBefore(nsIContent* aKid, nsIContent* aBeforeThis,
bool aNotify) override;
virtual nsresult InsertChildAt_Deprecated(nsIContent* aKid, uint32_t aIndex,
bool aNotify) override;
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,

Просмотреть файл

@ -81,6 +81,18 @@ NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGSwitchElement)
//----------------------------------------------------------------------
// nsINode methods
nsresult
SVGSwitchElement::InsertChildBefore(nsIContent* aKid, nsIContent* aBeforeThis,
bool aNotify)
{
nsresult rv =
SVGSwitchElementBase::InsertChildBefore(aKid, aBeforeThis, aNotify);
if (NS_SUCCEEDED(rv)) {
MaybeInvalidate();
}
return rv;
}
nsresult
SVGSwitchElement::InsertChildAt_Deprecated(nsIContent* aKid,
uint32_t aIndex,

Просмотреть файл

@ -40,6 +40,8 @@ public:
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(SVGSwitchElement,
SVGSwitchElementBase)
// nsINode
virtual nsresult InsertChildBefore(nsIContent* aKid, nsIContent* aBeforeThis,
bool aNotify) override;
virtual nsresult InsertChildAt_Deprecated(nsIContent* aKid, uint32_t aIndex,
bool aNotify) override;
virtual void RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify) override;

Просмотреть файл

@ -1364,6 +1364,7 @@ nsresult nsWebBrowserPersist::SaveURIInternal(
nsContentUtils::GetSystemPrincipal(),
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
nsIContentPolicy::TYPE_OTHER,
nullptr, // aPerformanceStorage
nullptr, // aLoadGroup
static_cast<nsIInterfaceRequestor*>(this),
loadFlags);

Просмотреть файл

@ -98,6 +98,11 @@ interface Document : Node {
Attr createAttribute(DOMString name);
[NewObject, Throws]
Attr createAttributeNS(DOMString? namespace, DOMString name);
// Allows setting innerHTML without automatic sanitization.
// Do not use this.
[ChromeOnly]
attribute boolean allowUnsafeHTML;
};
// http://www.whatwg.org/specs/web-apps/current-work/#the-document-object

Просмотреть файл

@ -236,6 +236,16 @@ partial interface Element {
attribute DOMString outerHTML;
[CEReactions, Throws]
void insertAdjacentHTML(DOMString position, DOMString text);
/**
* Like the innerHTML setter, but does not sanitize its values, even in
* chrome-privileged documents.
*
* If you're thinking about using this, don't. You have many, much better
* options.
*/
[ChromeOnly, Throws]
void unsafeSetInnerHTML(DOMString html);
};
// http://www.w3.org/TR/selectors-api/#interface-definitions

Просмотреть файл

@ -42,7 +42,7 @@ partial interface Performance {
};
// http://www.w3.org/TR/resource-timing/#extensions-performance-interface
[Exposed=Window]
[Exposed=(Window,Worker)]
partial interface Performance {
void clearResourceTimings();
void setResourceTimingBufferSize(unsigned long maxSize);

Просмотреть файл

@ -10,6 +10,7 @@
* liability, trademark and document use rules apply.
*/
[Exposed=(Window,Worker)]
interface PerformanceResourceTiming : PerformanceEntry
{
readonly attribute DOMString initiatorType;

Просмотреть файл

@ -57,6 +57,7 @@
#include "mozilla/dom/InternalResponse.h"
#include "mozilla/dom/nsCSPService.h"
#include "mozilla/dom/nsCSPUtils.h"
#include "mozilla/dom/PerformanceStorage.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/PromiseNativeHandler.h"
#include "mozilla/dom/Response.h"
@ -110,6 +111,7 @@ nsresult
ChannelFromScriptURL(nsIPrincipal* principal,
nsIURI* baseURI,
nsIDocument* parentDoc,
WorkerPrivate* aWorkerPrivate,
nsILoadGroup* loadGroup,
nsIIOService* ios,
nsIScriptSecurityManager* secMan,
@ -190,6 +192,7 @@ ChannelFromScriptURL(nsIPrincipal* principal,
parentDoc,
secFlags,
contentPolicyType,
nullptr, // aPerformanceStorage
loadGroup,
nullptr, // aCallbacks
aLoadFlags,
@ -200,6 +203,11 @@ ChannelFromScriptURL(nsIPrincipal* principal,
MOZ_ASSERT(loadGroup);
MOZ_ASSERT(NS_LoadGroupMatchesPrincipal(loadGroup, principal));
RefPtr<PerformanceStorage> performanceStorage;
if (aWorkerPrivate && !aIsMainScript) {
performanceStorage = aWorkerPrivate->GetPerformanceStorage();
}
if (aClientInfo.isSome()) {
rv = NS_NewChannel(getter_AddRefs(channel),
uri,
@ -208,6 +216,7 @@ ChannelFromScriptURL(nsIPrincipal* principal,
aController,
secFlags,
contentPolicyType,
performanceStorage,
loadGroup,
nullptr, // aCallbacks
aLoadFlags,
@ -218,6 +227,7 @@ ChannelFromScriptURL(nsIPrincipal* principal,
principal,
secFlags,
contentPolicyType,
performanceStorage,
loadGroup,
nullptr, // aCallbacks
aLoadFlags,
@ -991,7 +1001,8 @@ private:
// Only top level workers' main script use the document charset for the
// script uri encoding. Otherwise, default encoding (UTF-8) is applied.
bool useDefaultEncoding = !(!parentWorker && IsMainWorkerScript());
rv = ChannelFromScriptURL(principal, baseURI, parentDoc, loadGroup, ios,
rv = ChannelFromScriptURL(principal, baseURI, parentDoc, mWorkerPrivate,
loadGroup, ios,
secMan, loadInfo.mURL,
mClientInfo, mController,
IsMainWorkerScript(),
@ -2266,8 +2277,8 @@ ChannelFromScriptURLMainThread(nsIPrincipal* aPrincipal,
nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
NS_ASSERTION(secMan, "This should never be null!");
return ChannelFromScriptURL(aPrincipal, aBaseURI, aParentDoc, aLoadGroup,
ios, secMan, aScriptURL, aClientInfo,
return ChannelFromScriptURL(aPrincipal, aBaseURI, aParentDoc, nullptr,
aLoadGroup, ios, secMan, aScriptURL, aClientInfo,
Maybe<ServiceWorkerDescriptor>(),
true, WorkerScript, aMainScriptContentPolicyType,
nsIRequest::LOAD_NORMAL, aDefaultURIEncoding,

Просмотреть файл

@ -730,7 +730,10 @@ CompareNetwork::Initialize(nsIPrincipal* aPrincipal,
// use the TYPE_INTERNAL_SCRIPT content policy types when loading a service
// worker.
rv = NS_NewChannel(getter_AddRefs(mChannel), uri, aPrincipal, secFlags,
contentPolicyType, loadGroup, nullptr /* aCallbacks */,
contentPolicyType,
nullptr, /* aPerformanceStorage */
loadGroup,
nullptr /* aCallbacks */,
mLoadFlags);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;

Просмотреть файл

@ -64,6 +64,7 @@
#include "mozilla/dom/MessagePortBinding.h"
#include "mozilla/dom/nsCSPUtils.h"
#include "mozilla/dom/Performance.h"
#include "mozilla/dom/PerformanceStorageWorker.h"
#include "mozilla/dom/PMessagePort.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/PromiseDebugging.h"
@ -1918,6 +1919,19 @@ WorkerLoadInfo::GetPrincipalAndLoadGroupFromChannel(nsIChannel* aChannel,
nsresult rv = ssm->GetChannelResultPrincipal(aChannel, getter_AddRefs(channelPrincipal));
NS_ENSURE_SUCCESS(rv, rv);
// Every time we call GetChannelResultPrincipal() it will return a different
// null principal for a data URL. We don't want to change the worker's
// principal again, though. Instead just keep the original null principal we
// first got from the channel.
//
// Note, we don't do this by setting principalToInherit on the channel's
// load info because we don't yet have the first null principal when we
// create the channel.
if (mPrincipal && mPrincipal->GetIsNullPrincipal() &&
channelPrincipal->GetIsNullPrincipal()) {
channelPrincipal = mPrincipal;
}
nsCOMPtr<nsILoadGroup> channelLoadGroup;
rv = aChannel->GetLoadGroup(getter_AddRefs(channelLoadGroup));
NS_ENSURE_SUCCESS(rv, rv);
@ -7199,6 +7213,18 @@ WorkerPrivate::DumpCrashInformation(nsACString& aString)
}
}
PerformanceStorage*
WorkerPrivate::GetPerformanceStorage()
{
AssertIsOnMainThread();
if (!mPerformanceStorage) {
mPerformanceStorage = PerformanceStorageWorker::Create(this);
}
return mPerformanceStorage;
}
NS_IMPL_ISUPPORTS_INHERITED0(ExternalRunnableWrapper, WorkerRunnable)
template <class Derived>

Просмотреть файл

@ -68,6 +68,7 @@ class ClientSource;
class Function;
class MessagePort;
class MessagePortIdentifier;
class PerformanceStorage;
class PromiseNativeHandler;
class StructuredCloneHolder;
class WorkerDebuggerGlobalScope;
@ -1067,6 +1068,8 @@ class WorkerPrivate : public WorkerPrivateParent<WorkerPrivate>
// fired on the main thread if the worker script fails to load
nsCOMPtr<nsIRunnable> mLoadFailedRunnable;
RefPtr<PerformanceStorage> mPerformanceStorage;
JS::UniqueChars mDefaultLocale; // nulled during worker JSContext init
TimeStamp mKillTime;
uint32_t mErrorHandlerRecursionCount;
@ -1512,6 +1515,9 @@ public:
void
ExecutionReady();
PerformanceStorage*
GetPerformanceStorage();
private:
WorkerPrivate(WorkerPrivate* aParent,
const nsAString& aScriptURL, bool aIsChromeWorker,

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше