зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to autoland
This commit is contained in:
Коммит
39d63fc827
|
@ -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,
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче