blob: f68af5a62938e69e3e16eaef388a022a299ca88e [file] [log] [blame]
Blink Reformat4c46d092018-04-07 15:32:371/*
2 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2008, 2009 Anthony Ricaud <[email protected]>
4 * Copyright (C) 2011 Google Inc. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
16 * its contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31/**
32 * @implements {SDK.SDKModelObserver<!SDK.NetworkManager>}
33 */
34Network.NetworkLogView = class extends UI.VBox {
35 /**
36 * @param {!UI.FilterBar} filterBar
37 * @param {!Element} progressBarContainer
38 * @param {!Common.Setting} networkLogLargeRowsSetting
39 */
40 constructor(filterBar, progressBarContainer, networkLogLargeRowsSetting) {
41 super();
42 this.setMinimumSize(50, 64);
43 this.registerRequiredCSS('network/networkLogView.css');
44
45 this.element.id = 'network-container';
46
47 this._networkHideDataURLSetting = Common.settings.createSetting('networkHideDataURL', false);
48 this._networkResourceTypeFiltersSetting = Common.settings.createSetting('networkResourceTypeFilters', {});
49
50 this._rawRowHeight = 0;
51 this._progressBarContainer = progressBarContainer;
52 this._networkLogLargeRowsSetting = networkLogLargeRowsSetting;
53 this._networkLogLargeRowsSetting.addChangeListener(updateRowHeight.bind(this), this);
54
55 /**
56 * @this {Network.NetworkLogView}
57 */
58 function updateRowHeight() {
59 this._rawRowHeight = !!this._networkLogLargeRowsSetting.get() ? 41 : 21;
60 this._rowHeight = this._computeRowHeight();
61 }
62 this._rawRowHeight = 0;
63 this._rowHeight = 0;
64 updateRowHeight.call(this);
65
66 /** @type {!Network.NetworkTransferTimeCalculator} */
67 this._timeCalculator = new Network.NetworkTransferTimeCalculator();
68 /** @type {!Network.NetworkTransferDurationCalculator} */
69 this._durationCalculator = new Network.NetworkTransferDurationCalculator();
70 this._calculator = this._timeCalculator;
71
72 this._columns = new Network.NetworkLogViewColumns(
73 this, this._timeCalculator, this._durationCalculator, networkLogLargeRowsSetting);
74 this._columns.show(this.element);
75
76 /** @type {!Set<!SDK.NetworkRequest>} */
77 this._staleRequests = new Set();
78 /** @type {number} */
79 this._mainRequestLoadTime = -1;
80 /** @type {number} */
81 this._mainRequestDOMContentLoadedTime = -1;
82 this._highlightedSubstringChanges = [];
83
84 /** @type {!Array.<!Network.NetworkLogView.Filter>} */
85 this._filters = [];
86 /** @type {?Network.NetworkLogView.Filter} */
87 this._timeFilter = null;
88 /** @type {?Network.NetworkNode} */
89 this._hoveredNode = null;
90 /** @type {?Element} */
91 this._recordingHint = null;
92 /** @type {?number} */
93 this._refreshRequestId = null;
94 /** @type {?Network.NetworkRequestNode} */
95 this._highlightedNode = null;
96
97 this.linkifier = new Components.Linkifier();
98 this.badgePool = new ProductRegistry.BadgePool();
99
100 this._recording = false;
101 this._needsRefresh = false;
102
103 this._headerHeight = 0;
104
105 /** @type {!Map<string, !Network.GroupLookupInterface>} */
106 this._groupLookups = new Map();
107 this._groupLookups.set('Frame', new Network.NetworkFrameGrouper(this));
108
109 /** @type {?Network.GroupLookupInterface} */
110 this._activeGroupLookup = null;
111
112 this._textFilterUI = new UI.TextFilterUI();
113 this._textFilterUI.addEventListener(UI.FilterUI.Events.FilterChanged, this._filterChanged, this);
114 filterBar.addFilter(this._textFilterUI);
115
116 this._dataURLFilterUI = new UI.CheckboxFilterUI(
117 'hide-data-url', Common.UIString('Hide data URLs'), true, this._networkHideDataURLSetting);
118 this._dataURLFilterUI.addEventListener(UI.FilterUI.Events.FilterChanged, this._filterChanged.bind(this), this);
Joey Arharba99d622019-02-01 19:10:48119 this._dataURLFilterUI.element().title = ls`Hides data: and blob: URLs`;
Blink Reformat4c46d092018-04-07 15:32:37120 filterBar.addFilter(this._dataURLFilterUI);
121
122 const filterItems =
123 Object.values(Common.resourceCategories)
124 .map(category => ({name: category.title, label: category.shortTitle, title: category.title}));
125 this._resourceCategoryFilterUI = new UI.NamedBitSetFilterUI(filterItems, this._networkResourceTypeFiltersSetting);
Brandon Goddard568cef12019-06-27 17:18:20126 UI.ARIAUtils.setAccessibleName(this._resourceCategoryFilterUI.element(), ls`Resource types to include`);
Blink Reformat4c46d092018-04-07 15:32:37127 this._resourceCategoryFilterUI.addEventListener(
128 UI.FilterUI.Events.FilterChanged, this._filterChanged.bind(this), this);
129 filterBar.addFilter(this._resourceCategoryFilterUI);
130
131 this._filterParser = new TextUtils.FilterParser(Network.NetworkLogView._searchKeys);
132 this._suggestionBuilder =
133 new UI.FilterSuggestionBuilder(Network.NetworkLogView._searchKeys, Network.NetworkLogView._sortSearchValues);
134 this._resetSuggestionBuilder();
135
136 this._dataGrid = this._columns.dataGrid();
137 this._setupDataGrid();
138 this._columns.sortByCurrentColumn();
Erik Luo0187a022018-05-31 18:35:49139 filterBar.filterButton().addEventListener(
140 UI.ToolbarButton.Events.Click, this._dataGrid.scheduleUpdate.bind(this._dataGrid, true /* isFromUser */));
Blink Reformat4c46d092018-04-07 15:32:37141
Joey Arhara86c14e2019-03-12 03:20:50142 this._summaryToolbar = new UI.Toolbar('network-summary-bar', this.element);
Blink Reformat4c46d092018-04-07 15:32:37143
144 new UI.DropTarget(
145 this.element, [UI.DropTarget.Type.File], Common.UIString('Drop HAR files here'), this._handleDrop.bind(this));
146
147 Common.moduleSetting('networkColorCodeResourceTypes')
148 .addChangeListener(this._invalidateAllItems.bind(this, false), this);
149
150 SDK.targetManager.observeModels(SDK.NetworkManager, this);
Pavel Feldman18d13562018-07-31 03:31:18151 SDK.networkLog.addEventListener(SDK.NetworkLog.Events.RequestAdded, this._onRequestUpdated, this);
152 SDK.networkLog.addEventListener(SDK.NetworkLog.Events.RequestUpdated, this._onRequestUpdated, this);
153 SDK.networkLog.addEventListener(SDK.NetworkLog.Events.Reset, this._reset, this);
Blink Reformat4c46d092018-04-07 15:32:37154
155 this._updateGroupByFrame();
156 Common.moduleSetting('network.group-by-frame').addChangeListener(() => this._updateGroupByFrame());
157
158 this._filterBar = filterBar;
Blink Reformat4c46d092018-04-07 15:32:37159 }
160
Blink Reformat4c46d092018-04-07 15:32:37161 _updateGroupByFrame() {
162 const value = Common.moduleSetting('network.group-by-frame').get();
163 this._setGrouping(value ? 'Frame' : null);
164 }
165
166 /**
167 * @param {string} key
168 * @param {!Array<string>} values
169 */
170 static _sortSearchValues(key, values) {
171 if (key === Network.NetworkLogView.FilterType.Priority) {
172 values.sort((a, b) => {
173 const aPriority = /** @type {!Protocol.Network.ResourcePriority} */ (PerfUI.uiLabelToNetworkPriority(a));
174 const bPriority = /** @type {!Protocol.Network.ResourcePriority} */ (PerfUI.uiLabelToNetworkPriority(b));
175 return PerfUI.networkPriorityWeight(aPriority) - PerfUI.networkPriorityWeight(bPriority);
176 });
177 } else {
178 values.sort();
179 }
180 }
181
182 /**
183 * @param {!Network.NetworkLogView.Filter} filter
184 * @param {!SDK.NetworkRequest} request
185 * @return {boolean}
186 */
187 static _negativeFilter(filter, request) {
188 return !filter(request);
189 }
190
191 /**
192 * @param {?RegExp} regex
193 * @param {!SDK.NetworkRequest} request
194 * @return {boolean}
195 */
196 static _requestPathFilter(regex, request) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34197 if (!regex) {
Blink Reformat4c46d092018-04-07 15:32:37198 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34199 }
Blink Reformat4c46d092018-04-07 15:32:37200
201 return regex.test(request.path() + '/' + request.name());
202 }
203
204 /**
205 * @param {string} domain
206 * @return {!Array.<string>}
207 */
208 static _subdomains(domain) {
209 const result = [domain];
210 let indexOfPeriod = domain.indexOf('.');
211 while (indexOfPeriod !== -1) {
212 result.push('*' + domain.substring(indexOfPeriod));
213 indexOfPeriod = domain.indexOf('.', indexOfPeriod + 1);
214 }
215 return result;
216 }
217
218 /**
219 * @param {string} value
220 * @return {!Network.NetworkLogView.Filter}
221 */
222 static _createRequestDomainFilter(value) {
223 /**
224 * @param {string} string
225 * @return {string}
226 */
227 function escapeForRegExp(string) {
228 return string.escapeForRegExp();
229 }
230 const escapedPattern = value.split('*').map(escapeForRegExp).join('.*');
231 return Network.NetworkLogView._requestDomainFilter.bind(null, new RegExp('^' + escapedPattern + '$', 'i'));
232 }
233
234 /**
235 * @param {!RegExp} regex
236 * @param {!SDK.NetworkRequest} request
237 * @return {boolean}
238 */
239 static _requestDomainFilter(regex, request) {
240 return regex.test(request.domain);
241 }
242
243 /**
244 * @param {!SDK.NetworkRequest} request
245 * @return {boolean}
246 */
247 static _runningRequestFilter(request) {
248 return !request.finished;
249 }
250
251 /**
252 * @param {!SDK.NetworkRequest} request
253 * @return {boolean}
254 */
255 static _fromCacheRequestFilter(request) {
256 return request.cached();
257 }
258
259 /**
Joey Arhard183e7e2019-02-28 03:37:05260 * @param {!SDK.NetworkRequest} request
261 * @return {boolean}
262 */
263 static _interceptedByServiceWorkerFilter(request) {
264 return request.fetchedViaServiceWorker;
265 }
266
267 /**
268 * @param {!SDK.NetworkRequest} request
269 * @return {boolean}
270 */
271 static _initiatedByServiceWorkerFilter(request) {
272 return request.initiatedByServiceWorker();
273 }
274
275 /**
Blink Reformat4c46d092018-04-07 15:32:37276 * @param {string} value
277 * @param {!SDK.NetworkRequest} request
278 * @return {boolean}
279 */
280 static _requestResponseHeaderFilter(value, request) {
281 return request.responseHeaderValue(value) !== undefined;
282 }
283
284 /**
285 * @param {string} value
286 * @param {!SDK.NetworkRequest} request
287 * @return {boolean}
288 */
289 static _requestMethodFilter(value, request) {
290 return request.requestMethod === value;
291 }
292
293 /**
294 * @param {string} value
295 * @param {!SDK.NetworkRequest} request
296 * @return {boolean}
297 */
298 static _requestPriorityFilter(value, request) {
299 return request.priority() === value;
300 }
301
302 /**
303 * @param {string} value
304 * @param {!SDK.NetworkRequest} request
305 * @return {boolean}
306 */
307 static _requestMimeTypeFilter(value, request) {
308 return request.mimeType === value;
309 }
310
311 /**
312 * @param {!Network.NetworkLogView.MixedContentFilterValues} value
313 * @param {!SDK.NetworkRequest} request
314 * @return {boolean}
315 */
316 static _requestMixedContentFilter(value, request) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34317 if (value === Network.NetworkLogView.MixedContentFilterValues.Displayed) {
Blink Reformat4c46d092018-04-07 15:32:37318 return request.mixedContentType === Protocol.Security.MixedContentType.OptionallyBlockable;
Tim van der Lippe1d6e57a2019-09-30 11:55:34319 } else if (value === Network.NetworkLogView.MixedContentFilterValues.Blocked) {
Blink Reformat4c46d092018-04-07 15:32:37320 return request.mixedContentType === Protocol.Security.MixedContentType.Blockable && request.wasBlocked();
Tim van der Lippe1d6e57a2019-09-30 11:55:34321 } else if (value === Network.NetworkLogView.MixedContentFilterValues.BlockOverridden) {
Blink Reformat4c46d092018-04-07 15:32:37322 return request.mixedContentType === Protocol.Security.MixedContentType.Blockable && !request.wasBlocked();
Tim van der Lippe1d6e57a2019-09-30 11:55:34323 } else if (value === Network.NetworkLogView.MixedContentFilterValues.All) {
Blink Reformat4c46d092018-04-07 15:32:37324 return request.mixedContentType !== Protocol.Security.MixedContentType.None;
Tim van der Lippe1d6e57a2019-09-30 11:55:34325 }
Blink Reformat4c46d092018-04-07 15:32:37326
327 return false;
328 }
329
330 /**
331 * @param {string} value
332 * @param {!SDK.NetworkRequest} request
333 * @return {boolean}
334 */
335 static _requestSchemeFilter(value, request) {
336 return request.scheme === value;
337 }
338
339 /**
340 * @param {string} value
341 * @param {!SDK.NetworkRequest} request
342 * @return {boolean}
343 */
344 static _requestSetCookieDomainFilter(value, request) {
345 const cookies = request.responseCookies;
346 for (let i = 0, l = cookies ? cookies.length : 0; i < l; ++i) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34347 if (cookies[i].domain() === value) {
Blink Reformat4c46d092018-04-07 15:32:37348 return true;
Tim van der Lippe1d6e57a2019-09-30 11:55:34349 }
Blink Reformat4c46d092018-04-07 15:32:37350 }
351 return false;
352 }
353
354 /**
355 * @param {string} value
356 * @param {!SDK.NetworkRequest} request
357 * @return {boolean}
358 */
359 static _requestSetCookieNameFilter(value, request) {
360 const cookies = request.responseCookies;
361 for (let i = 0, l = cookies ? cookies.length : 0; i < l; ++i) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34362 if (cookies[i].name() === value) {
Blink Reformat4c46d092018-04-07 15:32:37363 return true;
Tim van der Lippe1d6e57a2019-09-30 11:55:34364 }
Blink Reformat4c46d092018-04-07 15:32:37365 }
366 return false;
367 }
368
369 /**
370 * @param {string} value
371 * @param {!SDK.NetworkRequest} request
372 * @return {boolean}
373 */
374 static _requestSetCookieValueFilter(value, request) {
375 const cookies = request.responseCookies;
376 for (let i = 0, l = cookies ? cookies.length : 0; i < l; ++i) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34377 if (cookies[i].value() === value) {
Blink Reformat4c46d092018-04-07 15:32:37378 return true;
Tim van der Lippe1d6e57a2019-09-30 11:55:34379 }
Blink Reformat4c46d092018-04-07 15:32:37380 }
381 return false;
382 }
383
384 /**
385 * @param {number} value
386 * @param {!SDK.NetworkRequest} request
387 * @return {boolean}
388 */
389 static _requestSizeLargerThanFilter(value, request) {
390 return request.transferSize >= value;
391 }
392
393 /**
394 * @param {string} value
395 * @param {!SDK.NetworkRequest} request
396 * @return {boolean}
397 */
398 static _statusCodeFilter(value, request) {
399 return ('' + request.statusCode) === value;
400 }
401
402 /**
403 * @param {!SDK.NetworkRequest} request
404 * @return {boolean}
405 */
406 static HTTPRequestsFilter(request) {
407 return request.parsedURL.isValid && (request.scheme in Network.NetworkLogView.HTTPSchemas);
408 }
409
410 /**
Blink Reformat4c46d092018-04-07 15:32:37411 * @param {number} windowStart
412 * @param {number} windowEnd
413 * @param {!SDK.NetworkRequest} request
414 * @return {boolean}
415 */
416 static _requestTimeFilter(windowStart, windowEnd, request) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34417 if (request.issueTime() > windowEnd) {
Blink Reformat4c46d092018-04-07 15:32:37418 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34419 }
420 if (request.endTime !== -1 && request.endTime < windowStart) {
Blink Reformat4c46d092018-04-07 15:32:37421 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34422 }
Blink Reformat4c46d092018-04-07 15:32:37423 return true;
424 }
425
426 /**
427 * @param {!SDK.NetworkRequest} request
428 */
429 static _copyRequestHeaders(request) {
Tim van der Lippe50cfa9b2019-10-01 10:40:58430 Host.InspectorFrontendHost.copyText(request.requestHeadersText());
Blink Reformat4c46d092018-04-07 15:32:37431 }
432
433 /**
434 * @param {!SDK.NetworkRequest} request
435 */
436 static _copyResponseHeaders(request) {
Tim van der Lippe50cfa9b2019-10-01 10:40:58437 Host.InspectorFrontendHost.copyText(request.responseHeadersText);
Blink Reformat4c46d092018-04-07 15:32:37438 }
439
440 /**
441 * @param {!SDK.NetworkRequest} request
442 */
443 static async _copyResponse(request) {
444 const contentData = await request.contentData();
Ingvar Stepanyan1c771842018-10-10 14:35:08445 let content = contentData.content || '';
Tim van der Lippe1d6e57a2019-09-30 11:55:34446 if (!request.contentType().isTextType()) {
Ingvar Stepanyan1c771842018-10-10 14:35:08447 content = Common.ContentProvider.contentAsDataURL(content, request.mimeType, contentData.encoded);
Tim van der Lippe1d6e57a2019-09-30 11:55:34448 } else if (contentData.encoded) {
Ingvar Stepanyan1c771842018-10-10 14:35:08449 content = window.atob(content);
Tim van der Lippe1d6e57a2019-09-30 11:55:34450 }
Tim van der Lippe50cfa9b2019-10-01 10:40:58451 Host.InspectorFrontendHost.copyText(content);
Blink Reformat4c46d092018-04-07 15:32:37452 }
453
454 /**
455 * @param {!DataTransfer} dataTransfer
456 */
457 _handleDrop(dataTransfer) {
458 const items = dataTransfer.items;
Tim van der Lippe1d6e57a2019-09-30 11:55:34459 if (!items.length) {
Blink Reformat4c46d092018-04-07 15:32:37460 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34461 }
Blink Reformat4c46d092018-04-07 15:32:37462 const entry = items[0].webkitGetAsEntry();
Tim van der Lippe1d6e57a2019-09-30 11:55:34463 if (entry.isDirectory) {
Blink Reformat4c46d092018-04-07 15:32:37464 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34465 }
Blink Reformat4c46d092018-04-07 15:32:37466
Joey Arhar0e1093c2019-05-21 00:34:22467 entry.file(this.onLoadFromFile.bind(this));
Blink Reformat4c46d092018-04-07 15:32:37468 }
469
470 /**
471 * @param {!File} file
472 */
Joey Arhar0e1093c2019-05-21 00:34:22473 async onLoadFromFile(file) {
Blink Reformat4c46d092018-04-07 15:32:37474 const outputStream = new Common.StringOutputStream();
475 const reader = new Bindings.ChunkedFileReader(file, /* chunkSize */ 10000000);
476 const success = await reader.read(outputStream);
477 if (!success) {
478 this._harLoadFailed(reader.error().message);
479 return;
480 }
481 let harRoot;
482 try {
483 // HARRoot and JSON.parse might throw.
484 harRoot = new HARImporter.HARRoot(JSON.parse(outputStream.data()));
485 } catch (e) {
486 this._harLoadFailed(e);
487 return;
488 }
Pavel Feldman18d13562018-07-31 03:31:18489 SDK.networkLog.importRequests(HARImporter.Importer.requestsFromHARLog(harRoot.log));
Blink Reformat4c46d092018-04-07 15:32:37490 }
491
492 /**
493 * @param {string} message
494 */
495 _harLoadFailed(message) {
496 Common.console.error('Failed to load HAR file with following error: ' + message);
497 }
498
499 /**
500 * @param {?string} groupKey
501 */
502 _setGrouping(groupKey) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34503 if (this._activeGroupLookup) {
Blink Reformat4c46d092018-04-07 15:32:37504 this._activeGroupLookup.reset();
Tim van der Lippe1d6e57a2019-09-30 11:55:34505 }
Blink Reformat4c46d092018-04-07 15:32:37506 const groupLookup = groupKey ? this._groupLookups.get(groupKey) || null : null;
507 this._activeGroupLookup = groupLookup;
508 this._invalidateAllItems();
509 }
510
511 /**
512 * @return {number}
513 */
514 _computeRowHeight() {
515 return Math.round(this._rawRowHeight * window.devicePixelRatio) / window.devicePixelRatio;
516 }
517
518 /**
519 * @param {!SDK.NetworkRequest} request
520 * @return {?Network.NetworkRequestNode}
521 */
522 nodeForRequest(request) {
523 return request[Network.NetworkLogView._networkNodeSymbol] || null;
524 }
525
526 /**
527 * @return {number}
528 */
529 headerHeight() {
530 return this._headerHeight;
531 }
532
533 /**
534 * @param {boolean} recording
535 */
536 setRecording(recording) {
537 this._recording = recording;
538 this._updateSummaryBar();
539 }
540
541 /**
542 * @override
543 * @param {!SDK.NetworkManager} networkManager
544 */
545 modelAdded(networkManager) {
546 // TODO(allada) Remove dependency on networkManager and instead use NetworkLog and PageLoad for needed data.
Tim van der Lippe1d6e57a2019-09-30 11:55:34547 if (networkManager.target().parentTarget()) {
Blink Reformat4c46d092018-04-07 15:32:37548 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34549 }
Blink Reformat4c46d092018-04-07 15:32:37550 const resourceTreeModel = networkManager.target().model(SDK.ResourceTreeModel);
551 if (resourceTreeModel) {
552 resourceTreeModel.addEventListener(SDK.ResourceTreeModel.Events.Load, this._loadEventFired, this);
553 resourceTreeModel.addEventListener(
554 SDK.ResourceTreeModel.Events.DOMContentLoaded, this._domContentLoadedEventFired, this);
555 }
556 }
557
558 /**
559 * @override
560 * @param {!SDK.NetworkManager} networkManager
561 */
562 modelRemoved(networkManager) {
563 if (!networkManager.target().parentTarget()) {
564 const resourceTreeModel = networkManager.target().model(SDK.ResourceTreeModel);
565 if (resourceTreeModel) {
566 resourceTreeModel.removeEventListener(SDK.ResourceTreeModel.Events.Load, this._loadEventFired, this);
567 resourceTreeModel.removeEventListener(
568 SDK.ResourceTreeModel.Events.DOMContentLoaded, this._domContentLoadedEventFired, this);
569 }
570 }
571 }
572
573 /**
574 * @param {number} start
575 * @param {number} end
576 */
577 setWindow(start, end) {
578 if (!start && !end) {
579 this._timeFilter = null;
580 this._timeCalculator.setWindow(null);
581 } else {
582 this._timeFilter = Network.NetworkLogView._requestTimeFilter.bind(null, start, end);
583 this._timeCalculator.setWindow(new Network.NetworkTimeBoundary(start, end));
584 }
585 this._filterRequests();
586 }
587
588 clearSelection() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34589 if (this._dataGrid.selectedNode) {
Blink Reformat4c46d092018-04-07 15:32:37590 this._dataGrid.selectedNode.deselect();
Tim van der Lippe1d6e57a2019-09-30 11:55:34591 }
Blink Reformat4c46d092018-04-07 15:32:37592 }
593
594 _resetSuggestionBuilder() {
595 this._suggestionBuilder.clear();
596 this._suggestionBuilder.addItem(Network.NetworkLogView.FilterType.Is, Network.NetworkLogView.IsFilterType.Running);
597 this._suggestionBuilder.addItem(
598 Network.NetworkLogView.FilterType.Is, Network.NetworkLogView.IsFilterType.FromCache);
Joey Arhard183e7e2019-02-28 03:37:05599 this._suggestionBuilder.addItem(
600 Network.NetworkLogView.FilterType.Is, Network.NetworkLogView.IsFilterType.ServiceWorkerIntercepted);
601 this._suggestionBuilder.addItem(
602 Network.NetworkLogView.FilterType.Is, Network.NetworkLogView.IsFilterType.ServiceWorkerInitiated);
Blink Reformat4c46d092018-04-07 15:32:37603 this._suggestionBuilder.addItem(Network.NetworkLogView.FilterType.LargerThan, '100');
604 this._suggestionBuilder.addItem(Network.NetworkLogView.FilterType.LargerThan, '10k');
605 this._suggestionBuilder.addItem(Network.NetworkLogView.FilterType.LargerThan, '1M');
606 this._textFilterUI.setSuggestionProvider(this._suggestionBuilder.completions.bind(this._suggestionBuilder));
607 }
608
609 /**
610 * @param {!Common.Event} event
611 */
612 _filterChanged(event) {
613 this.removeAllNodeHighlights();
614 this._parseFilterQuery(this._textFilterUI.value());
615 this._filterRequests();
Blink Reformat4c46d092018-04-07 15:32:37616 }
617
618 _showRecordingHint() {
619 this._hideRecordingHint();
620 this._recordingHint = this.element.createChild('div', 'network-status-pane fill');
621 const hintText = this._recordingHint.createChild('div', 'recording-hint');
Joey Arhar0585e6f2018-10-30 23:11:18622
623 let reloadShortcutNode = null;
624 const reloadShortcutDescriptor = UI.shortcutRegistry.shortcutDescriptorsForAction('inspector_main.reload')[0];
625 if (reloadShortcutDescriptor) {
626 reloadShortcutNode = this._recordingHint.createChild('b');
627 reloadShortcutNode.textContent = reloadShortcutDescriptor.name;
628 }
Blink Reformat4c46d092018-04-07 15:32:37629
630 if (this._recording) {
631 const recordingText = hintText.createChild('span');
632 recordingText.textContent = Common.UIString('Recording network activity\u2026');
Joey Arhar0585e6f2018-10-30 23:11:18633 if (reloadShortcutNode) {
634 hintText.createChild('br');
635 hintText.appendChild(
636 UI.formatLocalized('Perform a request or hit %s to record the reload.', [reloadShortcutNode]));
637 }
Blink Reformat4c46d092018-04-07 15:32:37638 } else {
639 const recordNode = hintText.createChild('b');
640 recordNode.textContent = UI.shortcutRegistry.shortcutTitleForAction('network.toggle-recording');
Joey Arhar0585e6f2018-10-30 23:11:18641 if (reloadShortcutNode) {
642 hintText.appendChild(UI.formatLocalized(
643 'Record (%s) or reload (%s) to display network activity.', [recordNode, reloadShortcutNode]));
644 } else {
645 hintText.appendChild(UI.formatLocalized('Record (%s) to display network activity.', [recordNode]));
646 }
Blink Reformat4c46d092018-04-07 15:32:37647 }
Kayce Basques5444c1b2019-02-15 20:32:53648 hintText.createChild('br');
649 hintText.appendChild(UI.XLink.create(
650 'https://developers.google.com/web/tools/chrome-devtools/network/?utm_source=devtools&utm_campaign=2019Q1',
651 'Learn more'));
Blink Reformat4c46d092018-04-07 15:32:37652 }
653
654 _hideRecordingHint() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34655 if (this._recordingHint) {
Blink Reformat4c46d092018-04-07 15:32:37656 this._recordingHint.remove();
Tim van der Lippe1d6e57a2019-09-30 11:55:34657 }
Blink Reformat4c46d092018-04-07 15:32:37658 this._recordingHint = null;
659 }
660
661 /**
662 * @override
663 * @return {!Array.<!Element>}
664 */
665 elementsToRestoreScrollPositionsFor() {
666 if (!this._dataGrid) // Not initialized yet.
Tim van der Lippe1d6e57a2019-09-30 11:55:34667 {
Blink Reformat4c46d092018-04-07 15:32:37668 return [];
Tim van der Lippe1d6e57a2019-09-30 11:55:34669 }
Blink Reformat4c46d092018-04-07 15:32:37670 return [this._dataGrid.scrollContainer];
671 }
672
673 columnExtensionResolved() {
674 this._invalidateAllItems(true);
675 }
676
677 _setupDataGrid() {
678 this._dataGrid.setRowContextMenuCallback((contextMenu, node) => {
679 const request = node.request();
Tim van der Lippe1d6e57a2019-09-30 11:55:34680 if (request) {
Blink Reformat4c46d092018-04-07 15:32:37681 this.handleContextMenuForRequest(contextMenu, request);
Tim van der Lippe1d6e57a2019-09-30 11:55:34682 }
Blink Reformat4c46d092018-04-07 15:32:37683 });
684 this._dataGrid.setStickToBottom(true);
685 this._dataGrid.setName('networkLog');
686 this._dataGrid.setResizeMethod(DataGrid.DataGrid.ResizeMethod.Last);
687 this._dataGrid.element.classList.add('network-log-grid');
688 this._dataGrid.element.addEventListener('mousedown', this._dataGridMouseDown.bind(this), true);
689 this._dataGrid.element.addEventListener('mousemove', this._dataGridMouseMove.bind(this), true);
690 this._dataGrid.element.addEventListener('mouseleave', () => this._setHoveredNode(null), true);
691 return this._dataGrid;
692 }
693
694 /**
695 * @param {!Event} event
696 */
697 _dataGridMouseMove(event) {
698 const node = (this._dataGrid.dataGridNodeFromNode(/** @type {!Node} */ (event.target)));
699 const highlightInitiatorChain = event.shiftKey;
700 this._setHoveredNode(node, highlightInitiatorChain);
701 }
702
703 /**
704 * @return {?Network.NetworkNode}
705 */
706 hoveredNode() {
707 return this._hoveredNode;
708 }
709
710 /**
711 * @param {?Network.NetworkNode} node
712 * @param {boolean=} highlightInitiatorChain
713 */
714 _setHoveredNode(node, highlightInitiatorChain) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34715 if (this._hoveredNode) {
Blink Reformat4c46d092018-04-07 15:32:37716 this._hoveredNode.setHovered(false, false);
Tim van der Lippe1d6e57a2019-09-30 11:55:34717 }
Blink Reformat4c46d092018-04-07 15:32:37718 this._hoveredNode = node;
Tim van der Lippe1d6e57a2019-09-30 11:55:34719 if (this._hoveredNode) {
Blink Reformat4c46d092018-04-07 15:32:37720 this._hoveredNode.setHovered(true, !!highlightInitiatorChain);
Tim van der Lippe1d6e57a2019-09-30 11:55:34721 }
Blink Reformat4c46d092018-04-07 15:32:37722 }
723
724 /**
725 * @param {!Event} event
726 */
727 _dataGridMouseDown(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34728 if (!this._dataGrid.selectedNode && event.button) {
Blink Reformat4c46d092018-04-07 15:32:37729 event.consume();
Tim van der Lippe1d6e57a2019-09-30 11:55:34730 }
Blink Reformat4c46d092018-04-07 15:32:37731 }
732
733 _updateSummaryBar() {
734 this._hideRecordingHint();
735
736 let transferSize = 0;
Dan Beam87466b52018-12-01 18:41:20737 let resourceSize = 0;
Blink Reformat4c46d092018-04-07 15:32:37738 let selectedNodeNumber = 0;
739 let selectedTransferSize = 0;
Dan Beam87466b52018-12-01 18:41:20740 let selectedResourceSize = 0;
Blink Reformat4c46d092018-04-07 15:32:37741 let baseTime = -1;
742 let maxTime = -1;
743
744 let nodeCount = 0;
Pavel Feldman18d13562018-07-31 03:31:18745 for (const request of SDK.networkLog.requests()) {
Blink Reformat4c46d092018-04-07 15:32:37746 const node = request[Network.NetworkLogView._networkNodeSymbol];
Tim van der Lippe1d6e57a2019-09-30 11:55:34747 if (!node) {
Blink Reformat4c46d092018-04-07 15:32:37748 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:34749 }
Blink Reformat4c46d092018-04-07 15:32:37750 nodeCount++;
751 const requestTransferSize = request.transferSize;
752 transferSize += requestTransferSize;
Dan Beam87466b52018-12-01 18:41:20753 const requestResourceSize = request.resourceSize;
754 resourceSize += requestResourceSize;
Blink Reformat4c46d092018-04-07 15:32:37755 if (!node[Network.NetworkLogView._isFilteredOutSymbol]) {
756 selectedNodeNumber++;
757 selectedTransferSize += requestTransferSize;
Dan Beam87466b52018-12-01 18:41:20758 selectedResourceSize += requestResourceSize;
Blink Reformat4c46d092018-04-07 15:32:37759 }
760 const networkManager = SDK.NetworkManager.forRequest(request);
761 // TODO(allada) inspectedURL should be stored in PageLoad used instead of target so HAR requests can have an
762 // inspected url.
763 if (networkManager && request.url() === networkManager.target().inspectedURL() &&
Tim van der Lippe1d6e57a2019-09-30 11:55:34764 request.resourceType() === Common.resourceTypes.Document && !networkManager.target().parentTarget()) {
Blink Reformat4c46d092018-04-07 15:32:37765 baseTime = request.startTime;
Tim van der Lippe1d6e57a2019-09-30 11:55:34766 }
767 if (request.endTime > maxTime) {
Blink Reformat4c46d092018-04-07 15:32:37768 maxTime = request.endTime;
Tim van der Lippe1d6e57a2019-09-30 11:55:34769 }
Blink Reformat4c46d092018-04-07 15:32:37770 }
771
772 if (!nodeCount) {
773 this._showRecordingHint();
774 return;
775 }
776
Joey Arhara86c14e2019-03-12 03:20:50777 this._summaryToolbar.removeToolbarItems();
Blink Reformat4c46d092018-04-07 15:32:37778 /**
779 * @param {string} chunk
Joey Arhara86c14e2019-03-12 03:20:50780 * @param {string=} title
Blink Reformat4c46d092018-04-07 15:32:37781 * @return {!Element}
782 */
Joey Arhara86c14e2019-03-12 03:20:50783 const appendChunk = (chunk, title) => {
784 const toolbarText = new UI.ToolbarText(chunk);
785 toolbarText.setTitle(title ? title : chunk);
786 this._summaryToolbar.appendToolbarItem(toolbarText);
787 return toolbarText.element;
788 };
Blink Reformat4c46d092018-04-07 15:32:37789
790 if (selectedNodeNumber !== nodeCount) {
Joey Arhara86c14e2019-03-12 03:20:50791 appendChunk(ls`${selectedNodeNumber} / ${nodeCount} requests`);
792 this._summaryToolbar.appendSeparator();
793 appendChunk(
794 ls`${Number.bytesToString(selectedTransferSize)} / ${Number.bytesToString(transferSize)} transferred`,
795 ls`${selectedTransferSize} B / ${transferSize} B transferred`);
796 this._summaryToolbar.appendSeparator();
797 appendChunk(
798 ls`${Number.bytesToString(selectedResourceSize)} / ${Number.bytesToString(resourceSize)} resources`,
799 ls`${selectedResourceSize} B / ${resourceSize} B resources`);
Blink Reformat4c46d092018-04-07 15:32:37800 } else {
Joey Arhara86c14e2019-03-12 03:20:50801 appendChunk(ls`${nodeCount} requests`);
802 this._summaryToolbar.appendSeparator();
803 appendChunk(ls`${Number.bytesToString(transferSize)} transferred`, ls`${transferSize} B transferred`);
804 this._summaryToolbar.appendSeparator();
805 appendChunk(ls`${Number.bytesToString(resourceSize)} resources`, ls`${resourceSize} B resources`);
Blink Reformat4c46d092018-04-07 15:32:37806 }
Dan Beam87466b52018-12-01 18:41:20807
Blink Reformat4c46d092018-04-07 15:32:37808 if (baseTime !== -1 && maxTime !== -1) {
Joey Arhara86c14e2019-03-12 03:20:50809 this._summaryToolbar.appendSeparator();
810 appendChunk(ls`Finish: ${Number.secondsToString(maxTime - baseTime)}`);
Blink Reformat4c46d092018-04-07 15:32:37811 if (this._mainRequestDOMContentLoadedTime !== -1 && this._mainRequestDOMContentLoadedTime > baseTime) {
Joey Arhara86c14e2019-03-12 03:20:50812 this._summaryToolbar.appendSeparator();
Alexei Filippovfdcd8a62018-12-17 21:32:30813 const domContentLoadedText =
814 ls`DOMContentLoaded: ${Number.secondsToString(this._mainRequestDOMContentLoadedTime - baseTime)}`;
Joey Arhara86c14e2019-03-12 03:20:50815 appendChunk(domContentLoadedText).style.color = Network.NetworkLogView.getDCLEventColor();
Blink Reformat4c46d092018-04-07 15:32:37816 }
817 if (this._mainRequestLoadTime !== -1) {
Joey Arhara86c14e2019-03-12 03:20:50818 this._summaryToolbar.appendSeparator();
Alexei Filippovfdcd8a62018-12-17 21:32:30819 const loadText = ls`Load: ${Number.secondsToString(this._mainRequestLoadTime - baseTime)}`;
Joey Arhara86c14e2019-03-12 03:20:50820 appendChunk(loadText).style.color = Network.NetworkLogView.getLoadEventColor();
Blink Reformat4c46d092018-04-07 15:32:37821 }
822 }
Blink Reformat4c46d092018-04-07 15:32:37823 }
824
825 scheduleRefresh() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34826 if (this._needsRefresh) {
Blink Reformat4c46d092018-04-07 15:32:37827 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34828 }
Blink Reformat4c46d092018-04-07 15:32:37829
830 this._needsRefresh = true;
831
Tim van der Lippe1d6e57a2019-09-30 11:55:34832 if (this.isShowing() && !this._refreshRequestId) {
Blink Reformat4c46d092018-04-07 15:32:37833 this._refreshRequestId = this.element.window().requestAnimationFrame(this._refresh.bind(this));
Tim van der Lippe1d6e57a2019-09-30 11:55:34834 }
Blink Reformat4c46d092018-04-07 15:32:37835 }
836
837 /**
838 * @param {!Array<number>} times
839 */
840 addFilmStripFrames(times) {
841 this._columns.addEventDividers(times, 'network-frame-divider');
842 }
843
844 /**
845 * @param {number} time
846 */
847 selectFilmStripFrame(time) {
848 this._columns.selectFilmStripFrame(time);
849 }
850
851 clearFilmStripFrame() {
852 this._columns.clearFilmStripFrame();
853 }
854
855 _refreshIfNeeded() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34856 if (this._needsRefresh) {
Blink Reformat4c46d092018-04-07 15:32:37857 this._refresh();
Tim van der Lippe1d6e57a2019-09-30 11:55:34858 }
Blink Reformat4c46d092018-04-07 15:32:37859 }
860
861 /**
862 * @param {boolean=} deferUpdate
863 */
864 _invalidateAllItems(deferUpdate) {
Pavel Feldman18d13562018-07-31 03:31:18865 this._staleRequests = new Set(SDK.networkLog.requests());
Tim van der Lippe1d6e57a2019-09-30 11:55:34866 if (deferUpdate) {
Blink Reformat4c46d092018-04-07 15:32:37867 this.scheduleRefresh();
Tim van der Lippe1d6e57a2019-09-30 11:55:34868 } else {
Blink Reformat4c46d092018-04-07 15:32:37869 this._refresh();
Tim van der Lippe1d6e57a2019-09-30 11:55:34870 }
Blink Reformat4c46d092018-04-07 15:32:37871 }
872
873 /**
874 * @return {!Network.NetworkTimeCalculator}
875 */
876 timeCalculator() {
877 return this._timeCalculator;
878 }
879
880 /**
881 * @return {!Network.NetworkTimeCalculator}
882 */
883 calculator() {
884 return this._calculator;
885 }
886
887 /**
888 * @param {!Network.NetworkTimeCalculator} x
889 */
890 setCalculator(x) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34891 if (!x || this._calculator === x) {
Blink Reformat4c46d092018-04-07 15:32:37892 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34893 }
Blink Reformat4c46d092018-04-07 15:32:37894
895 if (this._calculator !== x) {
896 this._calculator = x;
897 this._columns.setCalculator(this._calculator);
898 }
899 this._calculator.reset();
900
Tim van der Lippe1d6e57a2019-09-30 11:55:34901 if (this._calculator.startAtZero) {
Blink Reformat4c46d092018-04-07 15:32:37902 this._columns.hideEventDividers();
Tim van der Lippe1d6e57a2019-09-30 11:55:34903 } else {
Blink Reformat4c46d092018-04-07 15:32:37904 this._columns.showEventDividers();
Tim van der Lippe1d6e57a2019-09-30 11:55:34905 }
Blink Reformat4c46d092018-04-07 15:32:37906
907 this._invalidateAllItems();
908 }
909
910 /**
911 * @param {!Common.Event} event
912 */
913 _loadEventFired(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34914 if (!this._recording) {
Blink Reformat4c46d092018-04-07 15:32:37915 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34916 }
Blink Reformat4c46d092018-04-07 15:32:37917
918 const time = /** @type {number} */ (event.data.loadTime);
919 if (time) {
920 this._mainRequestLoadTime = time;
Alexei Filippovfdcd8a62018-12-17 21:32:30921 this._columns.addEventDividers([time], 'network-load-divider');
Blink Reformat4c46d092018-04-07 15:32:37922 }
923 }
924
925 /**
926 * @param {!Common.Event} event
927 */
928 _domContentLoadedEventFired(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34929 if (!this._recording) {
Blink Reformat4c46d092018-04-07 15:32:37930 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34931 }
Blink Reformat4c46d092018-04-07 15:32:37932 const data = /** @type {number} */ (event.data);
933 if (data) {
934 this._mainRequestDOMContentLoadedTime = data;
Alexei Filippovfdcd8a62018-12-17 21:32:30935 this._columns.addEventDividers([data], 'network-dcl-divider');
Blink Reformat4c46d092018-04-07 15:32:37936 }
937 }
938
939 /**
940 * @override
941 */
942 wasShown() {
943 this._refreshIfNeeded();
944 this._columns.wasShown();
945 }
946
947 /**
948 * @override
949 */
950 willHide() {
951 this._columns.willHide();
952 }
953
954 /**
955 * @override
956 */
957 onResize() {
958 this._rowHeight = this._computeRowHeight();
959 }
960
961 /**
962 * @return {!Array<!Network.NetworkNode>}
963 */
964 flatNodesList() {
965 return this._dataGrid.rootNode().flatChildren();
966 }
967
968 stylesChanged() {
969 this._columns.scheduleRefresh();
970 }
971
972 _refresh() {
973 this._needsRefresh = false;
974
975 if (this._refreshRequestId) {
976 this.element.window().cancelAnimationFrame(this._refreshRequestId);
977 this._refreshRequestId = null;
978 }
979
980 this.removeAllNodeHighlights();
981
982 this._timeCalculator.updateBoundariesForEventTime(this._mainRequestLoadTime);
983 this._durationCalculator.updateBoundariesForEventTime(this._mainRequestLoadTime);
984 this._timeCalculator.updateBoundariesForEventTime(this._mainRequestDOMContentLoadedTime);
985 this._durationCalculator.updateBoundariesForEventTime(this._mainRequestDOMContentLoadedTime);
986
987 /** @type {!Map<!Network.NetworkNode, !Network.NetworkNode>} */
988 const nodesToInsert = new Map();
989 /** @type {!Array<!Network.NetworkNode>} */
990 const nodesToRefresh = [];
991
992 /** @type {!Set<!Network.NetworkRequestNode>} */
993 const staleNodes = new Set();
994
995 // While creating nodes it may add more entries into _staleRequests because redirect request nodes update the parent
996 // node so we loop until we have no more stale requests.
997 while (this._staleRequests.size) {
998 const request = this._staleRequests.firstValue();
999 this._staleRequests.delete(request);
1000 let node = request[Network.NetworkLogView._networkNodeSymbol];
Tim van der Lippe1d6e57a2019-09-30 11:55:341001 if (!node) {
Blink Reformat4c46d092018-04-07 15:32:371002 node = this._createNodeForRequest(request);
Tim van der Lippe1d6e57a2019-09-30 11:55:341003 }
Blink Reformat4c46d092018-04-07 15:32:371004 staleNodes.add(node);
1005 }
1006
1007 for (const node of staleNodes) {
1008 const isFilteredOut = !this._applyFilter(node);
Tim van der Lippe1d6e57a2019-09-30 11:55:341009 if (isFilteredOut && node === this._hoveredNode) {
Blink Reformat4c46d092018-04-07 15:32:371010 this._setHoveredNode(null);
Tim van der Lippe1d6e57a2019-09-30 11:55:341011 }
Blink Reformat4c46d092018-04-07 15:32:371012
Tim van der Lippe1d6e57a2019-09-30 11:55:341013 if (!isFilteredOut) {
Blink Reformat4c46d092018-04-07 15:32:371014 nodesToRefresh.push(node);
Tim van der Lippe1d6e57a2019-09-30 11:55:341015 }
Blink Reformat4c46d092018-04-07 15:32:371016 const request = node.request();
1017 this._timeCalculator.updateBoundaries(request);
1018 this._durationCalculator.updateBoundaries(request);
1019 const newParent = this._parentNodeForInsert(node);
Tim van der Lippe1d6e57a2019-09-30 11:55:341020 if (node[Network.NetworkLogView._isFilteredOutSymbol] === isFilteredOut && node.parent === newParent) {
Blink Reformat4c46d092018-04-07 15:32:371021 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341022 }
Blink Reformat4c46d092018-04-07 15:32:371023 node[Network.NetworkLogView._isFilteredOutSymbol] = isFilteredOut;
1024 const removeFromParent = node.parent && (isFilteredOut || node.parent !== newParent);
1025 if (removeFromParent) {
1026 let parent = node.parent;
1027 parent.removeChild(node);
1028 while (parent && !parent.hasChildren() && parent.dataGrid && parent.dataGrid.rootNode() !== parent) {
1029 const grandparent = parent.parent;
1030 grandparent.removeChild(parent);
1031 parent = grandparent;
1032 }
1033 }
1034
Tim van der Lippe1d6e57a2019-09-30 11:55:341035 if (!newParent || isFilteredOut) {
Blink Reformat4c46d092018-04-07 15:32:371036 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341037 }
Blink Reformat4c46d092018-04-07 15:32:371038
1039 if (!newParent.dataGrid && !nodesToInsert.has(newParent)) {
1040 nodesToInsert.set(newParent, this._dataGrid.rootNode());
1041 nodesToRefresh.push(newParent);
1042 }
1043 nodesToInsert.set(node, newParent);
1044 }
1045
Tim van der Lippe1d6e57a2019-09-30 11:55:341046 for (const node of nodesToInsert.keys()) {
Blink Reformat4c46d092018-04-07 15:32:371047 nodesToInsert.get(node).appendChild(node);
Tim van der Lippe1d6e57a2019-09-30 11:55:341048 }
Blink Reformat4c46d092018-04-07 15:32:371049
Tim van der Lippe1d6e57a2019-09-30 11:55:341050 for (const node of nodesToRefresh) {
Blink Reformat4c46d092018-04-07 15:32:371051 node.refresh();
Tim van der Lippe1d6e57a2019-09-30 11:55:341052 }
Blink Reformat4c46d092018-04-07 15:32:371053
1054 this._updateSummaryBar();
1055
Tim van der Lippe1d6e57a2019-09-30 11:55:341056 if (nodesToInsert.size) {
Blink Reformat4c46d092018-04-07 15:32:371057 this._columns.sortByCurrentColumn();
Tim van der Lippe1d6e57a2019-09-30 11:55:341058 }
Blink Reformat4c46d092018-04-07 15:32:371059
1060 this._dataGrid.updateInstantly();
1061 this._didRefreshForTest();
1062 }
1063
1064 _didRefreshForTest() {
1065 }
1066
1067 /**
1068 * @param {!Network.NetworkRequestNode} node
1069 * @return {?Network.NetworkNode}
1070 */
1071 _parentNodeForInsert(node) {
Tim van der Lippe1d6e57a2019-09-30 11:55:341072 if (!this._activeGroupLookup) {
Blink Reformat4c46d092018-04-07 15:32:371073 return this._dataGrid.rootNode();
Tim van der Lippe1d6e57a2019-09-30 11:55:341074 }
Blink Reformat4c46d092018-04-07 15:32:371075
1076 const groupNode = this._activeGroupLookup.groupNodeForRequest(node.request());
Tim van der Lippe1d6e57a2019-09-30 11:55:341077 if (!groupNode) {
Blink Reformat4c46d092018-04-07 15:32:371078 return this._dataGrid.rootNode();
Tim van der Lippe1d6e57a2019-09-30 11:55:341079 }
Blink Reformat4c46d092018-04-07 15:32:371080 return groupNode;
1081 }
1082
1083 _reset() {
1084 this.dispatchEventToListeners(Network.NetworkLogView.Events.RequestSelected, null);
1085
1086 this._setHoveredNode(null);
1087 this._columns.reset();
1088
1089 this._timeFilter = null;
1090 this._calculator.reset();
1091
1092 this._timeCalculator.setWindow(null);
1093 this.linkifier.reset();
1094 this.badgePool.reset();
1095
Tim van der Lippe1d6e57a2019-09-30 11:55:341096 if (this._activeGroupLookup) {
Blink Reformat4c46d092018-04-07 15:32:371097 this._activeGroupLookup.reset();
Tim van der Lippe1d6e57a2019-09-30 11:55:341098 }
Blink Reformat4c46d092018-04-07 15:32:371099 this._staleRequests.clear();
1100 this._resetSuggestionBuilder();
1101
1102 this._mainRequestLoadTime = -1;
1103 this._mainRequestDOMContentLoadedTime = -1;
1104
1105 this._dataGrid.rootNode().removeChildren();
1106 this._updateSummaryBar();
1107 this._dataGrid.setStickToBottom(true);
1108 this.scheduleRefresh();
1109 }
1110
1111 /**
1112 * @param {string} filterString
1113 */
1114 setTextFilterValue(filterString) {
1115 this._textFilterUI.setValue(filterString);
1116 this._dataURLFilterUI.setChecked(false);
1117 this._resourceCategoryFilterUI.reset();
1118 }
1119
1120 /**
1121 * @param {!SDK.NetworkRequest} request
1122 */
1123 _createNodeForRequest(request) {
1124 const node = new Network.NetworkRequestNode(this, request);
1125 request[Network.NetworkLogView._networkNodeSymbol] = node;
1126 node[Network.NetworkLogView._isFilteredOutSymbol] = true;
1127
Tim van der Lippe1d6e57a2019-09-30 11:55:341128 for (let redirect = request.redirectSource(); redirect; redirect = redirect.redirectSource()) {
Blink Reformat4c46d092018-04-07 15:32:371129 this._refreshRequest(redirect);
Tim van der Lippe1d6e57a2019-09-30 11:55:341130 }
Blink Reformat4c46d092018-04-07 15:32:371131 return node;
1132 }
1133
1134 /**
1135 * @param {!Common.Event} event
1136 */
1137 _onRequestUpdated(event) {
1138 const request = /** @type {!SDK.NetworkRequest} */ (event.data);
1139 this._refreshRequest(request);
1140 }
1141
1142 /**
1143 * @param {!SDK.NetworkRequest} request
1144 */
1145 _refreshRequest(request) {
1146 Network.NetworkLogView._subdomains(request.domain)
1147 .forEach(
1148 this._suggestionBuilder.addItem.bind(this._suggestionBuilder, Network.NetworkLogView.FilterType.Domain));
1149 this._suggestionBuilder.addItem(Network.NetworkLogView.FilterType.Method, request.requestMethod);
1150 this._suggestionBuilder.addItem(Network.NetworkLogView.FilterType.MimeType, request.mimeType);
1151 this._suggestionBuilder.addItem(Network.NetworkLogView.FilterType.Scheme, '' + request.scheme);
1152 this._suggestionBuilder.addItem(Network.NetworkLogView.FilterType.StatusCode, '' + request.statusCode);
1153
1154 const priority = request.priority();
1155 if (priority) {
1156 this._suggestionBuilder.addItem(
1157 Network.NetworkLogView.FilterType.Priority, PerfUI.uiLabelForNetworkPriority(priority));
1158 }
1159
1160 if (request.mixedContentType !== Protocol.Security.MixedContentType.None) {
1161 this._suggestionBuilder.addItem(
1162 Network.NetworkLogView.FilterType.MixedContent, Network.NetworkLogView.MixedContentFilterValues.All);
1163 }
1164
1165 if (request.mixedContentType === Protocol.Security.MixedContentType.OptionallyBlockable) {
1166 this._suggestionBuilder.addItem(
1167 Network.NetworkLogView.FilterType.MixedContent, Network.NetworkLogView.MixedContentFilterValues.Displayed);
1168 }
1169
1170 if (request.mixedContentType === Protocol.Security.MixedContentType.Blockable) {
1171 const suggestion = request.wasBlocked() ? Network.NetworkLogView.MixedContentFilterValues.Blocked :
1172 Network.NetworkLogView.MixedContentFilterValues.BlockOverridden;
1173 this._suggestionBuilder.addItem(Network.NetworkLogView.FilterType.MixedContent, suggestion);
1174 }
1175
1176 const responseHeaders = request.responseHeaders;
Tim van der Lippe1d6e57a2019-09-30 11:55:341177 for (let i = 0, l = responseHeaders.length; i < l; ++i) {
Blink Reformat4c46d092018-04-07 15:32:371178 this._suggestionBuilder.addItem(Network.NetworkLogView.FilterType.HasResponseHeader, responseHeaders[i].name);
Tim van der Lippe1d6e57a2019-09-30 11:55:341179 }
Blink Reformat4c46d092018-04-07 15:32:371180 const cookies = request.responseCookies;
1181 for (let i = 0, l = cookies ? cookies.length : 0; i < l; ++i) {
1182 const cookie = cookies[i];
1183 this._suggestionBuilder.addItem(Network.NetworkLogView.FilterType.SetCookieDomain, cookie.domain());
1184 this._suggestionBuilder.addItem(Network.NetworkLogView.FilterType.SetCookieName, cookie.name());
1185 this._suggestionBuilder.addItem(Network.NetworkLogView.FilterType.SetCookieValue, cookie.value());
1186 }
1187
1188 this._staleRequests.add(request);
1189 this.scheduleRefresh();
1190 }
1191
1192 /**
1193 * @return {number}
1194 */
1195 rowHeight() {
1196 return this._rowHeight;
1197 }
1198
1199 /**
1200 * @param {boolean} gridMode
1201 */
1202 switchViewMode(gridMode) {
1203 this._columns.switchViewMode(gridMode);
1204 }
1205
1206 /**
1207 * @param {!UI.ContextMenu} contextMenu
1208 * @param {!SDK.NetworkRequest} request
1209 */
1210 handleContextMenuForRequest(contextMenu, request) {
1211 contextMenu.appendApplicableItems(request);
1212 let copyMenu = contextMenu.clipboardSection().appendSubMenuItem(Common.UIString('Copy'));
1213 const footerSection = copyMenu.footerSection();
1214 if (request) {
1215 copyMenu.defaultSection().appendItem(
Tim van der Lippe50cfa9b2019-10-01 10:40:581216 UI.copyLinkAddressLabel(),
1217 Host.InspectorFrontendHost.copyText.bind(Host.InspectorFrontendHost, request.contentURL()));
Blink Reformat4c46d092018-04-07 15:32:371218 if (request.requestHeadersText()) {
1219 copyMenu.defaultSection().appendItem(
1220 Common.UIString('Copy request headers'), Network.NetworkLogView._copyRequestHeaders.bind(null, request));
1221 }
1222
1223 if (request.responseHeadersText) {
1224 copyMenu.defaultSection().appendItem(
1225 Common.UIString('Copy response headers'), Network.NetworkLogView._copyResponseHeaders.bind(null, request));
1226 }
1227
1228 if (request.finished) {
1229 copyMenu.defaultSection().appendItem(
1230 Common.UIString('Copy response'), Network.NetworkLogView._copyResponse.bind(null, request));
1231 }
1232
Harley Libcf41f92018-09-10 18:01:131233 const disableIfBlob = request.isBlobRequest();
Blink Reformat4c46d092018-04-07 15:32:371234 if (Host.isWin()) {
1235 footerSection.appendItem(
Harley Libcf41f92018-09-10 18:01:131236 Common.UIString('Copy as PowerShell'), this._copyPowerShellCommand.bind(this, request), disableIfBlob);
Blink Reformat4c46d092018-04-07 15:32:371237 footerSection.appendItem(
Harley Libcf41f92018-09-10 18:01:131238 Common.UIString('Copy as fetch'), this._copyFetchCall.bind(this, request), disableIfBlob);
Blink Reformat4c46d092018-04-07 15:32:371239 footerSection.appendItem(
Harley Libcf41f92018-09-10 18:01:131240 Common.UIString('Copy as cURL (cmd)'), this._copyCurlCommand.bind(this, request, 'win'), disableIfBlob);
1241 footerSection.appendItem(
1242 Common.UIString('Copy as cURL (bash)'), this._copyCurlCommand.bind(this, request, 'unix'), disableIfBlob);
Blink Reformat4c46d092018-04-07 15:32:371243 footerSection.appendItem(Common.UIString('Copy all as PowerShell'), this._copyAllPowerShellCommand.bind(this));
1244 footerSection.appendItem(Common.UIString('Copy all as fetch'), this._copyAllFetchCall.bind(this));
1245 footerSection.appendItem(Common.UIString('Copy all as cURL (cmd)'), this._copyAllCurlCommand.bind(this, 'win'));
1246 footerSection.appendItem(
1247 Common.UIString('Copy all as cURL (bash)'), this._copyAllCurlCommand.bind(this, 'unix'));
1248 } else {
Harley Libcf41f92018-09-10 18:01:131249 footerSection.appendItem(
1250 Common.UIString('Copy as fetch'), this._copyFetchCall.bind(this, request), disableIfBlob);
1251 footerSection.appendItem(
1252 Common.UIString('Copy as cURL'), this._copyCurlCommand.bind(this, request, 'unix'), disableIfBlob);
Blink Reformat4c46d092018-04-07 15:32:371253 footerSection.appendItem(Common.UIString('Copy all as fetch'), this._copyAllFetchCall.bind(this));
1254 footerSection.appendItem(Common.UIString('Copy all as cURL'), this._copyAllCurlCommand.bind(this, 'unix'));
1255 }
1256 } else {
1257 copyMenu = contextMenu.clipboardSection().appendSubMenuItem(Common.UIString('Copy'));
1258 }
1259 footerSection.appendItem(Common.UIString('Copy all as HAR'), this._copyAll.bind(this));
1260
Joey Arhar0e1093c2019-05-21 00:34:221261 contextMenu.saveSection().appendItem(ls`Save all as HAR with content`, this.exportAll.bind(this));
Blink Reformat4c46d092018-04-07 15:32:371262
1263 contextMenu.editSection().appendItem(Common.UIString('Clear browser cache'), this._clearBrowserCache.bind(this));
1264 contextMenu.editSection().appendItem(
1265 Common.UIString('Clear browser cookies'), this._clearBrowserCookies.bind(this));
1266
1267 if (request) {
1268 const maxBlockedURLLength = 20;
1269 const manager = SDK.multitargetNetworkManager;
1270 let patterns = manager.blockedPatterns();
1271
Tim van der Lippeffa78622019-09-16 12:07:121272 /**
1273 * @param {string} url
1274 */
1275 function addBlockedURL(url) {
1276 patterns.push({enabled: true, url: url});
1277 manager.setBlockedPatterns(patterns);
1278 manager.setBlockingEnabled(true);
1279 UI.viewManager.showView('network.blocked-urls');
1280 }
1281
1282 /**
1283 * @param {string} url
1284 */
1285 function removeBlockedURL(url) {
1286 patterns = patterns.filter(pattern => pattern.url !== url);
1287 manager.setBlockedPatterns(patterns);
1288 UI.viewManager.showView('network.blocked-urls');
1289 }
1290
Blink Reformat4c46d092018-04-07 15:32:371291 const urlWithoutScheme = request.parsedURL.urlWithoutScheme();
1292 if (urlWithoutScheme && !patterns.find(pattern => pattern.url === urlWithoutScheme)) {
1293 contextMenu.debugSection().appendItem(
1294 Common.UIString('Block request URL'), addBlockedURL.bind(null, urlWithoutScheme));
1295 } else if (urlWithoutScheme) {
1296 const croppedURL = urlWithoutScheme.trimMiddle(maxBlockedURLLength);
1297 contextMenu.debugSection().appendItem(
1298 Common.UIString('Unblock %s', croppedURL), removeBlockedURL.bind(null, urlWithoutScheme));
1299 }
1300
1301 const domain = request.parsedURL.domain();
1302 if (domain && !patterns.find(pattern => pattern.url === domain)) {
1303 contextMenu.debugSection().appendItem(
1304 Common.UIString('Block request domain'), addBlockedURL.bind(null, domain));
1305 } else if (domain) {
1306 const croppedDomain = domain.trimMiddle(maxBlockedURLLength);
1307 contextMenu.debugSection().appendItem(
1308 Common.UIString('Unblock %s', croppedDomain), removeBlockedURL.bind(null, domain));
1309 }
1310
1311 if (SDK.NetworkManager.canReplayRequest(request)) {
1312 contextMenu.debugSection().appendItem(
1313 Common.UIString('Replay XHR'), SDK.NetworkManager.replayRequest.bind(null, request));
1314 }
Blink Reformat4c46d092018-04-07 15:32:371315 }
1316 }
1317
1318 _harRequests() {
Joey Arharb3d6de42019-04-23 21:26:171319 return SDK.networkLog.requests().filter(Network.NetworkLogView.HTTPRequestsFilter).filter(request => {
1320 return request.finished ||
1321 (request.resourceType() === Common.resourceTypes.WebSocket && request.responseReceivedTime);
1322 });
Blink Reformat4c46d092018-04-07 15:32:371323 }
1324
1325 async _copyAll() {
Pavel Feldman18d13562018-07-31 03:31:181326 const harArchive = {log: await SDK.HARLog.build(this._harRequests())};
Tim van der Lippe50cfa9b2019-10-01 10:40:581327 Host.InspectorFrontendHost.copyText(JSON.stringify(harArchive, null, 2));
Blink Reformat4c46d092018-04-07 15:32:371328 }
1329
1330 /**
1331 * @param {!SDK.NetworkRequest} request
1332 * @param {string} platform
1333 */
1334 async _copyCurlCommand(request, platform) {
1335 const command = await this._generateCurlCommand(request, platform);
Tim van der Lippe50cfa9b2019-10-01 10:40:581336 Host.InspectorFrontendHost.copyText(command);
Blink Reformat4c46d092018-04-07 15:32:371337 }
1338
1339 /**
1340 * @param {string} platform
1341 */
1342 async _copyAllCurlCommand(platform) {
Harley Libcf41f92018-09-10 18:01:131343 const commands = await this._generateAllCurlCommand(SDK.networkLog.requests(), platform);
Tim van der Lippe50cfa9b2019-10-01 10:40:581344 Host.InspectorFrontendHost.copyText(commands);
Blink Reformat4c46d092018-04-07 15:32:371345 }
1346
1347 /**
1348 * @param {!SDK.NetworkRequest} request
1349 * @param {string} platform
1350 */
1351 async _copyFetchCall(request, platform) {
1352 const command = await this._generateFetchCall(request);
Tim van der Lippe50cfa9b2019-10-01 10:40:581353 Host.InspectorFrontendHost.copyText(command);
Blink Reformat4c46d092018-04-07 15:32:371354 }
1355
1356 async _copyAllFetchCall() {
Harley Libcf41f92018-09-10 18:01:131357 const commands = await this._generateAllFetchCall(SDK.networkLog.requests());
Tim van der Lippe50cfa9b2019-10-01 10:40:581358 Host.InspectorFrontendHost.copyText(commands);
Blink Reformat4c46d092018-04-07 15:32:371359 }
1360
1361 /**
1362 * @param {!SDK.NetworkRequest} request
1363 */
1364 async _copyPowerShellCommand(request) {
1365 const command = await this._generatePowerShellCommand(request);
Tim van der Lippe50cfa9b2019-10-01 10:40:581366 Host.InspectorFrontendHost.copyText(command);
Blink Reformat4c46d092018-04-07 15:32:371367 }
1368
1369 async _copyAllPowerShellCommand() {
Harley Li5a470e92019-09-26 21:38:351370 const commands = await this._generateAllPowerShellCommand(SDK.networkLog.requests());
Tim van der Lippe50cfa9b2019-10-01 10:40:581371 Host.InspectorFrontendHost.copyText(commands);
Blink Reformat4c46d092018-04-07 15:32:371372 }
1373
Joey Arhar0e1093c2019-05-21 00:34:221374 async exportAll() {
Blink Reformat4c46d092018-04-07 15:32:371375 const url = SDK.targetManager.mainTarget().inspectedURL();
1376 const parsedURL = url.asParsedURL();
1377 const filename = parsedURL ? parsedURL.host : 'network-log';
1378 const stream = new Bindings.FileOutputStream();
1379
Tim van der Lippe1d6e57a2019-09-30 11:55:341380 if (!await stream.open(filename + '.har')) {
Blink Reformat4c46d092018-04-07 15:32:371381 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:341382 }
Blink Reformat4c46d092018-04-07 15:32:371383
1384 const progressIndicator = new UI.ProgressIndicator();
1385 this._progressBarContainer.appendChild(progressIndicator.element);
1386 await Network.HARWriter.write(stream, this._harRequests(), progressIndicator);
1387 progressIndicator.done();
1388 stream.close();
1389 }
1390
1391 _clearBrowserCache() {
Tim van der Lippe1d6e57a2019-09-30 11:55:341392 if (confirm(Common.UIString('Are you sure you want to clear browser cache?'))) {
Blink Reformat4c46d092018-04-07 15:32:371393 SDK.multitargetNetworkManager.clearBrowserCache();
Tim van der Lippe1d6e57a2019-09-30 11:55:341394 }
Blink Reformat4c46d092018-04-07 15:32:371395 }
1396
1397 _clearBrowserCookies() {
Tim van der Lippe1d6e57a2019-09-30 11:55:341398 if (confirm(Common.UIString('Are you sure you want to clear browser cookies?'))) {
Blink Reformat4c46d092018-04-07 15:32:371399 SDK.multitargetNetworkManager.clearBrowserCookies();
Tim van der Lippe1d6e57a2019-09-30 11:55:341400 }
Blink Reformat4c46d092018-04-07 15:32:371401 }
1402
1403 _removeAllHighlights() {
1404 this.removeAllNodeHighlights();
Tim van der Lippe1d6e57a2019-09-30 11:55:341405 for (let i = 0; i < this._highlightedSubstringChanges.length; ++i) {
Blink Reformat4c46d092018-04-07 15:32:371406 UI.revertDomChanges(this._highlightedSubstringChanges[i]);
Tim van der Lippe1d6e57a2019-09-30 11:55:341407 }
Blink Reformat4c46d092018-04-07 15:32:371408 this._highlightedSubstringChanges = [];
1409 }
1410
1411 /**
1412 * @param {!Network.NetworkRequestNode} node
1413 * @return {boolean}
1414 */
1415 _applyFilter(node) {
1416 const request = node.request();
Tim van der Lippe1d6e57a2019-09-30 11:55:341417 if (this._timeFilter && !this._timeFilter(request)) {
Blink Reformat4c46d092018-04-07 15:32:371418 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:341419 }
Blink Reformat4c46d092018-04-07 15:32:371420 const categoryName = request.resourceType().category().title;
Tim van der Lippe1d6e57a2019-09-30 11:55:341421 if (!this._resourceCategoryFilterUI.accept(categoryName)) {
Blink Reformat4c46d092018-04-07 15:32:371422 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:341423 }
1424 if (this._dataURLFilterUI.checked() && (request.parsedURL.isDataURL() || request.parsedURL.isBlobURL())) {
Blink Reformat4c46d092018-04-07 15:32:371425 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:341426 }
1427 if (request.statusText === 'Service Worker Fallback Required') {
Blink Reformat4c46d092018-04-07 15:32:371428 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:341429 }
Blink Reformat4c46d092018-04-07 15:32:371430 for (let i = 0; i < this._filters.length; ++i) {
Tim van der Lippe1d6e57a2019-09-30 11:55:341431 if (!this._filters[i](request)) {
Blink Reformat4c46d092018-04-07 15:32:371432 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:341433 }
Blink Reformat4c46d092018-04-07 15:32:371434 }
1435 return true;
1436 }
1437
1438 /**
1439 * @param {string} query
1440 */
1441 _parseFilterQuery(query) {
1442 const descriptors = this._filterParser.parse(query);
1443 this._filters = descriptors.map(descriptor => {
1444 const key = descriptor.key;
1445 const text = descriptor.text || '';
1446 const regex = descriptor.regex;
1447 let filter;
1448 if (key) {
1449 const defaultText = (key + ':' + text).escapeForRegExp();
1450 filter = this._createSpecialFilter(/** @type {!Network.NetworkLogView.FilterType} */ (key), text) ||
1451 Network.NetworkLogView._requestPathFilter.bind(null, new RegExp(defaultText, 'i'));
1452 } else if (descriptor.regex) {
1453 filter = Network.NetworkLogView._requestPathFilter.bind(null, /** @type {!RegExp} */ (regex));
1454 } else {
1455 filter = Network.NetworkLogView._requestPathFilter.bind(null, new RegExp(text.escapeForRegExp(), 'i'));
1456 }
1457 return descriptor.negative ? Network.NetworkLogView._negativeFilter.bind(null, filter) : filter;
1458 });
1459 }
1460
1461 /**
1462 * @param {!Network.NetworkLogView.FilterType} type
1463 * @param {string} value
1464 * @return {?Network.NetworkLogView.Filter}
1465 */
1466 _createSpecialFilter(type, value) {
1467 switch (type) {
1468 case Network.NetworkLogView.FilterType.Domain:
1469 return Network.NetworkLogView._createRequestDomainFilter(value);
1470
1471 case Network.NetworkLogView.FilterType.HasResponseHeader:
1472 return Network.NetworkLogView._requestResponseHeaderFilter.bind(null, value);
1473
1474 case Network.NetworkLogView.FilterType.Is:
Tim van der Lippe1d6e57a2019-09-30 11:55:341475 if (value.toLowerCase() === Network.NetworkLogView.IsFilterType.Running) {
Blink Reformat4c46d092018-04-07 15:32:371476 return Network.NetworkLogView._runningRequestFilter;
Tim van der Lippe1d6e57a2019-09-30 11:55:341477 }
1478 if (value.toLowerCase() === Network.NetworkLogView.IsFilterType.FromCache) {
Blink Reformat4c46d092018-04-07 15:32:371479 return Network.NetworkLogView._fromCacheRequestFilter;
Tim van der Lippe1d6e57a2019-09-30 11:55:341480 }
1481 if (value.toLowerCase() === Network.NetworkLogView.IsFilterType.ServiceWorkerIntercepted) {
Joey Arhard183e7e2019-02-28 03:37:051482 return Network.NetworkLogView._interceptedByServiceWorkerFilter;
Tim van der Lippe1d6e57a2019-09-30 11:55:341483 }
1484 if (value.toLowerCase() === Network.NetworkLogView.IsFilterType.ServiceWorkerInitiated) {
Joey Arhard183e7e2019-02-28 03:37:051485 return Network.NetworkLogView._initiatedByServiceWorkerFilter;
Tim van der Lippe1d6e57a2019-09-30 11:55:341486 }
Blink Reformat4c46d092018-04-07 15:32:371487 break;
1488
1489 case Network.NetworkLogView.FilterType.LargerThan:
1490 return this._createSizeFilter(value.toLowerCase());
1491
1492 case Network.NetworkLogView.FilterType.Method:
1493 return Network.NetworkLogView._requestMethodFilter.bind(null, value);
1494
1495 case Network.NetworkLogView.FilterType.MimeType:
1496 return Network.NetworkLogView._requestMimeTypeFilter.bind(null, value);
1497
1498 case Network.NetworkLogView.FilterType.MixedContent:
1499 return Network.NetworkLogView._requestMixedContentFilter.bind(
1500 null, /** @type {!Network.NetworkLogView.MixedContentFilterValues} */ (value));
1501
1502 case Network.NetworkLogView.FilterType.Scheme:
1503 return Network.NetworkLogView._requestSchemeFilter.bind(null, value);
1504
1505 case Network.NetworkLogView.FilterType.SetCookieDomain:
1506 return Network.NetworkLogView._requestSetCookieDomainFilter.bind(null, value);
1507
1508 case Network.NetworkLogView.FilterType.SetCookieName:
1509 return Network.NetworkLogView._requestSetCookieNameFilter.bind(null, value);
1510
1511 case Network.NetworkLogView.FilterType.SetCookieValue:
1512 return Network.NetworkLogView._requestSetCookieValueFilter.bind(null, value);
1513
1514 case Network.NetworkLogView.FilterType.Priority:
1515 return Network.NetworkLogView._requestPriorityFilter.bind(null, PerfUI.uiLabelToNetworkPriority(value));
1516
1517 case Network.NetworkLogView.FilterType.StatusCode:
1518 return Network.NetworkLogView._statusCodeFilter.bind(null, value);
1519 }
1520 return null;
1521 }
1522
1523 /**
1524 * @param {string} value
1525 * @return {?Network.NetworkLogView.Filter}
1526 */
1527 _createSizeFilter(value) {
1528 let multiplier = 1;
1529 if (value.endsWith('k')) {
1530 multiplier = 1024;
1531 value = value.substring(0, value.length - 1);
1532 } else if (value.endsWith('m')) {
1533 multiplier = 1024 * 1024;
1534 value = value.substring(0, value.length - 1);
1535 }
1536 const quantity = Number(value);
Tim van der Lippe1d6e57a2019-09-30 11:55:341537 if (isNaN(quantity)) {
Blink Reformat4c46d092018-04-07 15:32:371538 return null;
Tim van der Lippe1d6e57a2019-09-30 11:55:341539 }
Blink Reformat4c46d092018-04-07 15:32:371540 return Network.NetworkLogView._requestSizeLargerThanFilter.bind(null, quantity * multiplier);
1541 }
1542
1543 _filterRequests() {
1544 this._removeAllHighlights();
1545 this._invalidateAllItems();
1546 }
1547
1548 /**
1549 * @param {!SDK.NetworkRequest} request
1550 * @return {?Network.NetworkRequestNode}
1551 */
1552 _reveal(request) {
1553 this.removeAllNodeHighlights();
1554 const node = request[Network.NetworkLogView._networkNodeSymbol];
Tim van der Lippe1d6e57a2019-09-30 11:55:341555 if (!node || !node.dataGrid) {
Blink Reformat4c46d092018-04-07 15:32:371556 return null;
Tim van der Lippe1d6e57a2019-09-30 11:55:341557 }
Blink Reformat4c46d092018-04-07 15:32:371558 node.reveal();
1559 return node;
1560 }
1561
1562 /**
1563 * @param {!SDK.NetworkRequest} request
1564 */
1565 revealAndHighlightRequest(request) {
1566 const node = this._reveal(request);
Tim van der Lippe1d6e57a2019-09-30 11:55:341567 if (node) {
Blink Reformat4c46d092018-04-07 15:32:371568 this._highlightNode(node);
Tim van der Lippe1d6e57a2019-09-30 11:55:341569 }
Blink Reformat4c46d092018-04-07 15:32:371570 }
1571
1572 /**
1573 * @param {!SDK.NetworkRequest} request
1574 */
1575 selectRequest(request) {
Eugene Ostroukhovb600f662018-05-09 00:18:141576 this.setTextFilterValue('');
Blink Reformat4c46d092018-04-07 15:32:371577 const node = this._reveal(request);
Tim van der Lippe1d6e57a2019-09-30 11:55:341578 if (node) {
Blink Reformat4c46d092018-04-07 15:32:371579 node.select();
Tim van der Lippe1d6e57a2019-09-30 11:55:341580 }
Blink Reformat4c46d092018-04-07 15:32:371581 }
1582
1583 removeAllNodeHighlights() {
1584 if (this._highlightedNode) {
1585 this._highlightedNode.element().classList.remove('highlighted-row');
1586 this._highlightedNode = null;
1587 }
1588 }
1589
1590 /**
1591 * @param {!Network.NetworkRequestNode} node
1592 */
1593 _highlightNode(node) {
1594 UI.runCSSAnimationOnce(node.element(), 'highlighted-row');
1595 this._highlightedNode = node;
1596 }
1597
1598 /**
Harley Libcf41f92018-09-10 18:01:131599 * @param {!Array<!SDK.NetworkRequest>} requests
1600 * @return {!Array<!SDK.NetworkRequest>}
1601 */
1602 _filterOutBlobRequests(requests) {
1603 return requests.filter(request => !request.isBlobRequest());
1604 }
1605
1606 /**
Blink Reformat4c46d092018-04-07 15:32:371607 * @param {!SDK.NetworkRequest} request
1608 * @return {!Promise<string>}
1609 */
1610 async _generateFetchCall(request) {
1611 const ignoredHeaders = {
1612 // Internal headers
1613 'method': 1,
1614 'path': 1,
1615 'scheme': 1,
1616 'version': 1,
1617
1618 // Unsafe headers
1619 // Keep this list synchronized with src/net/http/http_util.cc
1620 'accept-charset': 1,
1621 'accept-encoding': 1,
1622 'access-control-request-headers': 1,
1623 'access-control-request-method': 1,
1624 'connection': 1,
1625 'content-length': 1,
1626 'cookie': 1,
1627 'cookie2': 1,
1628 'date': 1,
1629 'dnt': 1,
1630 'expect': 1,
1631 'host': 1,
1632 'keep-alive': 1,
1633 'origin': 1,
1634 'referer': 1,
1635 'te': 1,
1636 'trailer': 1,
1637 'transfer-encoding': 1,
1638 'upgrade': 1,
1639 'via': 1,
1640 // TODO(phistuck) - remove this once crbug.com/571722 is fixed.
1641 'user-agent': 1
1642 };
1643
1644 const credentialHeaders = {'cookie': 1, 'authorization': 1};
1645
1646 const url = JSON.stringify(request.url());
1647
1648 const requestHeaders = request.requestHeaders();
1649 const headerData = requestHeaders.reduce((result, header) => {
1650 const name = header.name;
1651
Tim van der Lippe1d6e57a2019-09-30 11:55:341652 if (!ignoredHeaders[name.toLowerCase()] && !name.includes(':')) {
Blink Reformat4c46d092018-04-07 15:32:371653 result.append(name, header.value);
Tim van der Lippe1d6e57a2019-09-30 11:55:341654 }
Blink Reformat4c46d092018-04-07 15:32:371655
1656 return result;
1657 }, new Headers());
1658
1659 const headers = {};
Tim van der Lippe1d6e57a2019-09-30 11:55:341660 for (const headerArray of headerData) {
PhistucK6ed0a3e2018-08-04 06:28:411661 headers[headerArray[0]] = headerArray[1];
Tim van der Lippe1d6e57a2019-09-30 11:55:341662 }
Blink Reformat4c46d092018-04-07 15:32:371663
1664 const credentials =
1665 request.requestCookies || requestHeaders.some(({name}) => credentialHeaders[name.toLowerCase()]) ? 'include' :
1666 'omit';
1667
1668 const referrerHeader = requestHeaders.find(({name}) => name.toLowerCase() === 'referer');
1669
1670 const referrer = referrerHeader ? referrerHeader.value : void 0;
1671
1672 const referrerPolicy = request.referrerPolicy() || void 0;
1673
1674 const requestBody = await request.requestFormData();
1675
1676 const fetchOptions = {
1677 credentials,
PhistucK6ed0a3e2018-08-04 06:28:411678 headers: Object.keys(headers).length ? headers : void 0,
Blink Reformat4c46d092018-04-07 15:32:371679 referrer,
1680 referrerPolicy,
1681 body: requestBody,
1682 method: request.requestMethod,
1683 mode: 'cors'
1684 };
1685
1686 const options = JSON.stringify(fetchOptions);
1687 return `fetch(${url}, ${options});`;
1688 }
1689
1690 /**
Harley Libcf41f92018-09-10 18:01:131691 * @param {!Array<!SDK.NetworkRequest>} requests
1692 * @return {!Promise<string>}
1693 */
1694 async _generateAllFetchCall(requests) {
1695 const nonBlobRequests = this._filterOutBlobRequests(requests);
1696 const commands = await Promise.all(nonBlobRequests.map(request => this._generateFetchCall(request)));
1697 return commands.join(' ;\n');
1698 }
1699
1700 /**
Blink Reformat4c46d092018-04-07 15:32:371701 * @param {!SDK.NetworkRequest} request
1702 * @param {string} platform
1703 * @return {!Promise<string>}
1704 */
1705 async _generateCurlCommand(request, platform) {
1706 let command = ['curl'];
Eric Lawrence7a7b3682019-10-17 23:06:361707 // Most of these headers are derived from the URL and are automatically added by cURL.
1708 // The |Accept-Encoding| header is ignored to prevent decompression errors. crbug.com/1015321
1709 const ignoredHeaders = {'accept-encoding': 1, 'host': 1, 'method': 1, 'path': 1, 'scheme': 1, 'version': 1};
Blink Reformat4c46d092018-04-07 15:32:371710
1711 function escapeStringWin(str) {
1712 /* If there are no new line characters do not escape the " characters
1713 since it only uglifies the command.
1714
1715 Because cmd.exe parser and MS Crt arguments parsers use some of the
1716 same escape characters, they can interact with each other in
1717 horrible ways, the order of operations is critical.
1718
1719 Replace \ with \\ first because it is an escape character for certain
1720 conditions in both parsers.
1721
1722 Replace all " with \" to ensure the first parser does not remove it.
1723
1724 Then escape all characters we are not sure about with ^ to ensure it
1725 gets to MS Crt parser safely.
1726
1727 The % character is special because MS Crt parser will try and look for
1728 ENV variables and fill them in it's place. We cannot escape them with %
1729 and cannot escape them with ^ (because it's cmd.exe's escape not MS Crt
1730 parser); So we can get cmd.exe parser to escape the character after it,
1731 if it is followed by a valid beginning character of an ENV variable.
1732 This ensures we do not try and double escape another ^ if it was placed
1733 by the previous replace.
1734
1735 Lastly we replace new lines with ^ and TWO new lines because the first
1736 new line is there to enact the escape command the second is the character
1737 to escape (in this case new line).
1738 */
1739 const encapsChars = /[\r\n]/.test(str) ? '^"' : '"';
1740 return encapsChars +
1741 str.replace(/\\/g, '\\\\')
1742 .replace(/"/g, '\\"')
1743 .replace(/[^a-zA-Z0-9\s_\-:=+~'\/.',?;()*`]/g, '^$&')
1744 .replace(/%(?=[a-zA-Z0-9_])/g, '%^')
1745 .replace(/\r\n|[\n\r]/g, '^\n\n') +
1746 encapsChars;
1747 }
1748
1749 /**
1750 * @param {string} str
1751 * @return {string}
1752 */
1753 function escapeStringPosix(str) {
1754 /**
1755 * @param {string} x
1756 * @return {string}
1757 */
1758 function escapeCharacter(x) {
Erik Luoaa676752018-08-21 05:52:221759 const code = x.charCodeAt(0);
Joey Arhar2d21f712019-05-20 21:07:121760 let hexString = code.toString(16);
1761 // Zero pad to four digits to comply with ANSI-C Quoting:
1762 // http://www.gnu.org/software/bash/manual/html_node/ANSI_002dC-Quoting.html
Tim van der Lippe1d6e57a2019-09-30 11:55:341763 while (hexString.length < 4) {
Joey Arhar2d21f712019-05-20 21:07:121764 hexString = '0' + hexString;
Tim van der Lippe1d6e57a2019-09-30 11:55:341765 }
Joey Arhar2d21f712019-05-20 21:07:121766
1767 return '\\u' + hexString;
Blink Reformat4c46d092018-04-07 15:32:371768 }
1769
Joey Arhar512e3742019-01-25 21:33:541770 if (/[\u0000-\u001f\u007f-\u009f!]|\'/.test(str)) {
Blink Reformat4c46d092018-04-07 15:32:371771 // Use ANSI-C quoting syntax.
1772 return '$\'' +
1773 str.replace(/\\/g, '\\\\')
1774 .replace(/\'/g, '\\\'')
1775 .replace(/\n/g, '\\n')
1776 .replace(/\r/g, '\\r')
Joey Arhar512e3742019-01-25 21:33:541777 .replace(/[\u0000-\u001f\u007f-\u009f!]/g, escapeCharacter) +
Blink Reformat4c46d092018-04-07 15:32:371778 '\'';
1779 } else {
1780 // Use single quote syntax.
1781 return '\'' + str + '\'';
1782 }
1783 }
1784
1785 // cURL command expected to run on the same platform that DevTools run
1786 // (it may be different from the inspected page platform).
1787 const escapeString = platform === 'win' ? escapeStringWin : escapeStringPosix;
1788
1789 command.push(escapeString(request.url()).replace(/[[{}\]]/g, '\\$&'));
1790
1791 let inferredMethod = 'GET';
1792 const data = [];
1793 const requestContentType = request.requestContentType();
1794 const formData = await request.requestFormData();
1795 if (requestContentType && requestContentType.startsWith('application/x-www-form-urlencoded') && formData) {
1796 data.push('--data');
1797 data.push(escapeString(formData));
1798 ignoredHeaders['content-length'] = true;
1799 inferredMethod = 'POST';
1800 } else if (formData) {
1801 data.push('--data-binary');
1802 data.push(escapeString(formData));
1803 ignoredHeaders['content-length'] = true;
1804 inferredMethod = 'POST';
1805 }
1806
1807 if (request.requestMethod !== inferredMethod) {
1808 command.push('-X');
1809 command.push(request.requestMethod);
1810 }
1811
1812 const requestHeaders = request.requestHeaders();
1813 for (let i = 0; i < requestHeaders.length; i++) {
1814 const header = requestHeaders[i];
1815 const name = header.name.replace(/^:/, ''); // Translate SPDY v3 headers to HTTP headers.
Tim van der Lippe1d6e57a2019-09-30 11:55:341816 if (name.toLowerCase() in ignoredHeaders) {
Blink Reformat4c46d092018-04-07 15:32:371817 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341818 }
Blink Reformat4c46d092018-04-07 15:32:371819 command.push('-H');
1820 command.push(escapeString(name + ': ' + header.value));
1821 }
1822 command = command.concat(data);
1823 command.push('--compressed');
1824
Tim van der Lippe1d6e57a2019-09-30 11:55:341825 if (request.securityState() === Protocol.Security.SecurityState.Insecure) {
Blink Reformat4c46d092018-04-07 15:32:371826 command.push('--insecure');
Tim van der Lippe1d6e57a2019-09-30 11:55:341827 }
Blink Reformat4c46d092018-04-07 15:32:371828 return command.join(' ');
1829 }
1830
1831 /**
Harley Libcf41f92018-09-10 18:01:131832 * @param {!Array<!SDK.NetworkRequest>} requests
1833 * @param {string} platform
1834 * @return {!Promise<string>}
1835 */
1836 async _generateAllCurlCommand(requests, platform) {
1837 const nonBlobRequests = this._filterOutBlobRequests(requests);
1838 const commands = await Promise.all(nonBlobRequests.map(request => this._generateCurlCommand(request, platform)));
Tim van der Lippe1d6e57a2019-09-30 11:55:341839 if (platform === 'win') {
Harley Libcf41f92018-09-10 18:01:131840 return commands.join(' &\r\n');
Tim van der Lippe1d6e57a2019-09-30 11:55:341841 } else {
Harley Libcf41f92018-09-10 18:01:131842 return commands.join(' ;\n');
Tim van der Lippe1d6e57a2019-09-30 11:55:341843 }
Harley Libcf41f92018-09-10 18:01:131844 }
1845
1846 /**
Blink Reformat4c46d092018-04-07 15:32:371847 * @param {!SDK.NetworkRequest} request
1848 * @return {!Promise<string>}
1849 */
1850 async _generatePowerShellCommand(request) {
1851 const command = ['Invoke-WebRequest'];
1852 const ignoredHeaders =
1853 new Set(['host', 'connection', 'proxy-connection', 'content-length', 'expect', 'range', 'content-type']);
1854
1855 /**
1856 * @param {string} str
1857 * @return {string}
1858 */
1859 function escapeString(str) {
1860 return '"' +
1861 str.replace(/[`\$"]/g, '`$&').replace(/[^\x20-\x7E]/g, char => '$([char]' + char.charCodeAt(0) + ')') + '"';
1862 }
1863
1864 command.push('-Uri');
1865 command.push(escapeString(request.url()));
1866
1867 if (request.requestMethod !== 'GET') {
1868 command.push('-Method');
1869 command.push(escapeString(request.requestMethod));
1870 }
1871
1872 const requestHeaders = request.requestHeaders();
1873 const headerNameValuePairs = [];
1874 for (const header of requestHeaders) {
1875 const name = header.name.replace(/^:/, ''); // Translate h2 headers to HTTP headers.
Tim van der Lippe1d6e57a2019-09-30 11:55:341876 if (ignoredHeaders.has(name.toLowerCase())) {
Blink Reformat4c46d092018-04-07 15:32:371877 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341878 }
Blink Reformat4c46d092018-04-07 15:32:371879 headerNameValuePairs.push(escapeString(name) + '=' + escapeString(header.value));
1880 }
1881 if (headerNameValuePairs.length) {
1882 command.push('-Headers');
1883 command.push('@{' + headerNameValuePairs.join('; ') + '}');
1884 }
1885
1886 const contentTypeHeader = requestHeaders.find(({name}) => name.toLowerCase() === 'content-type');
1887 if (contentTypeHeader) {
1888 command.push('-ContentType');
1889 command.push(escapeString(contentTypeHeader.value));
1890 }
1891
1892 const formData = await request.requestFormData();
1893 if (formData) {
1894 command.push('-Body');
1895 const body = escapeString(formData);
Tim van der Lippe1d6e57a2019-09-30 11:55:341896 if (/[^\x20-\x7E]/.test(formData)) {
Blink Reformat4c46d092018-04-07 15:32:371897 command.push('([System.Text.Encoding]::UTF8.GetBytes(' + body + '))');
Tim van der Lippe1d6e57a2019-09-30 11:55:341898 } else {
Blink Reformat4c46d092018-04-07 15:32:371899 command.push(body);
Tim van der Lippe1d6e57a2019-09-30 11:55:341900 }
Blink Reformat4c46d092018-04-07 15:32:371901 }
1902
1903 return command.join(' ');
1904 }
Harley Libcf41f92018-09-10 18:01:131905
1906 /**
1907 * @param {!Array<!SDK.NetworkRequest>} requests
1908 * @return {!Promise<string>}
1909 */
1910 async _generateAllPowerShellCommand(requests) {
1911 const nonBlobRequests = this._filterOutBlobRequests(requests);
1912 const commands = await Promise.all(nonBlobRequests.map(request => this._generatePowerShellCommand(request)));
1913 return commands.join(';\r\n');
1914 }
Joey Arhara86c14e2019-03-12 03:20:501915
1916 /**
1917 * @return {string}
1918 */
1919 static getDCLEventColor() {
Tim van der Lippe1d6e57a2019-09-30 11:55:341920 if (UI.themeSupport.themeName() === 'dark') {
Joey Arhara86c14e2019-03-12 03:20:501921 return '#03A9F4';
Tim van der Lippe1d6e57a2019-09-30 11:55:341922 }
Joey Arhara86c14e2019-03-12 03:20:501923 return '#0867CB';
1924 }
1925
1926 /**
1927 * @return {string}
1928 */
1929 static getLoadEventColor() {
1930 return UI.themeSupport.patchColorText('#B31412', UI.ThemeSupport.ColorUsage.Foreground);
1931 }
Blink Reformat4c46d092018-04-07 15:32:371932};
1933
1934Network.NetworkLogView._isFilteredOutSymbol = Symbol('isFilteredOut');
1935Network.NetworkLogView._networkNodeSymbol = Symbol('NetworkNode');
1936
1937Network.NetworkLogView.HTTPSchemas = {
1938 'http': true,
1939 'https': true,
1940 'ws': true,
1941 'wss': true
1942};
1943
1944/** @enum {symbol} */
1945Network.NetworkLogView.Events = {
1946 RequestSelected: Symbol('RequestSelected')
1947};
1948
1949/** @enum {string} */
1950Network.NetworkLogView.FilterType = {
1951 Domain: 'domain',
1952 HasResponseHeader: 'has-response-header',
1953 Is: 'is',
1954 LargerThan: 'larger-than',
1955 Method: 'method',
1956 MimeType: 'mime-type',
1957 MixedContent: 'mixed-content',
1958 Priority: 'priority',
1959 Scheme: 'scheme',
1960 SetCookieDomain: 'set-cookie-domain',
1961 SetCookieName: 'set-cookie-name',
1962 SetCookieValue: 'set-cookie-value',
1963 StatusCode: 'status-code'
1964};
1965
1966/** @enum {string} */
1967Network.NetworkLogView.MixedContentFilterValues = {
1968 All: 'all',
1969 Displayed: 'displayed',
1970 Blocked: 'blocked',
1971 BlockOverridden: 'block-overridden'
1972};
1973
1974/** @enum {string} */
1975Network.NetworkLogView.IsFilterType = {
1976 Running: 'running',
Joey Arhard183e7e2019-02-28 03:37:051977 FromCache: 'from-cache',
1978 ServiceWorkerIntercepted: 'service-worker-intercepted',
1979 ServiceWorkerInitiated: 'service-worker-initiated'
Blink Reformat4c46d092018-04-07 15:32:371980};
1981
1982/** @type {!Array<string>} */
1983Network.NetworkLogView._searchKeys =
1984 Object.keys(Network.NetworkLogView.FilterType).map(key => Network.NetworkLogView.FilterType[key]);
1985
1986/** @typedef {function(!SDK.NetworkRequest): boolean} */
1987Network.NetworkLogView.Filter;
1988
1989/**
1990 * @interface
1991 */
1992Network.GroupLookupInterface = function() {};
1993
1994Network.GroupLookupInterface.prototype = {
1995 /**
1996 * @param {!SDK.NetworkRequest} request
1997 * @return {?Network.NetworkGroupNode}
1998 */
1999 groupNodeForRequest: function(request) {},
2000
2001 reset: function() {}
2002};