Files
react-native-devtools-frontend/front_end/sdk/IssuesModel.js
T
Kateryna Prokopenko 314d6b7155 [issues] Get target for each issue individually (instead of main target) to get correct node in case of out of process iframes
We lose information about the target in aggregated issue, so for now create primary key from issue details to get the right target.

Bug: chromium:1115421
Change-Id: I2cde1f3db599ee989e45f36518316ba9693e76ab
Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/2352726
Reviewed-by: Sigurd Schneider <sigurds@chromium.org>
Commit-Queue: Kateryna Prokopenko <kprokopenko@google.com>
2020-08-19 07:32:37 +00:00

198 lines
6.1 KiB
JavaScript

// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {ContentSecurityPolicyIssue} from './ContentSecurityPolicyIssue.js';
import {CrossOriginEmbedderPolicyIssue, isCrossOriginEmbedderPolicyIssue} from './CrossOriginEmbedderPolicyIssue.js';
import {HeavyAdIssue} from './HeavyAdIssue.js';
import {Issue} from './Issue.js'; // eslint-disable-line no-unused-vars
import {MixedContentIssue} from './MixedContentIssue.js';
import {SameSiteCookieIssue} from './SameSiteCookieIssue.js';
import {Capability, SDKModel, Target} from './SDKModel.js'; // eslint-disable-line no-unused-vars
/**
* The `IssuesModel` is a thin dispatch that does not store issues, but only creates the representation
* class (usually derived from `Issue`) and passes the instances on via a dispatched event.
* We chose this approach here because the lifetime of the Model is tied to the target, but DevTools
* wants to preserve issues for targets (e.g. iframes) that are already gone as well.
* @implements {ProtocolProxyApiWorkaround_AuditsDispatcher}
*/
export class IssuesModel extends SDKModel {
/**
* @param {!Target} target
*/
constructor(target) {
super(target);
this._enabled = false;
/** @type {*} */
this._auditsAgent = null;
this.ensureEnabled();
this._disposed = false;
}
/**
* @return {!Protocol.UsesObjectNotation}
*/
usesObjectNotation() {
return true;
}
ensureEnabled() {
if (this._enabled) {
return;
}
this._enabled = true;
this.target().registerAuditsDispatcher(this);
this._auditsAgent = this.target().auditsAgent();
this._auditsAgent.invoke_enable();
}
/**
* @override
* @param {!Protocol.Audits.IssueAddedEvent} issueAddedEvent
*/
issueAdded(issueAddedEvent) {
const issues = this._createIssuesFromProtocolIssue(issueAddedEvent.issue);
for (const issue of issues) {
this.addIssue(issue);
}
}
/**
* @param {!Issue} issue
*/
addIssue(issue) {
this.dispatchEventToListeners(Events.IssueAdded, {issuesModel: this, issue});
}
/**
* Each issue reported by the backend can result in multiple {!Issue} instances.
* Handlers are simple functions hard-coded into a map.
* @param {!Protocol.Audits.InspectorIssue} inspectorIssue} inspectorIssue
* @return {!Array<!Issue>}
*/
_createIssuesFromProtocolIssue(inspectorIssue) {
const handler = issueCodeHandlers.get(inspectorIssue.code);
if (handler) {
return handler(this, inspectorIssue.details);
}
console.warn(`No handler registered for issue code ${inspectorIssue.code}`);
return [];
}
/**
* @override
*/
dispose() {
super.dispose();
this._disposed = true;
}
/**
* @returns {?Target}
*/
getTargetIfNotDisposed() {
if (!this._disposed) {
return this.target();
}
return null;
}
}
/**
* @param {!IssuesModel} issuesModel
* @param {!Protocol.Audits.InspectorIssueDetails} inspectorDetails
* @return {!Array<!Issue>}
*/
function createIssuesForSameSiteCookieIssue(issuesModel, inspectorDetails) {
const sameSiteDetails = inspectorDetails.sameSiteCookieIssueDetails;
if (!sameSiteDetails) {
console.warn('SameSite issue without details received.');
return [];
}
return SameSiteCookieIssue.createIssuesFromSameSiteDetails(sameSiteDetails);
}
/**
* @param {!IssuesModel} issuesModel
* @param {!Protocol.Audits.InspectorIssueDetails} inspectorDetails
* @return {!Array<!Issue>}
*/
function createIssuesForMixedContentIssue(issuesModel, inspectorDetails) {
const mixedContentDetails = inspectorDetails.mixedContentIssueDetails;
if (!mixedContentDetails) {
console.warn('Mixed content issue without details received.');
return [];
}
return [new MixedContentIssue(mixedContentDetails)];
}
/**
* @param {!IssuesModel} issuesModel
* @param {!Protocol.Audits.InspectorIssueDetails} inspectorDetails
* @return {!Array<!Issue>}
*/
function createIssuesForContentSecurityPolicyIssue(issuesModel, inspectorDetails) {
const cspDetails = inspectorDetails.contentSecurityPolicyIssueDetails;
if (!cspDetails) {
console.warn('Content security policy issue without details received.');
return [];
}
return [new ContentSecurityPolicyIssue(cspDetails, issuesModel)];
}
/**
* @param {!IssuesModel} issuesModel
* @param {!Protocol.Audits.InspectorIssueDetails} inspectorDetails
* @return {!Array<!Issue>}
*/
function createIssuesForHeavyAdIssue(issuesModel, inspectorDetails) {
const heavyAdIssueDetails = inspectorDetails.heavyAdIssueDetails;
if (!heavyAdIssueDetails) {
console.warn('Heavy Ad issue without details received.');
return [];
}
return [new HeavyAdIssue(heavyAdIssueDetails)];
}
/**
* @param {!IssuesModel} issuesModel
* @param {!Protocol.Audits.InspectorIssueDetails} inspectorDetails
* @return {!Array<!Issue>}
*/
function createIssuesForBlockedByResponseIssue(issuesModel, inspectorDetails) {
const blockedByResponseIssueDetails = inspectorDetails.blockedByResponseIssueDetails;
if (!blockedByResponseIssueDetails) {
console.warn('BlockedByResponse issue without details received.');
return [];
}
if (isCrossOriginEmbedderPolicyIssue(blockedByResponseIssueDetails.reason)) {
return [new CrossOriginEmbedderPolicyIssue(blockedByResponseIssueDetails)];
}
return [];
}
/**
* @type {!Map<!Protocol.Audits.InspectorIssueCode, function(!IssuesModel, !Protocol.Audits.InspectorIssueDetails):!Array<!Issue>>}
*/
const issueCodeHandlers = new Map([
[Protocol.Audits.InspectorIssueCode.SameSiteCookieIssue, createIssuesForSameSiteCookieIssue],
[Protocol.Audits.InspectorIssueCode.MixedContentIssue, createIssuesForMixedContentIssue],
[Protocol.Audits.InspectorIssueCode.HeavyAdIssue, createIssuesForHeavyAdIssue],
[Protocol.Audits.InspectorIssueCode.ContentSecurityPolicyIssue, createIssuesForContentSecurityPolicyIssue],
[Protocol.Audits.InspectorIssueCode.BlockedByResponseIssue, createIssuesForBlockedByResponseIssue],
]);
/** @enum {symbol} */
export const Events = {
IssueAdded: Symbol('IssueAdded'),
};
SDKModel.register(IssuesModel, Capability.Audits, true);