blob: 843b38f31d8f90ad1eddde122d20e2f78c05745c [file] [log] [blame]
Blink Reformat4c46d092018-04-07 15:32:371/*
2 * Copyright (C) 2011 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
Tim van der Lippe16a03772020-02-03 12:14:3431import * as Bindings from '../bindings/bindings.js';
32import * as Common from '../common/common.js';
33import * as Components from '../components/components.js';
34import * as Host from '../host/host.js';
Tim van der Lippe93b57c32020-02-20 17:38:4435import * as Platform from '../platform/platform.js';
Simon Zünd18213422020-03-19 05:57:4536import * as ProtocolClient from '../protocol_client/protocol_client.js'; // eslint-disable-line no-unused-vars
Tim van der Lipped71c22d2020-03-19 12:29:1937import * as Root from '../root/root.js'; // eslint-disable-line no-unused-vars
Tim van der Lippe16a03772020-02-03 12:14:3438import * as SDK from '../sdk/sdk.js';
39import * as TextUtils from '../text_utils/text_utils.js'; // eslint-disable-line no-unused-vars
40import * as UI from '../ui/ui.js';
41import * as Workspace from '../workspace/workspace.js';
42
Tim van der Lippea6110922020-01-09 15:38:3943import {ExtensionButton, ExtensionPanel, ExtensionSidebarPane} from './ExtensionPanel.js';
44import {ExtensionTraceProvider, TracingSession} from './ExtensionTraceProvider.js'; // eslint-disable-line no-unused-vars
45
Andrey Kosyakov4d123402020-04-01 04:38:3746const extensionOriginSymbol = Symbol('extensionOrigin');
47
Andrey Kosyakov9129f942020-05-27 19:41:4148const kAllowedOrigins = [
49 'chrome://newtab',
50 'chrome://new-tab-page',
51].map(url => (new URL(url)).origin);
52
Blink Reformat4c46d092018-04-07 15:32:3753/**
54 * @unrestricted
55 */
Tim van der Lippe16a03772020-02-03 12:14:3456export class ExtensionServer extends Common.ObjectWrapper.ObjectWrapper {
Blink Reformat4c46d092018-04-07 15:32:3757 /**
58 * @suppressGlobalPropertiesCheck
59 */
60 constructor() {
61 super();
62 this._clientObjects = {};
63 this._handlers = {};
Simon Zünde18b5612020-03-03 09:02:3664 /** @type {!Map<string, !Set<!MessagePort>>} */
65 this._subscribers = new Map();
Blink Reformat4c46d092018-04-07 15:32:3766 this._subscriptionStartHandlers = {};
67 this._subscriptionStopHandlers = {};
Tim van der Lippe990f2d12020-03-26 13:58:2668 /** @type {!Map<string, !Map<string, *>>} */
69 this._extraHeaders = new Map();
Blink Reformat4c46d092018-04-07 15:32:3770 this._requests = {};
71 this._lastRequestId = 0;
Andrey Kosyakov4d123402020-04-01 04:38:3772 /** @type {!Map<string, !{name: string}>} */
73 this._registeredExtensions = new Map();
Tim van der Lippe226fc222019-10-10 12:17:1274 this._status = new ExtensionStatus();
Tim van der Lippea6110922020-01-09 15:38:3975 /** @type {!Array<!ExtensionSidebarPane>} */
Blink Reformat4c46d092018-04-07 15:32:3776 this._sidebarPanes = [];
Tim van der Lippea6110922020-01-09 15:38:3977 /** @type {!Array<!ExtensionTraceProvider>} */
Blink Reformat4c46d092018-04-07 15:32:3778 this._traceProviders = [];
Tim van der Lippea6110922020-01-09 15:38:3979 /** @type {!Map<string, !TracingSession>} */
Blink Reformat4c46d092018-04-07 15:32:3780 this._traceSessions = new Map();
Andrey Kosyakova08cb9b2020-04-01 21:49:5281 // TODO(caseq): properly unload extensions when we disable them.
82 this._extensionsEnabled = true;
Blink Reformat4c46d092018-04-07 15:32:3783
84 const commands = Extensions.extensionAPI.Commands;
85
86 this._registerHandler(commands.AddRequestHeaders, this._onAddRequestHeaders.bind(this));
87 this._registerHandler(commands.AddTraceProvider, this._onAddTraceProvider.bind(this));
88 this._registerHandler(commands.ApplyStyleSheet, this._onApplyStyleSheet.bind(this));
89 this._registerHandler(commands.CompleteTraceSession, this._onCompleteTraceSession.bind(this));
90 this._registerHandler(commands.CreatePanel, this._onCreatePanel.bind(this));
91 this._registerHandler(commands.CreateSidebarPane, this._onCreateSidebarPane.bind(this));
92 this._registerHandler(commands.CreateToolbarButton, this._onCreateToolbarButton.bind(this));
93 this._registerHandler(commands.EvaluateOnInspectedPage, this._onEvaluateOnInspectedPage.bind(this));
94 this._registerHandler(commands.ForwardKeyboardEvent, this._onForwardKeyboardEvent.bind(this));
95 this._registerHandler(commands.GetHAR, this._onGetHAR.bind(this));
96 this._registerHandler(commands.GetPageResources, this._onGetPageResources.bind(this));
97 this._registerHandler(commands.GetRequestContent, this._onGetRequestContent.bind(this));
98 this._registerHandler(commands.GetResourceContent, this._onGetResourceContent.bind(this));
99 this._registerHandler(commands.Reload, this._onReload.bind(this));
100 this._registerHandler(commands.SetOpenResourceHandler, this._onSetOpenResourceHandler.bind(this));
101 this._registerHandler(commands.SetResourceContent, this._onSetResourceContent.bind(this));
102 this._registerHandler(commands.SetSidebarHeight, this._onSetSidebarHeight.bind(this));
103 this._registerHandler(commands.SetSidebarContent, this._onSetSidebarContent.bind(this));
104 this._registerHandler(commands.SetSidebarPage, this._onSetSidebarPage.bind(this));
105 this._registerHandler(commands.ShowPanel, this._onShowPanel.bind(this));
106 this._registerHandler(commands.Subscribe, this._onSubscribe.bind(this));
107 this._registerHandler(commands.OpenResource, this._onOpenResource.bind(this));
108 this._registerHandler(commands.Unsubscribe, this._onUnsubscribe.bind(this));
109 this._registerHandler(commands.UpdateButton, this._onUpdateButton.bind(this));
110 window.addEventListener('message', this._onWindowMessage.bind(this), false); // Only for main window.
111
Tim van der Lippe647e33b2019-11-04 19:02:31112 /** @suppress {checkTypes} */
Tim van der Lippe8a0cc702019-11-05 17:53:10113 const existingTabId =
114 window.DevToolsAPI && window.DevToolsAPI.getInspectedTabId && window.DevToolsAPI.getInspectedTabId();
Tim van der Lippe647e33b2019-11-04 19:02:31115
116 if (existingTabId) {
117 this._setInspectedTabId({data: existingTabId});
118 }
Tim van der Lippe16a03772020-02-03 12:14:34119 Host.InspectorFrontendHost.InspectorFrontendHostInstance.events.addEventListener(
Tim van der Lippe7b190162019-09-27 15:10:44120 Host.InspectorFrontendHostAPI.Events.SetInspectedTabId, this._setInspectedTabId, this);
Blink Reformat4c46d092018-04-07 15:32:37121
122 this._initExtensions();
123 }
124
125 initializeExtensions() {
Tim van der Lippe16a03772020-02-03 12:14:34126 Host.InspectorFrontendHost.InspectorFrontendHostInstance.setAddExtensionCallback(this._addExtension.bind(this));
Blink Reformat4c46d092018-04-07 15:32:37127 }
128
129 /**
130 * @return {boolean}
131 */
132 hasExtensions() {
Andrey Kosyakov4d123402020-04-01 04:38:37133 return !!this._registeredExtensions.size;
Blink Reformat4c46d092018-04-07 15:32:37134 }
135
136 /**
137 * @param {string} panelId
138 * @param {string} action
139 * @param {string=} searchString
140 */
141 notifySearchAction(panelId, action, searchString) {
142 this._postNotification(Extensions.extensionAPI.Events.PanelSearch + panelId, action, searchString);
143 }
144
145 /**
146 * @param {string} identifier
147 * @param {number=} frameIndex
148 */
149 notifyViewShown(identifier, frameIndex) {
150 this._postNotification(Extensions.extensionAPI.Events.ViewShown + identifier, frameIndex);
151 }
152
153 /**
154 * @param {string} identifier
155 */
156 notifyViewHidden(identifier) {
157 this._postNotification(Extensions.extensionAPI.Events.ViewHidden + identifier);
158 }
159
160 /**
161 * @param {string} identifier
162 */
163 notifyButtonClicked(identifier) {
164 this._postNotification(Extensions.extensionAPI.Events.ButtonClicked + identifier);
165 }
166
167 _inspectedURLChanged(event) {
Andrey Kosyakova08cb9b2020-04-01 21:49:52168 if (!this._canInspectURL(event.data.inspectedURL())) {
169 this._disableExtensions();
170 return;
171 }
Paul Lewisdaac1062020-03-05 14:37:10172 if (event.data !== SDK.SDKModel.TargetManager.instance().mainTarget()) {
Blink Reformat4c46d092018-04-07 15:32:37173 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34174 }
Blink Reformat4c46d092018-04-07 15:32:37175 this._requests = {};
176 const url = event.data.inspectedURL();
177 this._postNotification(Extensions.extensionAPI.Events.InspectedURLChanged, url);
178 }
179
180 /**
181 * @param {string} providerId
182 * @param {string} sessionId
Tim van der Lippea6110922020-01-09 15:38:39183 * @param {!TracingSession} session
Blink Reformat4c46d092018-04-07 15:32:37184 */
185 startTraceRecording(providerId, sessionId, session) {
186 this._traceSessions.set(sessionId, session);
187 this._postNotification('trace-recording-started-' + providerId, sessionId);
188 }
189
190 /**
191 * @param {string} providerId
192 */
193 stopTraceRecording(providerId) {
194 this._postNotification('trace-recording-stopped-' + providerId);
195 }
196
197 /**
198 * @param {string} type
199 * @return {boolean}
200 */
201 hasSubscribers(type) {
Simon Zünde18b5612020-03-03 09:02:36202 return this._subscribers.has(type);
Blink Reformat4c46d092018-04-07 15:32:37203 }
204
205 /**
206 * @param {string} type
207 * @param {...*} vararg
208 */
209 _postNotification(type, vararg) {
Andrey Kosyakova08cb9b2020-04-01 21:49:52210 if (!this._extensionsEnabled) {
211 return;
212 }
Simon Zünde18b5612020-03-03 09:02:36213 const subscribers = this._subscribers.get(type);
Tim van der Lippe1d6e57a2019-09-30 11:55:34214 if (!subscribers) {
Blink Reformat4c46d092018-04-07 15:32:37215 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34216 }
Blink Reformat4c46d092018-04-07 15:32:37217 const message = {command: 'notify-' + type, arguments: Array.prototype.slice.call(arguments, 1)};
Simon Zünde18b5612020-03-03 09:02:36218 for (const subscriber of subscribers) {
219 subscriber.postMessage(message);
Tim van der Lippe1d6e57a2019-09-30 11:55:34220 }
Blink Reformat4c46d092018-04-07 15:32:37221 }
222
223 _onSubscribe(message, port) {
Simon Zünde18b5612020-03-03 09:02:36224 const subscribers = this._subscribers.get(message.type);
Blink Reformat4c46d092018-04-07 15:32:37225 if (subscribers) {
Simon Zünde18b5612020-03-03 09:02:36226 subscribers.add(port);
Blink Reformat4c46d092018-04-07 15:32:37227 } else {
Simon Zünde18b5612020-03-03 09:02:36228 this._subscribers.set(message.type, new Set([port]));
Tim van der Lippe1d6e57a2019-09-30 11:55:34229 if (this._subscriptionStartHandlers[message.type]) {
Blink Reformat4c46d092018-04-07 15:32:37230 this._subscriptionStartHandlers[message.type]();
Tim van der Lippe1d6e57a2019-09-30 11:55:34231 }
Blink Reformat4c46d092018-04-07 15:32:37232 }
233 }
234
235 _onUnsubscribe(message, port) {
Simon Zünde18b5612020-03-03 09:02:36236 const subscribers = this._subscribers.get(message.type);
Tim van der Lippe1d6e57a2019-09-30 11:55:34237 if (!subscribers) {
Blink Reformat4c46d092018-04-07 15:32:37238 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34239 }
Simon Zünde18b5612020-03-03 09:02:36240 subscribers.delete(port);
241 if (!subscribers.size) {
242 this._subscribers.delete(message.type);
Tim van der Lippe1d6e57a2019-09-30 11:55:34243 if (this._subscriptionStopHandlers[message.type]) {
Blink Reformat4c46d092018-04-07 15:32:37244 this._subscriptionStopHandlers[message.type]();
Tim van der Lippe1d6e57a2019-09-30 11:55:34245 }
Blink Reformat4c46d092018-04-07 15:32:37246 }
247 }
248
249 _onAddRequestHeaders(message) {
250 const id = message.extensionId;
Tim van der Lippe1d6e57a2019-09-30 11:55:34251 if (typeof id !== 'string') {
Blink Reformat4c46d092018-04-07 15:32:37252 return this._status.E_BADARGTYPE('extensionId', typeof id, 'string');
Tim van der Lippe1d6e57a2019-09-30 11:55:34253 }
Tim van der Lippe990f2d12020-03-26 13:58:26254 let extensionHeaders = this._extraHeaders.get(id);
Blink Reformat4c46d092018-04-07 15:32:37255 if (!extensionHeaders) {
Tim van der Lippe990f2d12020-03-26 13:58:26256 extensionHeaders = new Map();
257 this._extraHeaders.set(id, extensionHeaders);
Blink Reformat4c46d092018-04-07 15:32:37258 }
Tim van der Lippe1d6e57a2019-09-30 11:55:34259 for (const name in message.headers) {
Tim van der Lippe990f2d12020-03-26 13:58:26260 extensionHeaders.set(name, message.headers[name]);
Tim van der Lippe1d6e57a2019-09-30 11:55:34261 }
Blink Reformat4c46d092018-04-07 15:32:37262 const allHeaders = /** @type {!Protocol.Network.Headers} */ ({});
Tim van der Lippe990f2d12020-03-26 13:58:26263 for (const headers of this._extraHeaders.values()) {
264 for (const name of headers.keys()) {
Andrey Kosyakov4d123402020-04-01 04:38:37265 if (name !== '__proto__' && typeof headers.get(name) === 'string') {
Tim van der Lippe990f2d12020-03-26 13:58:26266 allHeaders[name] = headers.get(name);
Tim van der Lippe1d6e57a2019-09-30 11:55:34267 }
Blink Reformat4c46d092018-04-07 15:32:37268 }
269 }
270
Tim van der Lippecd0bb372020-05-01 13:53:21271 SDK.NetworkManager.MultitargetNetworkManager.instance().setExtraHTTPHeaders(allHeaders);
Blink Reformat4c46d092018-04-07 15:32:37272 }
273
274 /**
275 * @param {*} message
276 * @suppressGlobalPropertiesCheck
277 */
278 _onApplyStyleSheet(message) {
Tim van der Lippe99e59b82019-09-30 20:00:59279 if (!Root.Runtime.experiments.isEnabled('applyCustomStylesheet')) {
Blink Reformat4c46d092018-04-07 15:32:37280 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34281 }
Blink Reformat4c46d092018-04-07 15:32:37282 const styleSheet = createElement('style');
283 styleSheet.textContent = message.styleSheet;
284 document.head.appendChild(styleSheet);
285
Paul Lewis93d8e2c2020-01-24 16:34:55286 self.UI.themeSupport.addCustomStylesheet(message.styleSheet);
Blink Reformat4c46d092018-04-07 15:32:37287 // Add to all the shadow roots that have already been created
288 for (let node = document.body; node; node = node.traverseNextNode(document.body)) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34289 if (node instanceof ShadowRoot) {
Paul Lewis93d8e2c2020-01-24 16:34:55290 self.UI.themeSupport.injectCustomStyleSheets(node);
Tim van der Lippe1d6e57a2019-09-30 11:55:34291 }
Blink Reformat4c46d092018-04-07 15:32:37292 }
293 }
294
295 _onCreatePanel(message, port) {
296 const id = message.id;
297 // The ids are generated on the client API side and must be unique, so the check below
298 // shouldn't be hit unless someone is bypassing the API.
Paul Lewis0a7c6b62020-01-23 16:16:22299 if (id in this._clientObjects || self.UI.inspectorView.hasPanel(id)) {
Blink Reformat4c46d092018-04-07 15:32:37300 return this._status.E_EXISTS(id);
Tim van der Lippe1d6e57a2019-09-30 11:55:34301 }
Blink Reformat4c46d092018-04-07 15:32:37302
Andrey Kosyakov4d123402020-04-01 04:38:37303 const page = this._expandResourcePath(port[extensionOriginSymbol], message.page);
304 let persistentId = port[extensionOriginSymbol] + message.title;
Blink Reformat4c46d092018-04-07 15:32:37305 persistentId = persistentId.replace(/\s/g, '');
Tim van der Lippea6110922020-01-09 15:38:39306 const panelView =
307 new ExtensionServerPanelView(persistentId, message.title, new ExtensionPanel(this, persistentId, id, page));
Blink Reformat4c46d092018-04-07 15:32:37308 this._clientObjects[id] = panelView;
Paul Lewis0a7c6b62020-01-23 16:16:22309 self.UI.inspectorView.addPanel(panelView);
Blink Reformat4c46d092018-04-07 15:32:37310 return this._status.OK();
311 }
312
313 _onShowPanel(message) {
314 let panelViewId = message.id;
315 const panelView = this._clientObjects[message.id];
Tim van der Lippe226fc222019-10-10 12:17:12316 if (panelView && panelView instanceof ExtensionServerPanelView) {
Blink Reformat4c46d092018-04-07 15:32:37317 panelViewId = panelView.viewId();
Tim van der Lippe1d6e57a2019-09-30 11:55:34318 }
Paul Lewis0a7c6b62020-01-23 16:16:22319 self.UI.inspectorView.showPanel(panelViewId);
Blink Reformat4c46d092018-04-07 15:32:37320 }
321
322 _onCreateToolbarButton(message, port) {
323 const panelView = this._clientObjects[message.panel];
Tim van der Lippe226fc222019-10-10 12:17:12324 if (!panelView || !(panelView instanceof ExtensionServerPanelView)) {
Blink Reformat4c46d092018-04-07 15:32:37325 return this._status.E_NOTFOUND(message.panel);
Tim van der Lippe1d6e57a2019-09-30 11:55:34326 }
Tim van der Lippea6110922020-01-09 15:38:39327 const button = new ExtensionButton(
Andrey Kosyakov4d123402020-04-01 04:38:37328 this, message.id, this._expandResourcePath(port[extensionOriginSymbol], message.icon), message.tooltip,
Blink Reformat4c46d092018-04-07 15:32:37329 message.disabled);
330 this._clientObjects[message.id] = button;
331
332 panelView.widget().then(appendButton);
333
334 /**
Tim van der Lippe16a03772020-02-03 12:14:34335 * @param {!UI.Widget.Widget} panel
Blink Reformat4c46d092018-04-07 15:32:37336 */
337 function appendButton(panel) {
Tim van der Lippea6110922020-01-09 15:38:39338 /** @type {!ExtensionPanel} panel*/ (panel).addToolbarItem(button.toolbarButton());
Blink Reformat4c46d092018-04-07 15:32:37339 }
340
341 return this._status.OK();
342 }
343
344 _onUpdateButton(message, port) {
345 const button = this._clientObjects[message.id];
Tim van der Lippea6110922020-01-09 15:38:39346 if (!button || !(button instanceof ExtensionButton)) {
Blink Reformat4c46d092018-04-07 15:32:37347 return this._status.E_NOTFOUND(message.id);
Tim van der Lippe1d6e57a2019-09-30 11:55:34348 }
Andrey Kosyakov4d123402020-04-01 04:38:37349 button.update(
350 this._expandResourcePath(port[extensionOriginSymbol], message.icon), message.tooltip, message.disabled);
Blink Reformat4c46d092018-04-07 15:32:37351 return this._status.OK();
352 }
353
354 /**
355 * @param {!Object} message
356 */
357 _onCompleteTraceSession(message) {
358 const session = this._traceSessions.get(message.id);
Tim van der Lippe1d6e57a2019-09-30 11:55:34359 if (!session) {
Blink Reformat4c46d092018-04-07 15:32:37360 return this._status.E_NOTFOUND(message.id);
Tim van der Lippe1d6e57a2019-09-30 11:55:34361 }
Blink Reformat4c46d092018-04-07 15:32:37362 this._traceSessions.delete(message.id);
363 session.complete(message.url, message.timeOffset);
364 }
365
366 _onCreateSidebarPane(message) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34367 if (message.panel !== 'elements' && message.panel !== 'sources') {
Blink Reformat4c46d092018-04-07 15:32:37368 return this._status.E_NOTFOUND(message.panel);
Tim van der Lippe1d6e57a2019-09-30 11:55:34369 }
Blink Reformat4c46d092018-04-07 15:32:37370 const id = message.id;
Tim van der Lippea6110922020-01-09 15:38:39371 const sidebar = new ExtensionSidebarPane(this, message.panel, message.title, id);
Blink Reformat4c46d092018-04-07 15:32:37372 this._sidebarPanes.push(sidebar);
373 this._clientObjects[id] = sidebar;
Tim van der Lippe226fc222019-10-10 12:17:12374 this.dispatchEventToListeners(Events.SidebarPaneAdded, sidebar);
Blink Reformat4c46d092018-04-07 15:32:37375
376 return this._status.OK();
377 }
378
379 /**
Tim van der Lippea6110922020-01-09 15:38:39380 * @return {!Array.<!ExtensionSidebarPane>}
Blink Reformat4c46d092018-04-07 15:32:37381 */
382 sidebarPanes() {
383 return this._sidebarPanes;
384 }
385
386 _onSetSidebarHeight(message) {
387 const sidebar = this._clientObjects[message.id];
Tim van der Lippe1d6e57a2019-09-30 11:55:34388 if (!sidebar) {
Blink Reformat4c46d092018-04-07 15:32:37389 return this._status.E_NOTFOUND(message.id);
Tim van der Lippe1d6e57a2019-09-30 11:55:34390 }
Blink Reformat4c46d092018-04-07 15:32:37391 sidebar.setHeight(message.height);
392 return this._status.OK();
393 }
394
395 _onSetSidebarContent(message, port) {
396 const sidebar = this._clientObjects[message.id];
Tim van der Lippe1d6e57a2019-09-30 11:55:34397 if (!sidebar) {
Blink Reformat4c46d092018-04-07 15:32:37398 return this._status.E_NOTFOUND(message.id);
Tim van der Lippe1d6e57a2019-09-30 11:55:34399 }
Blink Reformat4c46d092018-04-07 15:32:37400
401 /**
Tim van der Lippe226fc222019-10-10 12:17:12402 * @this {ExtensionServer}
Blink Reformat4c46d092018-04-07 15:32:37403 */
404 function callback(error) {
405 const result = error ? this._status.E_FAILED(error) : this._status.OK();
406 this._dispatchCallback(message.requestId, port, result);
407 }
408 if (message.evaluateOnPage) {
409 return sidebar.setExpression(
Andrey Kosyakov4d123402020-04-01 04:38:37410 message.expression, message.rootTitle, message.evaluateOptions, port[extensionOriginSymbol],
411 callback.bind(this));
Blink Reformat4c46d092018-04-07 15:32:37412 }
413 sidebar.setObject(message.expression, message.rootTitle, callback.bind(this));
414 }
415
416 _onSetSidebarPage(message, port) {
417 const sidebar = this._clientObjects[message.id];
Tim van der Lippe1d6e57a2019-09-30 11:55:34418 if (!sidebar) {
Blink Reformat4c46d092018-04-07 15:32:37419 return this._status.E_NOTFOUND(message.id);
Tim van der Lippe1d6e57a2019-09-30 11:55:34420 }
Andrey Kosyakov4d123402020-04-01 04:38:37421 sidebar.setPage(this._expandResourcePath(port[extensionOriginSymbol], message.page));
Blink Reformat4c46d092018-04-07 15:32:37422 }
423
424 _onOpenResource(message) {
Paul Lewis7cbdcae2020-03-19 10:48:12425 const uiSourceCode = Workspace.Workspace.WorkspaceImpl.instance().uiSourceCodeForURL(message.url);
Blink Reformat4c46d092018-04-07 15:32:37426 if (uiSourceCode) {
427 Common.Revealer.reveal(uiSourceCode.uiLocation(message.lineNumber, 0));
428 return this._status.OK();
429 }
430
Tim van der Lippe16a03772020-02-03 12:14:34431 const resource = Bindings.ResourceUtils.resourceForURL(message.url);
Blink Reformat4c46d092018-04-07 15:32:37432 if (resource) {
433 Common.Revealer.reveal(resource);
434 return this._status.OK();
435 }
436
Wolfgang Beyerd81fad62020-05-27 12:30:27437 const request = SDK.NetworkLog.NetworkLog.instance().requestForURL(message.url);
Blink Reformat4c46d092018-04-07 15:32:37438 if (request) {
439 Common.Revealer.reveal(request);
440 return this._status.OK();
441 }
442
443 return this._status.E_NOTFOUND(message.url);
444 }
445
446 _onSetOpenResourceHandler(message, port) {
Andrey Kosyakov4d123402020-04-01 04:38:37447 const name = this._registeredExtensions.get(port[extensionOriginSymbol]).name;
Tim van der Lippe1d6e57a2019-09-30 11:55:34448 if (message.handlerPresent) {
Tim van der Lippe16a03772020-02-03 12:14:34449 Components.Linkifier.Linkifier.registerLinkHandler(name, this._handleOpenURL.bind(this, port));
Tim van der Lippe1d6e57a2019-09-30 11:55:34450 } else {
Tim van der Lippe16a03772020-02-03 12:14:34451 Components.Linkifier.Linkifier.unregisterLinkHandler(name);
Tim van der Lippe1d6e57a2019-09-30 11:55:34452 }
Blink Reformat4c46d092018-04-07 15:32:37453 }
454
455 _handleOpenURL(port, contentProvider, lineNumber) {
456 port.postMessage(
457 {command: 'open-resource', resource: this._makeResource(contentProvider), lineNumber: lineNumber + 1});
458 }
459
460 _onReload(message) {
461 const options = /** @type {!ExtensionReloadOptions} */ (message.options || {});
462
Tim van der Lippecd0bb372020-05-01 13:53:21463 SDK.NetworkManager.MultitargetNetworkManager.instance().setUserAgentOverride(
Maks Orlovich8ce113c2020-05-07 12:16:28464 typeof options.userAgent === 'string' ? options.userAgent : '', null);
Blink Reformat4c46d092018-04-07 15:32:37465 let injectedScript;
Tim van der Lippe1d6e57a2019-09-30 11:55:34466 if (options.injectedScript) {
Blink Reformat4c46d092018-04-07 15:32:37467 injectedScript = '(function(){' + options.injectedScript + '})()';
Tim van der Lippe1d6e57a2019-09-30 11:55:34468 }
Tim van der Lippe16a03772020-02-03 12:14:34469 SDK.ResourceTreeModel.ResourceTreeModel.reloadAllPages(!!options.ignoreCache, injectedScript);
Blink Reformat4c46d092018-04-07 15:32:37470 return this._status.OK();
471 }
472
473 _onEvaluateOnInspectedPage(message, port) {
474 /**
Simon Zünd18213422020-03-19 05:57:45475 * @param {?ProtocolClient.InspectorBackend.ProtocolError} error
Tim van der Lippe16a03772020-02-03 12:14:34476 * @param {?SDK.RemoteObject.RemoteObject} object
Blink Reformat4c46d092018-04-07 15:32:37477 * @param {boolean} wasThrown
Tim van der Lippe226fc222019-10-10 12:17:12478 * @this {ExtensionServer}
Blink Reformat4c46d092018-04-07 15:32:37479 */
480 function callback(error, object, wasThrown) {
481 let result;
Tim van der Lippe1d6e57a2019-09-30 11:55:34482 if (error || !object) {
Blink Reformat4c46d092018-04-07 15:32:37483 result = this._status.E_PROTOCOLERROR(error.toString());
Tim van der Lippe1d6e57a2019-09-30 11:55:34484 } else if (wasThrown) {
Blink Reformat4c46d092018-04-07 15:32:37485 result = {isException: true, value: object.description};
Tim van der Lippe1d6e57a2019-09-30 11:55:34486 } else {
Blink Reformat4c46d092018-04-07 15:32:37487 result = {value: object.value};
Tim van der Lippe1d6e57a2019-09-30 11:55:34488 }
Blink Reformat4c46d092018-04-07 15:32:37489
490 this._dispatchCallback(message.requestId, port, result);
491 }
492 return this.evaluate(
Andrey Kosyakov4d123402020-04-01 04:38:37493 message.expression, true, true, message.evaluateOptions, port[extensionOriginSymbol], callback.bind(this));
Blink Reformat4c46d092018-04-07 15:32:37494 }
495
496 async _onGetHAR() {
Wolfgang Beyerd81fad62020-05-27 12:30:27497 const requests = SDK.NetworkLog.NetworkLog.instance().requests();
Tim van der Lippe16a03772020-02-03 12:14:34498 const harLog = await SDK.HARLog.HARLog.build(requests);
Tim van der Lippe1d6e57a2019-09-30 11:55:34499 for (let i = 0; i < harLog.entries.length; ++i) {
Blink Reformat4c46d092018-04-07 15:32:37500 harLog.entries[i]._requestId = this._requestId(requests[i]);
Tim van der Lippe1d6e57a2019-09-30 11:55:34501 }
Blink Reformat4c46d092018-04-07 15:32:37502 return harLog;
503 }
504
505 /**
Tim van der Lippe18f04892020-03-17 11:39:40506 * @param {!TextUtils.ContentProvider.ContentProvider} contentProvider
Blink Reformat4c46d092018-04-07 15:32:37507 */
508 _makeResource(contentProvider) {
509 return {url: contentProvider.contentURL(), type: contentProvider.contentType().name()};
510 }
511
512 /**
Tim van der Lippe18f04892020-03-17 11:39:40513 * @return {!Array<!TextUtils.ContentProvider.ContentProvider>}
Blink Reformat4c46d092018-04-07 15:32:37514 */
515 _onGetPageResources() {
Tim van der Lippe18f04892020-03-17 11:39:40516 /** @type {!Map<string, !TextUtils.ContentProvider.ContentProvider>} */
Blink Reformat4c46d092018-04-07 15:32:37517 const resources = new Map();
518
519 /**
Tim van der Lippe226fc222019-10-10 12:17:12520 * @this {ExtensionServer}
Blink Reformat4c46d092018-04-07 15:32:37521 */
522 function pushResourceData(contentProvider) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34523 if (!resources.has(contentProvider.contentURL())) {
Blink Reformat4c46d092018-04-07 15:32:37524 resources.set(contentProvider.contentURL(), this._makeResource(contentProvider));
Tim van der Lippe1d6e57a2019-09-30 11:55:34525 }
Blink Reformat4c46d092018-04-07 15:32:37526 }
Paul Lewis7cbdcae2020-03-19 10:48:12527 let uiSourceCodes = Workspace.Workspace.WorkspaceImpl.instance().uiSourceCodesForProjectType(
528 Workspace.Workspace.projectTypes.Network);
529 uiSourceCodes = uiSourceCodes.concat(Workspace.Workspace.WorkspaceImpl.instance().uiSourceCodesForProjectType(
530 Workspace.Workspace.projectTypes.ContentScripts));
Blink Reformat4c46d092018-04-07 15:32:37531 uiSourceCodes.forEach(pushResourceData.bind(this));
Paul Lewisdaac1062020-03-05 14:37:10532 for (const resourceTreeModel of SDK.SDKModel.TargetManager.instance().models(
533 SDK.ResourceTreeModel.ResourceTreeModel)) {
Blink Reformat4c46d092018-04-07 15:32:37534 resourceTreeModel.forAllResources(pushResourceData.bind(this));
Tim van der Lippe1d6e57a2019-09-30 11:55:34535 }
Simon Zünda0d40622020-02-12 13:16:42536 return [...resources.values()];
Blink Reformat4c46d092018-04-07 15:32:37537 }
538
539 /**
Tim van der Lippe18f04892020-03-17 11:39:40540 * @param {!TextUtils.ContentProvider.ContentProvider} contentProvider
Blink Reformat4c46d092018-04-07 15:32:37541 * @param {!Object} message
542 * @param {!MessagePort} port
543 */
544 async _getResourceContent(contentProvider, message, port) {
Rob Paveza2eb8c142019-10-13 18:02:38545 const {content} = await contentProvider.requestContent();
Blink Reformat4c46d092018-04-07 15:32:37546 const encoded = await contentProvider.contentEncoded();
547 this._dispatchCallback(message.requestId, port, {encoding: encoded ? 'base64' : '', content: content});
548 }
549
550 _onGetRequestContent(message, port) {
551 const request = this._requestById(message.id);
Tim van der Lippe1d6e57a2019-09-30 11:55:34552 if (!request) {
Blink Reformat4c46d092018-04-07 15:32:37553 return this._status.E_NOTFOUND(message.id);
Tim van der Lippe1d6e57a2019-09-30 11:55:34554 }
Blink Reformat4c46d092018-04-07 15:32:37555 this._getResourceContent(request, message, port);
556 }
557
558 _onGetResourceContent(message, port) {
559 const url = /** @type {string} */ (message.url);
Paul Lewis7cbdcae2020-03-19 10:48:12560 const contentProvider = Workspace.Workspace.WorkspaceImpl.instance().uiSourceCodeForURL(url) ||
561 Bindings.ResourceUtils.resourceForURL(url);
Tim van der Lippe1d6e57a2019-09-30 11:55:34562 if (!contentProvider) {
Blink Reformat4c46d092018-04-07 15:32:37563 return this._status.E_NOTFOUND(url);
Tim van der Lippe1d6e57a2019-09-30 11:55:34564 }
Blink Reformat4c46d092018-04-07 15:32:37565 this._getResourceContent(contentProvider, message, port);
566 }
567
568 _onSetResourceContent(message, port) {
569 /**
Simon Zünd18213422020-03-19 05:57:45570 * @param {?ProtocolClient.InspectorBackend.ProtocolError} error
Tim van der Lippe226fc222019-10-10 12:17:12571 * @this {ExtensionServer}
Blink Reformat4c46d092018-04-07 15:32:37572 */
573 function callbackWrapper(error) {
574 const response = error ? this._status.E_FAILED(error) : this._status.OK();
575 this._dispatchCallback(message.requestId, port, response);
576 }
577
578 const url = /** @type {string} */ (message.url);
Paul Lewis7cbdcae2020-03-19 10:48:12579 const uiSourceCode = Workspace.Workspace.WorkspaceImpl.instance().uiSourceCodeForURL(url);
Blink Reformat4c46d092018-04-07 15:32:37580 if (!uiSourceCode || !uiSourceCode.contentType().isDocumentOrScriptOrStyleSheet()) {
Tim van der Lippe16a03772020-02-03 12:14:34581 const resource = SDK.ResourceTreeModel.ResourceTreeModel.resourceForURL(url);
Tim van der Lippe1d6e57a2019-09-30 11:55:34582 if (!resource) {
Blink Reformat4c46d092018-04-07 15:32:37583 return this._status.E_NOTFOUND(url);
Tim van der Lippe1d6e57a2019-09-30 11:55:34584 }
Blink Reformat4c46d092018-04-07 15:32:37585 return this._status.E_NOTSUPPORTED('Resource is not editable');
586 }
587 uiSourceCode.setWorkingCopy(message.content);
Tim van der Lippe1d6e57a2019-09-30 11:55:34588 if (message.commit) {
Blink Reformat4c46d092018-04-07 15:32:37589 uiSourceCode.commitWorkingCopy();
Tim van der Lippe1d6e57a2019-09-30 11:55:34590 }
Blink Reformat4c46d092018-04-07 15:32:37591 callbackWrapper.call(this, null);
592 }
593
594 _requestId(request) {
595 if (!request._extensionRequestId) {
596 request._extensionRequestId = ++this._lastRequestId;
597 this._requests[request._extensionRequestId] = request;
598 }
599 return request._extensionRequestId;
600 }
601
602 _requestById(id) {
603 return this._requests[id];
604 }
605
606 /**
607 * @param {!Object} message
608 * @param {!MessagePort} port
609 */
610 _onAddTraceProvider(message, port) {
Andrey Kosyakov4d123402020-04-01 04:38:37611 const provider = new ExtensionTraceProvider(
612 port[extensionOriginSymbol], message.id, message.categoryName, message.categoryTooltip);
Blink Reformat4c46d092018-04-07 15:32:37613 this._clientObjects[message.id] = provider;
614 this._traceProviders.push(provider);
Tim van der Lippe226fc222019-10-10 12:17:12615 this.dispatchEventToListeners(Events.TraceProviderAdded, provider);
Blink Reformat4c46d092018-04-07 15:32:37616 }
617
618 /**
Tim van der Lippea6110922020-01-09 15:38:39619 * @return {!Array<!ExtensionTraceProvider>}
Blink Reformat4c46d092018-04-07 15:32:37620 */
621 traceProviders() {
622 return this._traceProviders;
623 }
624
625 _onForwardKeyboardEvent(message) {
626 message.entries.forEach(handleEventEntry);
627
628 /**
629 * @param {*} entry
630 * @suppressGlobalPropertiesCheck
631 */
632 function handleEventEntry(entry) {
Blink Reformat4c46d092018-04-07 15:32:37633 // Fool around closure compiler -- it has its own notion of both KeyboardEvent constructor
634 // and initKeyboardEvent methods and overriding these in externs.js does not have effect.
635 const event = new window.KeyboardEvent(entry.eventType, {
636 key: entry.key,
637 code: entry.code,
638 keyCode: entry.keyCode,
639 location: entry.location,
640 ctrlKey: entry.ctrlKey,
641 altKey: entry.altKey,
642 shiftKey: entry.shiftKey,
643 metaKey: entry.metaKey
644 });
645 event.__keyCode = keyCodeForEntry(entry);
646 document.dispatchEvent(event);
647 }
648
649 function keyCodeForEntry(entry) {
650 let keyCode = entry.keyCode;
651 if (!keyCode) {
652 // This is required only for synthetic events (e.g. dispatched in tests).
Tim van der Lippe1d6e57a2019-09-30 11:55:34653 if (entry.key === 'Escape') {
Blink Reformat4c46d092018-04-07 15:32:37654 keyCode = 27;
Tim van der Lippe1d6e57a2019-09-30 11:55:34655 }
Blink Reformat4c46d092018-04-07 15:32:37656 }
657 return keyCode || 0;
658 }
659 }
660
661 _dispatchCallback(requestId, port, result) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34662 if (requestId) {
Blink Reformat4c46d092018-04-07 15:32:37663 port.postMessage({command: 'callback', requestId: requestId, result: result});
Tim van der Lippe1d6e57a2019-09-30 11:55:34664 }
Blink Reformat4c46d092018-04-07 15:32:37665 }
666
667 _initExtensions() {
668 this._registerAutosubscriptionHandler(
Paul Lewis7cbdcae2020-03-19 10:48:12669 Extensions.extensionAPI.Events.ResourceAdded, Workspace.Workspace.WorkspaceImpl.instance(),
Paul Lewis10e83a92020-01-23 14:07:58670 Workspace.Workspace.Events.UISourceCodeAdded, this._notifyResourceAdded);
Blink Reformat4c46d092018-04-07 15:32:37671 this._registerAutosubscriptionTargetManagerHandler(
Tim van der Lippe16a03772020-02-03 12:14:34672 Extensions.extensionAPI.Events.NetworkRequestFinished, SDK.NetworkManager.NetworkManager,
Blink Reformat4c46d092018-04-07 15:32:37673 SDK.NetworkManager.Events.RequestFinished, this._notifyRequestFinished);
674
675 /**
Tim van der Lippe226fc222019-10-10 12:17:12676 * @this {ExtensionServer}
Blink Reformat4c46d092018-04-07 15:32:37677 */
678 function onElementsSubscriptionStarted() {
Tim van der Lippe16a03772020-02-03 12:14:34679 self.UI.context.addFlavorChangeListener(SDK.DOMModel.DOMNode, this._notifyElementsSelectionChanged, this);
Blink Reformat4c46d092018-04-07 15:32:37680 }
681
682 /**
Tim van der Lippe226fc222019-10-10 12:17:12683 * @this {ExtensionServer}
Blink Reformat4c46d092018-04-07 15:32:37684 */
685 function onElementsSubscriptionStopped() {
Tim van der Lippe16a03772020-02-03 12:14:34686 self.UI.context.removeFlavorChangeListener(SDK.DOMModel.DOMNode, this._notifyElementsSelectionChanged, this);
Blink Reformat4c46d092018-04-07 15:32:37687 }
688
689 this._registerSubscriptionHandler(
690 Extensions.extensionAPI.Events.PanelObjectSelected + 'elements', onElementsSubscriptionStarted.bind(this),
691 onElementsSubscriptionStopped.bind(this));
692 this._registerResourceContentCommittedHandler(this._notifyUISourceCodeContentCommitted);
693
Paul Lewisdaac1062020-03-05 14:37:10694 SDK.SDKModel.TargetManager.instance().addEventListener(
695 SDK.SDKModel.Events.InspectedURLChanged, this._inspectedURLChanged, this);
Blink Reformat4c46d092018-04-07 15:32:37696 }
697
698 _notifyResourceAdded(event) {
Tim van der Lippe16a03772020-02-03 12:14:34699 const uiSourceCode = /** @type {!Workspace.UISourceCode.UISourceCode} */ (event.data);
Blink Reformat4c46d092018-04-07 15:32:37700 this._postNotification(Extensions.extensionAPI.Events.ResourceAdded, this._makeResource(uiSourceCode));
701 }
702
703 _notifyUISourceCodeContentCommitted(event) {
Tim van der Lippe16a03772020-02-03 12:14:34704 const uiSourceCode = /** @type {!Workspace.UISourceCode.UISourceCode} */ (event.data.uiSourceCode);
Blink Reformat4c46d092018-04-07 15:32:37705 const content = /** @type {string} */ (event.data.content);
706 this._postNotification(
707 Extensions.extensionAPI.Events.ResourceContentCommitted, this._makeResource(uiSourceCode), content);
708 }
709
710 async _notifyRequestFinished(event) {
Tim van der Lippe16a03772020-02-03 12:14:34711 const request = /** @type {!SDK.NetworkRequest.NetworkRequest} */ (event.data);
Pavel Feldman18d13562018-07-31 03:31:18712 const entry = await SDK.HARLog.Entry.build(request);
Blink Reformat4c46d092018-04-07 15:32:37713 this._postNotification(Extensions.extensionAPI.Events.NetworkRequestFinished, this._requestId(request), entry);
714 }
715
716 _notifyElementsSelectionChanged() {
717 this._postNotification(Extensions.extensionAPI.Events.PanelObjectSelected + 'elements');
718 }
719
720 /**
721 * @param {string} url
Tim van der Lippe16a03772020-02-03 12:14:34722 * @param {!TextUtils.TextRange.TextRange} range
Blink Reformat4c46d092018-04-07 15:32:37723 */
724 sourceSelectionChanged(url, range) {
725 this._postNotification(Extensions.extensionAPI.Events.PanelObjectSelected + 'sources', {
726 startLine: range.startLine,
727 startColumn: range.startColumn,
728 endLine: range.endLine,
729 endColumn: range.endColumn,
730 url: url,
731 });
732 }
733
734 /**
Tim van der Lippec02a97c2020-02-14 14:39:27735 * @param {!Common.EventTarget.EventTargetEvent} event
Blink Reformat4c46d092018-04-07 15:32:37736 */
Blink Reformat4c46d092018-04-07 15:32:37737 _setInspectedTabId(event) {
738 this._inspectedTabId = /** @type {string} */ (event.data);
739 }
740
741 /**
Tim van der Lipped71c22d2020-03-19 12:29:19742 * @param {!Root.Runtime.RuntimeExtensionDescriptor} extensionInfo
Blink Reformat4c46d092018-04-07 15:32:37743 * @suppressGlobalPropertiesCheck
744 */
745 _addExtension(extensionInfo) {
Blink Reformat4c46d092018-04-07 15:32:37746 const startPage = extensionInfo.startPage;
Blink Reformat4c46d092018-04-07 15:32:37747
Andrey Kosyakova08cb9b2020-04-01 21:49:52748 const inspectedURL = SDK.SDKModel.TargetManager.instance().mainTarget().inspectedURL();
Andrey Kosyakov45762822020-06-12 14:36:15749 if (inspectedURL !== '' && !this._canInspectURL(inspectedURL)) {
Andrey Kosyakova08cb9b2020-04-01 21:49:52750 this._disableExtensions();
751 }
752 if (!this._extensionsEnabled) {
753 return;
754 }
Blink Reformat4c46d092018-04-07 15:32:37755 try {
Andrey Kosyakov4d123402020-04-01 04:38:37756 const startPageURL = new URL(/** @type {string} */ (startPage));
757 const extensionOrigin = startPageURL.origin;
758 if (!this._registeredExtensions.get(extensionOrigin)) {
Blink Reformat4c46d092018-04-07 15:32:37759 // See ExtensionAPI.js for details.
Tim van der Lippe226fc222019-10-10 12:17:12760 const injectedAPI = self.buildExtensionAPIInjectedScript(
Tim van der Lipped71c22d2020-03-19 12:29:19761 /** @type {!{startPage: string, name: string, exposeExperimentalAPIs: boolean}} */ (extensionInfo),
762 this._inspectedTabId, self.UI.themeSupport.themeName(), self.UI.shortcutRegistry.globalShortcutKeys(),
763 self.Extensions.extensionServer['_extensionAPITestHook']);
Tim van der Lippe16a03772020-02-03 12:14:34764 Host.InspectorFrontendHost.InspectorFrontendHostInstance.setInjectedScriptForOrigin(
765 extensionOrigin, injectedAPI);
Andrey Kosyakov4d123402020-04-01 04:38:37766 const name = extensionInfo.name || `Extension ${extensionOrigin}`;
767 this._registeredExtensions.set(extensionOrigin, {name});
Blink Reformat4c46d092018-04-07 15:32:37768 }
769 const iframe = createElement('iframe');
770 iframe.src = startPage;
771 iframe.style.display = 'none';
772 document.body.appendChild(iframe); // Only for main window.
773 } catch (e) {
774 console.error('Failed to initialize extension ' + startPage + ':' + e);
775 return false;
776 }
777 return true;
778 }
779
780 _registerExtension(origin, port) {
Andrey Kosyakov4d123402020-04-01 04:38:37781 if (!this._registeredExtensions.has(origin)) {
782 if (origin !== window.location.origin) { // Just ignore inspector frames.
Blink Reformat4c46d092018-04-07 15:32:37783 console.error('Ignoring unauthorized client request from ' + origin);
Tim van der Lippe1d6e57a2019-09-30 11:55:34784 }
Blink Reformat4c46d092018-04-07 15:32:37785 return;
786 }
Andrey Kosyakov4d123402020-04-01 04:38:37787 port[extensionOriginSymbol] = origin;
Blink Reformat4c46d092018-04-07 15:32:37788 port.addEventListener('message', this._onmessage.bind(this), false);
789 port.start();
790 }
791
792 _onWindowMessage(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34793 if (event.data === 'registerExtension') {
Blink Reformat4c46d092018-04-07 15:32:37794 this._registerExtension(event.origin, event.ports[0]);
Tim van der Lippe1d6e57a2019-09-30 11:55:34795 }
Blink Reformat4c46d092018-04-07 15:32:37796 }
797
798 async _onmessage(event) {
799 const message = event.data;
800 let result;
801
Andrey Kosyakova08cb9b2020-04-01 21:49:52802 if (!(message.command in this._handlers)) {
Blink Reformat4c46d092018-04-07 15:32:37803 result = this._status.E_NOTSUPPORTED(message.command);
Andrey Kosyakova08cb9b2020-04-01 21:49:52804 } else if (!this._extensionsEnabled) {
805 result = this._status.E_FAILED('Permission denied');
806 } else {
807 result = await this._handlers[message.command](message, event.target);
Tim van der Lippe1d6e57a2019-09-30 11:55:34808 }
Blink Reformat4c46d092018-04-07 15:32:37809
Tim van der Lippe1d6e57a2019-09-30 11:55:34810 if (result && message.requestId) {
Blink Reformat4c46d092018-04-07 15:32:37811 this._dispatchCallback(message.requestId, event.target, result);
Tim van der Lippe1d6e57a2019-09-30 11:55:34812 }
Blink Reformat4c46d092018-04-07 15:32:37813 }
814
815 _registerHandler(command, callback) {
816 console.assert(command);
817 this._handlers[command] = callback;
818 }
819
820 _registerSubscriptionHandler(eventTopic, onSubscribeFirst, onUnsubscribeLast) {
821 this._subscriptionStartHandlers[eventTopic] = onSubscribeFirst;
822 this._subscriptionStopHandlers[eventTopic] = onUnsubscribeLast;
823 }
824
825 /**
826 * @param {string} eventTopic
827 * @param {!Object} eventTarget
Tim van der Lippeffa78622019-09-16 12:07:12828 * @param {symbol} frontendEventType
Tim van der Lippec02a97c2020-02-14 14:39:27829 * @param {function(!Common.EventTarget.EventTargetEvent)} handler
Blink Reformat4c46d092018-04-07 15:32:37830 */
831 _registerAutosubscriptionHandler(eventTopic, eventTarget, frontendEventType, handler) {
832 this._registerSubscriptionHandler(
833 eventTopic, eventTarget.addEventListener.bind(eventTarget, frontendEventType, handler, this),
834 eventTarget.removeEventListener.bind(eventTarget, frontendEventType, handler, this));
835 }
836
837 /**
838 * @param {string} eventTopic
839 * @param {!Function} modelClass
Tim van der Lippeffa78622019-09-16 12:07:12840 * @param {symbol} frontendEventType
Tim van der Lippec02a97c2020-02-14 14:39:27841 * @param {function(!Common.EventTarget.EventTargetEvent)} handler
Blink Reformat4c46d092018-04-07 15:32:37842 */
843 _registerAutosubscriptionTargetManagerHandler(eventTopic, modelClass, frontendEventType, handler) {
844 this._registerSubscriptionHandler(
845 eventTopic,
Paul Lewisdaac1062020-03-05 14:37:10846 SDK.SDKModel.TargetManager.instance().addModelListener.bind(
847 SDK.SDKModel.TargetManager.instance(), modelClass, frontendEventType, handler, this),
848 SDK.SDKModel.TargetManager.instance().removeModelListener.bind(
849 SDK.SDKModel.TargetManager.instance(), modelClass, frontendEventType, handler, this));
Blink Reformat4c46d092018-04-07 15:32:37850 }
851
852 _registerResourceContentCommittedHandler(handler) {
853 /**
Tim van der Lippe226fc222019-10-10 12:17:12854 * @this {ExtensionServer}
Blink Reformat4c46d092018-04-07 15:32:37855 */
856 function addFirstEventListener() {
Paul Lewis7cbdcae2020-03-19 10:48:12857 Workspace.Workspace.WorkspaceImpl.instance().addEventListener(
858 Workspace.Workspace.Events.WorkingCopyCommittedByUser, handler, this);
859 Workspace.Workspace.WorkspaceImpl.instance().setHasResourceContentTrackingExtensions(true);
Blink Reformat4c46d092018-04-07 15:32:37860 }
861
862 /**
Tim van der Lippe226fc222019-10-10 12:17:12863 * @this {ExtensionServer}
Blink Reformat4c46d092018-04-07 15:32:37864 */
865 function removeLastEventListener() {
Paul Lewis7cbdcae2020-03-19 10:48:12866 Workspace.Workspace.WorkspaceImpl.instance().setHasResourceContentTrackingExtensions(false);
867 Workspace.Workspace.WorkspaceImpl.instance().removeEventListener(
Paul Lewis10e83a92020-01-23 14:07:58868 Workspace.Workspace.Events.WorkingCopyCommittedByUser, handler, this);
Blink Reformat4c46d092018-04-07 15:32:37869 }
870
871 this._registerSubscriptionHandler(
872 Extensions.extensionAPI.Events.ResourceContentCommitted, addFirstEventListener.bind(this),
873 removeLastEventListener.bind(this));
874 }
875
876 _expandResourcePath(extensionPath, resourcePath) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34877 if (!resourcePath) {
Blink Reformat4c46d092018-04-07 15:32:37878 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34879 }
Blink Reformat4c46d092018-04-07 15:32:37880 return extensionPath + this._normalizePath(resourcePath);
881 }
882
883 _normalizePath(path) {
884 const source = path.split('/');
885 const result = [];
886
887 for (let i = 0; i < source.length; ++i) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34888 if (source[i] === '.') {
Blink Reformat4c46d092018-04-07 15:32:37889 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:34890 }
Blink Reformat4c46d092018-04-07 15:32:37891 // Ignore empty path components resulting from //, as well as a leading and traling slashes.
Tim van der Lippe1d6e57a2019-09-30 11:55:34892 if (source[i] === '') {
Blink Reformat4c46d092018-04-07 15:32:37893 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:34894 }
895 if (source[i] === '..') {
Blink Reformat4c46d092018-04-07 15:32:37896 result.pop();
Tim van der Lippe1d6e57a2019-09-30 11:55:34897 } else {
Blink Reformat4c46d092018-04-07 15:32:37898 result.push(source[i]);
Tim van der Lippe1d6e57a2019-09-30 11:55:34899 }
Blink Reformat4c46d092018-04-07 15:32:37900 }
901 return '/' + result.join('/');
902 }
903
904 /**
905 * @param {string} expression
906 * @param {boolean} exposeCommandLineAPI
907 * @param {boolean} returnByValue
908 * @param {?Object} options
909 * @param {string} securityOrigin
Tim van der Lippe16a03772020-02-03 12:14:34910 * @param {function(?string, ?SDK.RemoteObject.RemoteObject, boolean)} callback
Tim van der Lippe1cf8e422020-03-12 16:09:21911 * @return {!Record|undefined}
Blink Reformat4c46d092018-04-07 15:32:37912 */
913 evaluate(expression, exposeCommandLineAPI, returnByValue, options, securityOrigin, callback) {
914 let context;
915
916 /**
917 * @param {string} url
918 * @return {boolean}
919 */
920 function resolveURLToFrame(url) {
921 let found;
922 function hasMatchingURL(frame) {
923 found = (frame.url === url) ? frame : null;
924 return found;
925 }
Tim van der Lippe16a03772020-02-03 12:14:34926 SDK.ResourceTreeModel.ResourceTreeModel.frames().some(hasMatchingURL);
Blink Reformat4c46d092018-04-07 15:32:37927 return found;
928 }
929
930 options = options || {};
931 let frame;
932 if (options.frameURL) {
933 frame = resolveURLToFrame(options.frameURL);
934 } else {
Paul Lewisdaac1062020-03-05 14:37:10935 const target = SDK.SDKModel.TargetManager.instance().mainTarget();
Tim van der Lippe16a03772020-02-03 12:14:34936 const resourceTreeModel = target && target.model(SDK.ResourceTreeModel.ResourceTreeModel);
Blink Reformat4c46d092018-04-07 15:32:37937 frame = resourceTreeModel && resourceTreeModel.mainFrame;
938 }
939 if (!frame) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34940 if (options.frameURL) {
Blink Reformat4c46d092018-04-07 15:32:37941 console.warn('evaluate: there is no frame with URL ' + options.frameURL);
Tim van der Lippe1d6e57a2019-09-30 11:55:34942 } else {
Blink Reformat4c46d092018-04-07 15:32:37943 console.warn('evaluate: the main frame is not yet available');
Tim van der Lippe1d6e57a2019-09-30 11:55:34944 }
Blink Reformat4c46d092018-04-07 15:32:37945 return this._status.E_NOTFOUND(options.frameURL || '<top>');
946 }
Andrey Kosyakova08cb9b2020-04-01 21:49:52947 // We shouldn't get here if the top frame can't be inspected by an extension, but
948 // let's double check for subframes.
949 if (!this._canInspectURL(frame.url)) {
950 return this._status.E_FAILED('Permission denied');
951 }
Blink Reformat4c46d092018-04-07 15:32:37952
953 let contextSecurityOrigin;
Tim van der Lippe1d6e57a2019-09-30 11:55:34954 if (options.useContentScriptContext) {
Blink Reformat4c46d092018-04-07 15:32:37955 contextSecurityOrigin = securityOrigin;
Tim van der Lippe1d6e57a2019-09-30 11:55:34956 } else if (options.scriptExecutionContext) {
Blink Reformat4c46d092018-04-07 15:32:37957 contextSecurityOrigin = options.scriptExecutionContext;
Tim van der Lippe1d6e57a2019-09-30 11:55:34958 }
Blink Reformat4c46d092018-04-07 15:32:37959
Tim van der Lippe16a03772020-02-03 12:14:34960 const runtimeModel = frame.resourceTreeModel().target().model(SDK.RuntimeModel.RuntimeModel);
Blink Reformat4c46d092018-04-07 15:32:37961 const executionContexts = runtimeModel ? runtimeModel.executionContexts() : [];
962 if (contextSecurityOrigin) {
963 for (let i = 0; i < executionContexts.length; ++i) {
964 const executionContext = executionContexts[i];
965 if (executionContext.frameId === frame.id && executionContext.origin === contextSecurityOrigin &&
Tim van der Lippe1d6e57a2019-09-30 11:55:34966 !executionContext.isDefault) {
Blink Reformat4c46d092018-04-07 15:32:37967 context = executionContext;
Tim van der Lippe1d6e57a2019-09-30 11:55:34968 }
Blink Reformat4c46d092018-04-07 15:32:37969 }
970 if (!context) {
971 console.warn('The JavaScript context ' + contextSecurityOrigin + ' was not found in the frame ' + frame.url);
972 return this._status.E_NOTFOUND(contextSecurityOrigin);
973 }
974 } else {
975 for (let i = 0; i < executionContexts.length; ++i) {
976 const executionContext = executionContexts[i];
Tim van der Lippe1d6e57a2019-09-30 11:55:34977 if (executionContext.frameId === frame.id && executionContext.isDefault) {
Blink Reformat4c46d092018-04-07 15:32:37978 context = executionContext;
Tim van der Lippe1d6e57a2019-09-30 11:55:34979 }
Blink Reformat4c46d092018-04-07 15:32:37980 }
Tim van der Lippe1d6e57a2019-09-30 11:55:34981 if (!context) {
Blink Reformat4c46d092018-04-07 15:32:37982 return this._status.E_FAILED(frame.url + ' has no execution context');
Tim van der Lippe1d6e57a2019-09-30 11:55:34983 }
Blink Reformat4c46d092018-04-07 15:32:37984 }
Andrey Kosyakova08cb9b2020-04-01 21:49:52985 if (!this._canInspectURL(context.origin)) {
986 return this._status.E_FAILED('Permission denied');
987 }
Blink Reformat4c46d092018-04-07 15:32:37988
989 context
990 .evaluate(
991 {
992 expression: expression,
993 objectGroup: 'extension',
994 includeCommandLineAPI: exposeCommandLineAPI,
995 silent: true,
996 returnByValue: returnByValue,
997 generatePreview: false
998 },
999 /* userGesture */ false, /* awaitPromise */ false)
1000 .then(onEvaluate);
1001
1002 /**
1003 * @param {!SDK.RuntimeModel.EvaluationResult} result
1004 */
1005 function onEvaluate(result) {
1006 if (result.error) {
1007 callback(result.error, null, false);
1008 return;
1009 }
1010 callback(null, result.object || null, !!result.exceptionDetails);
1011 }
1012 }
Andrey Kosyakova08cb9b2020-04-01 21:49:521013
1014 /**
1015 *
1016 * @param {string} url
1017 */
1018 _canInspectURL(url) {
1019 let parsedURL;
1020 // This is only to work around invalid URLs we're occasionally getting from some tests.
1021 // TODO(caseq): make sure tests supply valid URLs or we specifically handle invalid ones.
1022 try {
1023 parsedURL = new URL(url);
1024 } catch (exception) {
1025 return false;
1026 }
Andrey Kosyakov9129f942020-05-27 19:41:411027 if (kAllowedOrigins.includes(parsedURL.origin)) {
1028 return true;
1029 }
Andrey Kosyakova08cb9b2020-04-01 21:49:521030 if (parsedURL.protocol === 'chrome:' || parsedURL.protocol === 'devtools:') {
1031 return false;
1032 }
1033 if (parsedURL.protocol.startsWith('http') && parsedURL.hostname === 'chrome.google.com' &&
1034 parsedURL.pathname.startsWith('/webstore')) {
1035 return false;
1036 }
1037 return true;
1038 }
1039
1040 _disableExtensions() {
1041 this._extensionsEnabled = false;
1042 }
Tim van der Lippe226fc222019-10-10 12:17:121043}
Blink Reformat4c46d092018-04-07 15:32:371044
1045/** @enum {symbol} */
Tim van der Lippe226fc222019-10-10 12:17:121046export const Events = {
Blink Reformat4c46d092018-04-07 15:32:371047 SidebarPaneAdded: Symbol('SidebarPaneAdded'),
1048 TraceProviderAdded: Symbol('TraceProviderAdded')
1049};
1050
1051/**
1052 * @unrestricted
1053 */
Tim van der Lippe16a03772020-02-03 12:14:341054class ExtensionServerPanelView extends UI.View.SimpleView {
Blink Reformat4c46d092018-04-07 15:32:371055 /**
1056 * @param {string} name
1057 * @param {string} title
Tim van der Lippe16a03772020-02-03 12:14:341058 * @param {!UI.Panel.Panel} panel
Blink Reformat4c46d092018-04-07 15:32:371059 */
1060 constructor(name, title, panel) {
1061 super(title);
1062 this._name = name;
1063 this._panel = panel;
1064 }
1065
1066 /**
1067 * @override
1068 * @return {string}
1069 */
1070 viewId() {
1071 return this._name;
1072 }
1073
1074 /**
1075 * @override
Tim van der Lippe16a03772020-02-03 12:14:341076 * @return {!Promise.<!UI.Widget.Widget>}
Blink Reformat4c46d092018-04-07 15:32:371077 */
1078 widget() {
Tim van der Lippe16a03772020-02-03 12:14:341079 return /** @type {!Promise.<!UI.Widget.Widget>} */ (Promise.resolve(this._panel));
Blink Reformat4c46d092018-04-07 15:32:371080 }
Tim van der Lippe226fc222019-10-10 12:17:121081}
Blink Reformat4c46d092018-04-07 15:32:371082
1083/**
1084 * @unrestricted
1085 */
Tim van der Lippe226fc222019-10-10 12:17:121086export class ExtensionStatus {
Blink Reformat4c46d092018-04-07 15:32:371087 constructor() {
1088 /**
1089 * @param {string} code
1090 * @param {string} description
Tim van der Lippe1cf8e422020-03-12 16:09:211091 * @return {!Record}
Blink Reformat4c46d092018-04-07 15:32:371092 */
1093 function makeStatus(code, description) {
1094 const details = Array.prototype.slice.call(arguments, 2);
1095 const status = {code: code, description: description, details: details};
1096 if (code !== 'OK') {
1097 status.isError = true;
Tim van der Lippe93b57c32020-02-20 17:38:441098 console.error('Extension server error: ' + Platform.StringUtilities.vsprintf(description, details));
Blink Reformat4c46d092018-04-07 15:32:371099 }
1100 return status;
1101 }
1102
1103 this.OK = makeStatus.bind(null, 'OK', 'OK');
1104 this.E_EXISTS = makeStatus.bind(null, 'E_EXISTS', 'Object already exists: %s');
1105 this.E_BADARG = makeStatus.bind(null, 'E_BADARG', 'Invalid argument %s: %s');
1106 this.E_BADARGTYPE = makeStatus.bind(null, 'E_BADARGTYPE', 'Invalid type for argument %s: got %s, expected %s');
1107 this.E_NOTFOUND = makeStatus.bind(null, 'E_NOTFOUND', 'Object not found: %s');
1108 this.E_NOTSUPPORTED = makeStatus.bind(null, 'E_NOTSUPPORTED', 'Object does not support requested operation: %s');
1109 this.E_PROTOCOLERROR = makeStatus.bind(null, 'E_PROTOCOLERROR', 'Inspector protocol error: %s');
1110 this.E_FAILED = makeStatus.bind(null, 'E_FAILED', 'Operation failed: %s');
1111 }
Tim van der Lippe226fc222019-10-10 12:17:121112}
Tim van der Lippe1cf8e422020-03-12 16:09:211113
1114/**
1115 * @typedef {{code: string, description: string, details: !Array.<*>}}
1116 */
1117export let Record;