blob: f46263f6421d2f2dad846a702ace6b2ff10e2b23 [file] [log] [blame]
Wolfgang Beyer760462e2020-07-13 15:01:351// Copyright 2020 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Wolfgang Beyer2ed11a42020-09-30 07:24:545import * as Bindings from '../bindings/bindings.js';
Sigurd Schneider1e5ad282020-07-17 11:52:086import * as Common from '../common/common.js';
Sigurd Schneiderfc2bd212020-08-12 12:58:417import * as Network from '../network/network.js';
Wolfgang Beyer95951c4d2020-10-23 08:00:068import * as Root from '../root/root.js';
Wolfgang Beyer760462e2020-07-13 15:01:359import * as SDK from '../sdk/sdk.js'; // eslint-disable-line no-unused-vars
10import * as UI from '../ui/ui.js';
Sigurd Schneider1e5ad282020-07-17 11:52:0811import * as Workspace from '../workspace/workspace.js';
Wolfgang Beyer760462e2020-07-13 15:01:3512
Sigurd Schneideraef29822020-08-20 14:01:1313/**
14 * @param {boolean} b
15 */
16const booleanToYesNo = b => b ? ls`Yes` : ls`No`;
17
Sigurd Schneider1e5ad282020-07-17 11:52:0818export class FrameDetailsView extends UI.ThrottledWidget.ThrottledWidget {
Wolfgang Beyer760462e2020-07-13 15:01:3519 /**
20 * @param {!SDK.ResourceTreeModel.ResourceTreeFrame} frame
21 */
22 constructor(frame) {
23 super();
Wolfgang Beyer95951c4d2020-10-23 08:00:0624 this._protocolMonitorExperimentEnabled = Root.Runtime.experiments.isEnabled('protocolMonitor');
Wolfgang Beyer5ac564d2020-09-28 13:49:3525 this.registerRequiredCSS('resources/frameDetailsReportView.css');
Sigurd Schneider1e5ad282020-07-17 11:52:0826 this._frame = frame;
Wolfgang Beyer5ac564d2020-09-28 13:49:3527 this.contentElement.classList.add('frame-details-container');
28
Wolfgang Beyer760462e2020-07-13 15:01:3529 this._reportView = new UI.ReportView.ReportView(frame.displayName());
Sigurd Schneider1e5ad282020-07-17 11:52:0830 this._reportView.registerRequiredCSS('resources/frameDetailsReportView.css');
Wolfgang Beyer760462e2020-07-13 15:01:3531 this._reportView.show(this.contentElement);
Wolfgang Beyer5ac564d2020-09-28 13:49:3532 this._reportView.element.classList.add('frame-details-report-container');
Wolfgang Beyer760462e2020-07-13 15:01:3533
Sigurd Schneider1e5ad282020-07-17 11:52:0834 this._generalSection = this._reportView.appendSection(ls`Document`);
35 this._urlFieldValue = this._generalSection.appendField(ls`URL`);
Wolfgang Beyer5ac564d2020-09-28 13:49:3536 this._urlStringElement = this._urlFieldValue.createChild('div', 'text-ellipsis');
Sigurd Schneiderfc2bd212020-08-12 12:58:4137 this._unreachableURL = this._generalSection.appendField(ls`Unreachable URL`);
Wolfgang Beyer5ac564d2020-09-28 13:49:3538 const originFieldValue = this._generalSection.appendField(ls`Origin`);
39 this._originStringElement = originFieldValue.createChild('div', 'text-ellipsis');
Wolfgang Beyeraaa82a72020-09-24 12:22:0640 this._ownerFieldValue = this._generalSection.appendField(ls`Owner Element`);
Sigurd Schneiderf1aba722020-07-20 09:03:1941 this._adStatus = this._generalSection.appendField(ls`Ad Status`);
Sigurd Schneider3cc78e22020-09-18 10:44:1342
Sigurd Schneider680531a2020-08-19 08:08:5143 this._isolationSection = this._reportView.appendSection(ls`Security & Isolation`);
Sigurd Schneideraef29822020-08-20 14:01:1344 this._secureContext = this._isolationSection.appendField(ls`Secure Context`);
Sigurd Schneidercea65762020-10-19 09:47:5045 this._crossOriginIsolatedContext = this._isolationSection.appendField(ls`Cross-Origin Isolated`);
Sigurd Schneider680531a2020-08-19 08:08:5146 this._coepPolicy = this._isolationSection.appendField(ls`Cross-Origin Embedder Policy`);
47 this._coopPolicy = this._isolationSection.appendField(ls`Cross-Origin Opener Policy`);
Sigurd Schneider3fa2f7f2020-10-19 14:36:0248
49 this._apiAvailability = this._reportView.appendSection(ls`API availablity`);
50 const summaryRow = this._apiAvailability.appendRow();
51 const summaryText = ls`Availability of certain APIs depends on the document being cross-origin isolated.`;
52 const link = 'https://web.dev/why-coop-coep/';
53 summaryRow.appendChild(UI.Fragment.html`<div>${summaryText} ${UI.XLink.XLink.create(link, ls`Learn more`)}</div>`);
Wolfgang Beyer95951c4d2020-10-23 08:00:0654
55 if (this._protocolMonitorExperimentEnabled) {
56 this._additionalInfo = this._reportView.appendSection(ls`Additional Information`);
57 this._additionalInfo.setTitle(
58 ls`Additional Information`,
59 ls`This additional (debugging) information is shown because the 'Protocol Monitor' experiment is enabled.`);
60 const frameIDField = this._additionalInfo.appendField(ls`Frame ID`);
61 frameIDField.textContent = frame.id;
62 }
Sigurd Schneider1e5ad282020-07-17 11:52:0863 this.update();
64 }
65
66 /**
67 * @override
68 * @return {!Promise<?>}
69 */
70 async doUpdate() {
Wolfgang Beyer5ac564d2020-09-28 13:49:3571 this._urlFieldValue.removeChildren();
72 this._urlStringElement.textContent = this._frame.url;
73 this._urlStringElement.title = this._frame.url;
74 this._urlFieldValue.appendChild(this._urlStringElement);
Sigurd Schneiderfc2bd212020-08-12 12:58:4175 if (!this._frame.unreachableUrl()) {
Wolfgang Beyer2ed11a42020-09-30 07:24:5476 const sourceCode = this.uiSourceCodeForFrame(this._frame);
Wolfgang Beyeref272ee2020-10-15 15:52:5077 const revealSource = linkifyIcon(
Wolfgang Beyeraaa82a72020-09-24 12:22:0678 'mediumicon-sources-panel', ls`Click to reveal in Sources panel`, () => Common.Revealer.reveal(sourceCode));
79 this._urlFieldValue.appendChild(revealSource);
Sigurd Schneiderfc2bd212020-08-12 12:58:4180 }
Sigurd Schneider7929aeb2020-08-18 13:53:1881 FrameDetailsView.maybeAppendLinkToRequest(this._urlFieldValue, this._frame.resourceForURL(this._frame.url));
Sigurd Schneiderfc2bd212020-08-12 12:58:4182 this._maybeAppendLinkForUnreachableUrl();
Sigurd Schneider7929aeb2020-08-18 13:53:1883 if (this._frame.securityOrigin && this._frame.securityOrigin !== '://') {
Wolfgang Beyer5ac564d2020-09-28 13:49:3584 this._originStringElement.textContent = this._frame.securityOrigin;
85 this._originStringElement.title = this._frame.securityOrigin;
Sigurd Schneider7929aeb2020-08-18 13:53:1886 this._generalSection.setFieldVisible(ls`Origin`, true);
87 } else {
88 this._generalSection.setFieldVisible(ls`Origin`, false);
89 }
Sigurd Schneiderf1aba722020-07-20 09:03:1990 this._updateAdStatus();
Wolfgang Beyeraaa82a72020-09-24 12:22:0691 this._ownerFieldValue.removeChildren();
Wolfgang Beyeref272ee2020-10-15 15:52:5092 const linkElement = await maybeCreateLinkToElementsPanel(this._frame);
93 if (linkElement) {
94 this._ownerFieldValue.appendChild(linkElement);
Sigurd Schneider1e5ad282020-07-17 11:52:0895 }
Sigurd Schneider680531a2020-08-19 08:08:5196 await this._updateCoopCoepStatus();
Sigurd Schneideraef29822020-08-20 14:01:1397 this._updateContextStatus();
Sigurd Schneider680531a2020-08-19 08:08:5198 }
99
Sigurd Schneider3cc78e22020-09-18 10:44:13100 /**
Wolfgang Beyer2ed11a42020-09-30 07:24:54101 * @param {!SDK.ResourceTreeModel.ResourceTreeFrame} frame
102 * @return {?Workspace.UISourceCode.UISourceCode}
103 */
104 uiSourceCodeForFrame(frame) {
105 for (const project of Workspace.Workspace.WorkspaceImpl.instance().projects()) {
106 const projectTarget = Bindings.NetworkProject.NetworkProject.getTargetForProject(project);
107 if (projectTarget && projectTarget === frame.resourceTreeModel().target()) {
108 const uiSourceCode = project.uiSourceCodeForURL(frame.url);
109 if (uiSourceCode) {
110 return uiSourceCode;
111 }
112 }
113 }
114 return null;
115 }
116
117 /**
Sigurd Schneider3cc78e22020-09-18 10:44:13118 *
119 * @param {!HTMLElement} field
120 * @param {function((!Protocol.Network.CrossOriginEmbedderPolicyValue|!Protocol.Network.CrossOriginOpenerPolicyValue)):boolean} isEnabled
121 * @param {!Protocol.Network.CrossOriginEmbedderPolicyStatus|!Protocol.Network.CrossOriginOpenerPolicyStatus} info
122 */
123 static fillCrossOriginPolicy(field, isEnabled, info) {
124 const enabled = isEnabled(info.value);
125 field.textContent = enabled ? info.value : info.reportOnlyValue;
126 if (!enabled && isEnabled(info.reportOnlyValue)) {
127 const reportOnly = document.createElement('span');
128 reportOnly.classList.add('inline-comment');
129 reportOnly.textContent = 'report-only';
130 field.appendChild(reportOnly);
131 }
132 const endpoint = enabled ? info.reportingEndpoint : info.reportOnlyReportingEndpoint;
133 if (endpoint) {
134 const reportingEndpointPrefix = field.createChild('span', 'inline-name');
135 reportingEndpointPrefix.textContent = ls`reporting to`;
Wolfgang Beyer9a64fc62020-10-06 14:54:43136 const reportingEndpointName = field.createChild('span');
Sigurd Schneider3cc78e22020-09-18 10:44:13137 reportingEndpointName.textContent = endpoint;
138 }
139 }
140
Sigurd Schneider680531a2020-08-19 08:08:51141 async _updateCoopCoepStatus() {
Sigurd Schneider5a5b7352020-10-05 11:13:05142 const model = this._frame.resourceTreeModel().target().model(SDK.NetworkManager.NetworkManager);
143 const info = model && await model.getSecurityIsolationStatus(this._frame.id);
Sigurd Schneider3cc78e22020-09-18 10:44:13144 if (!info) {
145 return;
146 }
147 /**
148 * @param {!Protocol.Network.CrossOriginEmbedderPolicyValue|!Protocol.Network.CrossOriginOpenerPolicyValue} value
149 */
150 const coepIsEnabled = value => value !== Protocol.Network.CrossOriginEmbedderPolicyValue.None;
151 FrameDetailsView.fillCrossOriginPolicy(this._coepPolicy, coepIsEnabled, info.coep);
152 /**
153 * @param {!Protocol.Network.CrossOriginEmbedderPolicyValue|!Protocol.Network.CrossOriginOpenerPolicyValue} value
154 */
155 const coopIsEnabled = value => value !== Protocol.Network.CrossOriginOpenerPolicyValue.UnsafeNone;
156 FrameDetailsView.fillCrossOriginPolicy(this._coopPolicy, coopIsEnabled, info.coop);
Wolfgang Beyer760462e2020-07-13 15:01:35157 }
Sigurd Schneiderf1aba722020-07-20 09:03:19158
Sigurd Schneider7929aeb2020-08-18 13:53:18159 /**
Sigurd Schneideraef29822020-08-20 14:01:13160 * @param {?Protocol.Page.SecureContextType} type
161 * @returns {?string}
162 */
163 _explanationFromSecureContextType(type) {
164 switch (type) {
165 case Protocol.Page.SecureContextType.Secure:
166 return null;
167 case Protocol.Page.SecureContextType.SecureLocalhost:
168 return ls`Localhost is always a secure context`;
169 case Protocol.Page.SecureContextType.InsecureAncestor:
170 return ls`A frame ancestor is an insecure context`;
171 case Protocol.Page.SecureContextType.InsecureScheme:
172 return ls`The frame's scheme is insecure`;
173 }
174 return null;
175 }
176
177 _updateContextStatus() {
178 if (this._frame.unreachableUrl()) {
179 this._isolationSection.setFieldVisible(ls`Secure Context`, false);
Sigurd Schneidercea65762020-10-19 09:47:50180 this._isolationSection.setFieldVisible(ls`Cross-Origin Isolated`, false);
Sigurd Schneideraef29822020-08-20 14:01:13181 return;
182 }
183 this._isolationSection.setFieldVisible(ls`Secure Context`, true);
Sigurd Schneidercea65762020-10-19 09:47:50184 this._isolationSection.setFieldVisible(ls`Cross-Origin Isolated`, true);
185
Sigurd Schneideraef29822020-08-20 14:01:13186 this._secureContext.textContent = booleanToYesNo(this._frame.isSecureContext());
187 const secureContextExplanation = this._explanationFromSecureContextType(this._frame.getSecureContextType());
188 if (secureContextExplanation) {
Sigurd Schneidercea65762020-10-19 09:47:50189 const secureContextType = this._secureContext.createChild('span', 'inline-comment');
Sigurd Schneideraef29822020-08-20 14:01:13190 secureContextType.textContent = secureContextExplanation;
191 }
Sigurd Schneidercea65762020-10-19 09:47:50192 this._crossOriginIsolatedContext.textContent = booleanToYesNo(this._frame.isCrossOriginIsolated());
Sigurd Schneideraef29822020-08-20 14:01:13193 }
194
195 /**
Sigurd Schneider7929aeb2020-08-18 13:53:18196 * @param {!Element} element
197 * @param {?SDK.Resource.Resource} resource
198 */
199 static maybeAppendLinkToRequest(element, resource) {
200 if (resource && resource.request) {
201 const request = resource.request;
Wolfgang Beyeref272ee2020-10-15 15:52:50202 const revealRequest = linkifyIcon(
Wolfgang Beyeraaa82a72020-09-24 12:22:06203 'mediumicon-network-panel', ls`Click to reveal in Network panel`,
204 () => Network.NetworkPanel.NetworkPanel.selectAndShowRequest(request, Network.NetworkItemView.Tabs.Headers));
Wolfgang Beyer0c589cc2020-08-27 12:41:15205 element.appendChild(revealRequest);
Sigurd Schneider7929aeb2020-08-18 13:53:18206 }
207 }
208
Sigurd Schneiderfc2bd212020-08-12 12:58:41209 _maybeAppendLinkForUnreachableUrl() {
210 if (!this._frame.unreachableUrl()) {
211 this._generalSection.setFieldVisible(ls`Unreachable URL`, false);
212 return;
213 }
214 this._generalSection.setFieldVisible(ls`Unreachable URL`, true);
215 this._unreachableURL.textContent = this._frame.unreachableUrl();
216 const unreachableUrl = Common.ParsedURL.ParsedURL.fromString(this._frame.unreachableUrl());
217 if (!unreachableUrl) {
218 return;
219 }
Wolfgang Beyer0c589cc2020-08-27 12:41:15220
Wolfgang Beyeref272ee2020-10-15 15:52:50221 const revealRequest = linkifyIcon(
Wolfgang Beyeraaa82a72020-09-24 12:22:06222 'mediumicon-network-panel', ls`Click to reveal in Network panel (might require page reload)`, () => {
223 Network.NetworkPanel.NetworkPanel.revealAndFilter([
224 {
225 filterType: 'domain',
226 filterValue: unreachableUrl.domain(),
227 },
228 {
229 filterType: null,
230 filterValue: unreachableUrl.path,
231 }
232 ]);
233 });
234 this._unreachableURL.appendChild(revealRequest);
Sigurd Schneiderfc2bd212020-08-12 12:58:41235 }
236
Sigurd Schneiderf1aba722020-07-20 09:03:19237 _updateAdStatus() {
238 switch (this._frame.adFrameType()) {
239 case Protocol.Page.AdFrameType.Root:
240 this._generalSection.setFieldVisible(ls`Ad Status`, true);
241 this._adStatus.textContent = ls`root`;
242 this._adStatus.title = ls`This frame has been identified as the root frame of an ad`;
243 break;
244 case Protocol.Page.AdFrameType.Child:
245 this._generalSection.setFieldVisible(ls`Ad Status`, true);
246 this._adStatus.textContent = ls`child`;
247 this._adStatus.title = ls`This frame has been identified as the a child frame of an ad`;
248 break;
249 default:
250 this._generalSection.setFieldVisible(ls`Ad Status`, false);
251 break;
252 }
253 }
Wolfgang Beyer760462e2020-07-13 15:01:35254}
Wolfgang Beyer3b4747f2020-08-12 07:30:46255
Wolfgang Beyeref272ee2020-10-15 15:52:50256/**
257 * @param {string} iconType
258 * @param {string} title
259 * @param {function():(void|!Promise<void>)} eventHandler
260 * @return {!Element}
261 */
262function linkifyIcon(iconType, title, eventHandler) {
263 const icon = UI.Icon.Icon.create(iconType, 'icon-link devtools-link');
264 const span = document.createElement('span');
265 span.title = title;
266 span.classList.add('devtools-link');
267 span.tabIndex = 0;
268 span.appendChild(icon);
269 span.addEventListener('click', () => eventHandler());
270 span.addEventListener('keydown', event => {
271 if (isEnterKey(event)) {
272 eventHandler();
273 }
274 });
275 return span;
276}
277
278/**
279 * @param {!SDK.ResourceTreeModel.ResourceTreeFrame|!Protocol.Page.FrameId|undefined} opener
280 * @return {!Promise<?Element>}
281 */
282async function maybeCreateLinkToElementsPanel(opener) {
283 /** @type {?SDK.ResourceTreeModel.ResourceTreeFrame} */
284 let openerFrame = null;
285 if (opener instanceof SDK.ResourceTreeModel.ResourceTreeFrame) {
286 openerFrame = opener;
287 } else if (opener) {
288 openerFrame = SDK.FrameManager.FrameManager.instance().getFrame(opener);
289 }
290 if (!openerFrame) {
291 return null;
292 }
293 const linkTargetDOMNode = await openerFrame.getOwnerDOMNodeOrDocument();
294 if (!linkTargetDOMNode) {
295 return null;
296 }
297 const linkElement = linkifyIcon(
298 'mediumicon-elements-panel', ls`Click to reveal in Elements panel`,
299 () => Common.Revealer.reveal(linkTargetDOMNode));
300 const label = document.createElement('span');
301 label.textContent = `<${linkTargetDOMNode.nodeName().toLocaleLowerCase()}>`;
302 linkElement.insertBefore(label, linkElement.firstChild);
303 linkElement.addEventListener('mouseenter', () => {
304 if (openerFrame) {
305 openerFrame.highlight();
306 }
307 });
308 linkElement.addEventListener('mouseleave', () => {
309 SDK.OverlayModel.OverlayModel.hideDOMNodeHighlight();
310 });
311 return linkElement;
312}
313
Wolfgang Beyer3b4747f2020-08-12 07:30:46314export class OpenedWindowDetailsView extends UI.ThrottledWidget.ThrottledWidget {
315 /**
316 * @param {!Protocol.Target.TargetInfo} targetInfo
317 * @param {boolean} isWindowClosed
318 */
319 constructor(targetInfo, isWindowClosed) {
320 super();
321 this._targetInfo = targetInfo;
322 this._isWindowClosed = isWindowClosed;
Wolfgang Beyer84858862020-10-15 10:15:45323 this.registerRequiredCSS('resources/frameDetailsReportView.css');
324 this.contentElement.classList.add('frame-details-container');
Wolfgang Beyer3b4747f2020-08-12 07:30:46325 this._reportView = new UI.ReportView.ReportView(this.buildTitle());
326 this._reportView.registerRequiredCSS('resources/frameDetailsReportView.css');
327 this._reportView.show(this.contentElement);
Wolfgang Beyer84858862020-10-15 10:15:45328 this._reportView.element.classList.add('frame-details-report-container');
Wolfgang Beyer3b4747f2020-08-12 07:30:46329
330 this._documentSection = this._reportView.appendSection(ls`Document`);
331 this._URLFieldValue = this._documentSection.appendField(ls`URL`);
332
333 this._securitySection = this._reportView.appendSection(ls`Security`);
Wolfgang Beyeref272ee2020-10-15 15:52:50334 this._openerElementField = this._securitySection.appendField(ls`Opener Frame`);
335 this._securitySection.setFieldVisible(ls`Opener Frame`, false);
Wolfgang Beyer3b4747f2020-08-12 07:30:46336 this._hasDOMAccessValue = this._securitySection.appendField(ls`Access to opener`);
Wolfgang Beyeref272ee2020-10-15 15:52:50337 this._hasDOMAccessValue.title = ls`Shows whether the opened window is able to access its opener and vice versa`;
Wolfgang Beyer3b4747f2020-08-12 07:30:46338 this.update();
339 }
340
341 /**
342 * @override
343 * @return {!Promise<?>}
344 */
345 async doUpdate() {
346 this._reportView.setTitle(this.buildTitle());
347 this._URLFieldValue.textContent = this._targetInfo.url;
Sigurd Schneideraef29822020-08-20 14:01:13348 this._hasDOMAccessValue.textContent = booleanToYesNo(this._targetInfo.canAccessOpener);
Wolfgang Beyeref272ee2020-10-15 15:52:50349 this.maybeDisplayOpenerFrame();
350 }
351
352 async maybeDisplayOpenerFrame() {
353 this._openerElementField.removeChildren();
354 const linkElement = await maybeCreateLinkToElementsPanel(this._targetInfo.openerFrameId);
355 if (linkElement) {
356 this._openerElementField.append(linkElement);
357 this._securitySection.setFieldVisible(ls`Opener Frame`, true);
358 return;
359 }
360 this._securitySection.setFieldVisible(ls`Opener Frame`, false);
Wolfgang Beyer3b4747f2020-08-12 07:30:46361 }
362
363 /**
364 * @return {string}
365 */
366 buildTitle() {
367 let title = this._targetInfo.title || ls`Window without title`;
368 if (this._isWindowClosed) {
369 title += ` (${ls`closed`})`;
370 }
371 return title;
372 }
373
374 /**
375 * @param {boolean} isWindowClosed
376 */
377 setIsWindowClosed(isWindowClosed) {
378 this._isWindowClosed = isWindowClosed;
379 }
380
381 /**
382 * @param {!Protocol.Target.TargetInfo} targetInfo
383 */
384 setTargetInfo(targetInfo) {
385 this._targetInfo = targetInfo;
386 }
387}
Wolfgang Beyerffd66902020-10-12 14:22:02388
389export class WorkerDetailsView extends UI.ThrottledWidget.ThrottledWidget {
390 /**
391 * @param {!Protocol.Target.TargetInfo} targetInfo
392 */
393 constructor(targetInfo) {
394 super();
395 this._targetInfo = targetInfo;
Wolfgang Beyer84858862020-10-15 10:15:45396 this.registerRequiredCSS('resources/frameDetailsReportView.css');
397 this.contentElement.classList.add('frame-details-container');
Wolfgang Beyerffd66902020-10-12 14:22:02398 this._reportView = new UI.ReportView.ReportView(this._targetInfo.title || this._targetInfo.url || ls`worker`);
399 this._reportView.registerRequiredCSS('resources/frameDetailsReportView.css');
400 this._reportView.show(this.contentElement);
Wolfgang Beyer84858862020-10-15 10:15:45401 this._reportView.element.classList.add('frame-details-report-container');
Wolfgang Beyerffd66902020-10-12 14:22:02402
403 this._documentSection = this._reportView.appendSection(ls`Document`);
404 this._URLFieldValue = this._documentSection.appendField(ls`URL`);
405 this._URLFieldValue.textContent = this._targetInfo.url;
406 }
407}