blob: 8aa0b86abcd41aac66bd5c569dff640099093cf8 [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) {
430 InspectorFrontendHost.copyText(request.requestHeadersText());
431 }
432
433 /**
434 * @param {!SDK.NetworkRequest} request
435 */
436 static _copyResponseHeaders(request) {
437 InspectorFrontendHost.copyText(request.responseHeadersText);
438 }
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 }
Ingvar Stepanyan1c771842018-10-10 14:35:08451 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(
1216 UI.copyLinkAddressLabel(), InspectorFrontendHost.copyText.bind(InspectorFrontendHost, request.contentURL()));
1217 if (request.requestHeadersText()) {
1218 copyMenu.defaultSection().appendItem(
1219 Common.UIString('Copy request headers'), Network.NetworkLogView._copyRequestHeaders.bind(null, request));
1220 }
1221
1222 if (request.responseHeadersText) {
1223 copyMenu.defaultSection().appendItem(
1224 Common.UIString('Copy response headers'), Network.NetworkLogView._copyResponseHeaders.bind(null, request));
1225 }
1226
1227 if (request.finished) {
1228 copyMenu.defaultSection().appendItem(
1229 Common.UIString('Copy response'), Network.NetworkLogView._copyResponse.bind(null, request));
1230 }
1231
Harley Libcf41f92018-09-10 18:01:131232 const disableIfBlob = request.isBlobRequest();
Blink Reformat4c46d092018-04-07 15:32:371233 if (Host.isWin()) {
1234 footerSection.appendItem(
Harley Libcf41f92018-09-10 18:01:131235 Common.UIString('Copy as PowerShell'), this._copyPowerShellCommand.bind(this, request), disableIfBlob);
Blink Reformat4c46d092018-04-07 15:32:371236 footerSection.appendItem(
Harley Libcf41f92018-09-10 18:01:131237 Common.UIString('Copy as fetch'), this._copyFetchCall.bind(this, request), disableIfBlob);
Blink Reformat4c46d092018-04-07 15:32:371238 footerSection.appendItem(
Harley Libcf41f92018-09-10 18:01:131239 Common.UIString('Copy as cURL (cmd)'), this._copyCurlCommand.bind(this, request, 'win'), disableIfBlob);
1240 footerSection.appendItem(
1241 Common.UIString('Copy as cURL (bash)'), this._copyCurlCommand.bind(this, request, 'unix'), disableIfBlob);
Blink Reformat4c46d092018-04-07 15:32:371242 footerSection.appendItem(Common.UIString('Copy all as PowerShell'), this._copyAllPowerShellCommand.bind(this));
1243 footerSection.appendItem(Common.UIString('Copy all as fetch'), this._copyAllFetchCall.bind(this));
1244 footerSection.appendItem(Common.UIString('Copy all as cURL (cmd)'), this._copyAllCurlCommand.bind(this, 'win'));
1245 footerSection.appendItem(
1246 Common.UIString('Copy all as cURL (bash)'), this._copyAllCurlCommand.bind(this, 'unix'));
1247 } else {
Harley Libcf41f92018-09-10 18:01:131248 footerSection.appendItem(
1249 Common.UIString('Copy as fetch'), this._copyFetchCall.bind(this, request), disableIfBlob);
1250 footerSection.appendItem(
1251 Common.UIString('Copy as cURL'), this._copyCurlCommand.bind(this, request, 'unix'), disableIfBlob);
Blink Reformat4c46d092018-04-07 15:32:371252 footerSection.appendItem(Common.UIString('Copy all as fetch'), this._copyAllFetchCall.bind(this));
1253 footerSection.appendItem(Common.UIString('Copy all as cURL'), this._copyAllCurlCommand.bind(this, 'unix'));
1254 }
1255 } else {
1256 copyMenu = contextMenu.clipboardSection().appendSubMenuItem(Common.UIString('Copy'));
1257 }
1258 footerSection.appendItem(Common.UIString('Copy all as HAR'), this._copyAll.bind(this));
1259
Joey Arhar0e1093c2019-05-21 00:34:221260 contextMenu.saveSection().appendItem(ls`Save all as HAR with content`, this.exportAll.bind(this));
Blink Reformat4c46d092018-04-07 15:32:371261
1262 contextMenu.editSection().appendItem(Common.UIString('Clear browser cache'), this._clearBrowserCache.bind(this));
1263 contextMenu.editSection().appendItem(
1264 Common.UIString('Clear browser cookies'), this._clearBrowserCookies.bind(this));
1265
1266 if (request) {
1267 const maxBlockedURLLength = 20;
1268 const manager = SDK.multitargetNetworkManager;
1269 let patterns = manager.blockedPatterns();
1270
Tim van der Lippeffa78622019-09-16 12:07:121271 /**
1272 * @param {string} url
1273 */
1274 function addBlockedURL(url) {
1275 patterns.push({enabled: true, url: url});
1276 manager.setBlockedPatterns(patterns);
1277 manager.setBlockingEnabled(true);
1278 UI.viewManager.showView('network.blocked-urls');
1279 }
1280
1281 /**
1282 * @param {string} url
1283 */
1284 function removeBlockedURL(url) {
1285 patterns = patterns.filter(pattern => pattern.url !== url);
1286 manager.setBlockedPatterns(patterns);
1287 UI.viewManager.showView('network.blocked-urls');
1288 }
1289
Blink Reformat4c46d092018-04-07 15:32:371290 const urlWithoutScheme = request.parsedURL.urlWithoutScheme();
1291 if (urlWithoutScheme && !patterns.find(pattern => pattern.url === urlWithoutScheme)) {
1292 contextMenu.debugSection().appendItem(
1293 Common.UIString('Block request URL'), addBlockedURL.bind(null, urlWithoutScheme));
1294 } else if (urlWithoutScheme) {
1295 const croppedURL = urlWithoutScheme.trimMiddle(maxBlockedURLLength);
1296 contextMenu.debugSection().appendItem(
1297 Common.UIString('Unblock %s', croppedURL), removeBlockedURL.bind(null, urlWithoutScheme));
1298 }
1299
1300 const domain = request.parsedURL.domain();
1301 if (domain && !patterns.find(pattern => pattern.url === domain)) {
1302 contextMenu.debugSection().appendItem(
1303 Common.UIString('Block request domain'), addBlockedURL.bind(null, domain));
1304 } else if (domain) {
1305 const croppedDomain = domain.trimMiddle(maxBlockedURLLength);
1306 contextMenu.debugSection().appendItem(
1307 Common.UIString('Unblock %s', croppedDomain), removeBlockedURL.bind(null, domain));
1308 }
1309
1310 if (SDK.NetworkManager.canReplayRequest(request)) {
1311 contextMenu.debugSection().appendItem(
1312 Common.UIString('Replay XHR'), SDK.NetworkManager.replayRequest.bind(null, request));
1313 }
Blink Reformat4c46d092018-04-07 15:32:371314 }
1315 }
1316
1317 _harRequests() {
Joey Arharb3d6de42019-04-23 21:26:171318 return SDK.networkLog.requests().filter(Network.NetworkLogView.HTTPRequestsFilter).filter(request => {
1319 return request.finished ||
1320 (request.resourceType() === Common.resourceTypes.WebSocket && request.responseReceivedTime);
1321 });
Blink Reformat4c46d092018-04-07 15:32:371322 }
1323
1324 async _copyAll() {
Pavel Feldman18d13562018-07-31 03:31:181325 const harArchive = {log: await SDK.HARLog.build(this._harRequests())};
Blink Reformat4c46d092018-04-07 15:32:371326 InspectorFrontendHost.copyText(JSON.stringify(harArchive, null, 2));
1327 }
1328
1329 /**
1330 * @param {!SDK.NetworkRequest} request
1331 * @param {string} platform
1332 */
1333 async _copyCurlCommand(request, platform) {
1334 const command = await this._generateCurlCommand(request, platform);
1335 InspectorFrontendHost.copyText(command);
1336 }
1337
1338 /**
1339 * @param {string} platform
1340 */
1341 async _copyAllCurlCommand(platform) {
Harley Libcf41f92018-09-10 18:01:131342 const commands = await this._generateAllCurlCommand(SDK.networkLog.requests(), platform);
1343 InspectorFrontendHost.copyText(commands);
Blink Reformat4c46d092018-04-07 15:32:371344 }
1345
1346 /**
1347 * @param {!SDK.NetworkRequest} request
1348 * @param {string} platform
1349 */
1350 async _copyFetchCall(request, platform) {
1351 const command = await this._generateFetchCall(request);
1352 InspectorFrontendHost.copyText(command);
1353 }
1354
1355 async _copyAllFetchCall() {
Harley Libcf41f92018-09-10 18:01:131356 const commands = await this._generateAllFetchCall(SDK.networkLog.requests());
1357 InspectorFrontendHost.copyText(commands);
Blink Reformat4c46d092018-04-07 15:32:371358 }
1359
1360 /**
1361 * @param {!SDK.NetworkRequest} request
1362 */
1363 async _copyPowerShellCommand(request) {
1364 const command = await this._generatePowerShellCommand(request);
1365 InspectorFrontendHost.copyText(command);
1366 }
1367
1368 async _copyAllPowerShellCommand() {
Harley Li5a470e92019-09-26 21:38:351369 const commands = await this._generateAllPowerShellCommand(SDK.networkLog.requests());
Harley Libcf41f92018-09-10 18:01:131370 InspectorFrontendHost.copyText(commands);
Blink Reformat4c46d092018-04-07 15:32:371371 }
1372
Joey Arhar0e1093c2019-05-21 00:34:221373 async exportAll() {
Blink Reformat4c46d092018-04-07 15:32:371374 const url = SDK.targetManager.mainTarget().inspectedURL();
1375 const parsedURL = url.asParsedURL();
1376 const filename = parsedURL ? parsedURL.host : 'network-log';
1377 const stream = new Bindings.FileOutputStream();
1378
Tim van der Lippe1d6e57a2019-09-30 11:55:341379 if (!await stream.open(filename + '.har')) {
Blink Reformat4c46d092018-04-07 15:32:371380 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:341381 }
Blink Reformat4c46d092018-04-07 15:32:371382
1383 const progressIndicator = new UI.ProgressIndicator();
1384 this._progressBarContainer.appendChild(progressIndicator.element);
1385 await Network.HARWriter.write(stream, this._harRequests(), progressIndicator);
1386 progressIndicator.done();
1387 stream.close();
1388 }
1389
1390 _clearBrowserCache() {
Tim van der Lippe1d6e57a2019-09-30 11:55:341391 if (confirm(Common.UIString('Are you sure you want to clear browser cache?'))) {
Blink Reformat4c46d092018-04-07 15:32:371392 SDK.multitargetNetworkManager.clearBrowserCache();
Tim van der Lippe1d6e57a2019-09-30 11:55:341393 }
Blink Reformat4c46d092018-04-07 15:32:371394 }
1395
1396 _clearBrowserCookies() {
Tim van der Lippe1d6e57a2019-09-30 11:55:341397 if (confirm(Common.UIString('Are you sure you want to clear browser cookies?'))) {
Blink Reformat4c46d092018-04-07 15:32:371398 SDK.multitargetNetworkManager.clearBrowserCookies();
Tim van der Lippe1d6e57a2019-09-30 11:55:341399 }
Blink Reformat4c46d092018-04-07 15:32:371400 }
1401
1402 _removeAllHighlights() {
1403 this.removeAllNodeHighlights();
Tim van der Lippe1d6e57a2019-09-30 11:55:341404 for (let i = 0; i < this._highlightedSubstringChanges.length; ++i) {
Blink Reformat4c46d092018-04-07 15:32:371405 UI.revertDomChanges(this._highlightedSubstringChanges[i]);
Tim van der Lippe1d6e57a2019-09-30 11:55:341406 }
Blink Reformat4c46d092018-04-07 15:32:371407 this._highlightedSubstringChanges = [];
1408 }
1409
1410 /**
1411 * @param {!Network.NetworkRequestNode} node
1412 * @return {boolean}
1413 */
1414 _applyFilter(node) {
1415 const request = node.request();
Tim van der Lippe1d6e57a2019-09-30 11:55:341416 if (this._timeFilter && !this._timeFilter(request)) {
Blink Reformat4c46d092018-04-07 15:32:371417 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:341418 }
Blink Reformat4c46d092018-04-07 15:32:371419 const categoryName = request.resourceType().category().title;
Tim van der Lippe1d6e57a2019-09-30 11:55:341420 if (!this._resourceCategoryFilterUI.accept(categoryName)) {
Blink Reformat4c46d092018-04-07 15:32:371421 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:341422 }
1423 if (this._dataURLFilterUI.checked() && (request.parsedURL.isDataURL() || request.parsedURL.isBlobURL())) {
Blink Reformat4c46d092018-04-07 15:32:371424 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:341425 }
1426 if (request.statusText === 'Service Worker Fallback Required') {
Blink Reformat4c46d092018-04-07 15:32:371427 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:341428 }
Blink Reformat4c46d092018-04-07 15:32:371429 for (let i = 0; i < this._filters.length; ++i) {
Tim van der Lippe1d6e57a2019-09-30 11:55:341430 if (!this._filters[i](request)) {
Blink Reformat4c46d092018-04-07 15:32:371431 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:341432 }
Blink Reformat4c46d092018-04-07 15:32:371433 }
1434 return true;
1435 }
1436
1437 /**
1438 * @param {string} query
1439 */
1440 _parseFilterQuery(query) {
1441 const descriptors = this._filterParser.parse(query);
1442 this._filters = descriptors.map(descriptor => {
1443 const key = descriptor.key;
1444 const text = descriptor.text || '';
1445 const regex = descriptor.regex;
1446 let filter;
1447 if (key) {
1448 const defaultText = (key + ':' + text).escapeForRegExp();
1449 filter = this._createSpecialFilter(/** @type {!Network.NetworkLogView.FilterType} */ (key), text) ||
1450 Network.NetworkLogView._requestPathFilter.bind(null, new RegExp(defaultText, 'i'));
1451 } else if (descriptor.regex) {
1452 filter = Network.NetworkLogView._requestPathFilter.bind(null, /** @type {!RegExp} */ (regex));
1453 } else {
1454 filter = Network.NetworkLogView._requestPathFilter.bind(null, new RegExp(text.escapeForRegExp(), 'i'));
1455 }
1456 return descriptor.negative ? Network.NetworkLogView._negativeFilter.bind(null, filter) : filter;
1457 });
1458 }
1459
1460 /**
1461 * @param {!Network.NetworkLogView.FilterType} type
1462 * @param {string} value
1463 * @return {?Network.NetworkLogView.Filter}
1464 */
1465 _createSpecialFilter(type, value) {
1466 switch (type) {
1467 case Network.NetworkLogView.FilterType.Domain:
1468 return Network.NetworkLogView._createRequestDomainFilter(value);
1469
1470 case Network.NetworkLogView.FilterType.HasResponseHeader:
1471 return Network.NetworkLogView._requestResponseHeaderFilter.bind(null, value);
1472
1473 case Network.NetworkLogView.FilterType.Is:
Tim van der Lippe1d6e57a2019-09-30 11:55:341474 if (value.toLowerCase() === Network.NetworkLogView.IsFilterType.Running) {
Blink Reformat4c46d092018-04-07 15:32:371475 return Network.NetworkLogView._runningRequestFilter;
Tim van der Lippe1d6e57a2019-09-30 11:55:341476 }
1477 if (value.toLowerCase() === Network.NetworkLogView.IsFilterType.FromCache) {
Blink Reformat4c46d092018-04-07 15:32:371478 return Network.NetworkLogView._fromCacheRequestFilter;
Tim van der Lippe1d6e57a2019-09-30 11:55:341479 }
1480 if (value.toLowerCase() === Network.NetworkLogView.IsFilterType.ServiceWorkerIntercepted) {
Joey Arhard183e7e2019-02-28 03:37:051481 return Network.NetworkLogView._interceptedByServiceWorkerFilter;
Tim van der Lippe1d6e57a2019-09-30 11:55:341482 }
1483 if (value.toLowerCase() === Network.NetworkLogView.IsFilterType.ServiceWorkerInitiated) {
Joey Arhard183e7e2019-02-28 03:37:051484 return Network.NetworkLogView._initiatedByServiceWorkerFilter;
Tim van der Lippe1d6e57a2019-09-30 11:55:341485 }
Blink Reformat4c46d092018-04-07 15:32:371486 break;
1487
1488 case Network.NetworkLogView.FilterType.LargerThan:
1489 return this._createSizeFilter(value.toLowerCase());
1490
1491 case Network.NetworkLogView.FilterType.Method:
1492 return Network.NetworkLogView._requestMethodFilter.bind(null, value);
1493
1494 case Network.NetworkLogView.FilterType.MimeType:
1495 return Network.NetworkLogView._requestMimeTypeFilter.bind(null, value);
1496
1497 case Network.NetworkLogView.FilterType.MixedContent:
1498 return Network.NetworkLogView._requestMixedContentFilter.bind(
1499 null, /** @type {!Network.NetworkLogView.MixedContentFilterValues} */ (value));
1500
1501 case Network.NetworkLogView.FilterType.Scheme:
1502 return Network.NetworkLogView._requestSchemeFilter.bind(null, value);
1503
1504 case Network.NetworkLogView.FilterType.SetCookieDomain:
1505 return Network.NetworkLogView._requestSetCookieDomainFilter.bind(null, value);
1506
1507 case Network.NetworkLogView.FilterType.SetCookieName:
1508 return Network.NetworkLogView._requestSetCookieNameFilter.bind(null, value);
1509
1510 case Network.NetworkLogView.FilterType.SetCookieValue:
1511 return Network.NetworkLogView._requestSetCookieValueFilter.bind(null, value);
1512
1513 case Network.NetworkLogView.FilterType.Priority:
1514 return Network.NetworkLogView._requestPriorityFilter.bind(null, PerfUI.uiLabelToNetworkPriority(value));
1515
1516 case Network.NetworkLogView.FilterType.StatusCode:
1517 return Network.NetworkLogView._statusCodeFilter.bind(null, value);
1518 }
1519 return null;
1520 }
1521
1522 /**
1523 * @param {string} value
1524 * @return {?Network.NetworkLogView.Filter}
1525 */
1526 _createSizeFilter(value) {
1527 let multiplier = 1;
1528 if (value.endsWith('k')) {
1529 multiplier = 1024;
1530 value = value.substring(0, value.length - 1);
1531 } else if (value.endsWith('m')) {
1532 multiplier = 1024 * 1024;
1533 value = value.substring(0, value.length - 1);
1534 }
1535 const quantity = Number(value);
Tim van der Lippe1d6e57a2019-09-30 11:55:341536 if (isNaN(quantity)) {
Blink Reformat4c46d092018-04-07 15:32:371537 return null;
Tim van der Lippe1d6e57a2019-09-30 11:55:341538 }
Blink Reformat4c46d092018-04-07 15:32:371539 return Network.NetworkLogView._requestSizeLargerThanFilter.bind(null, quantity * multiplier);
1540 }
1541
1542 _filterRequests() {
1543 this._removeAllHighlights();
1544 this._invalidateAllItems();
1545 }
1546
1547 /**
1548 * @param {!SDK.NetworkRequest} request
1549 * @return {?Network.NetworkRequestNode}
1550 */
1551 _reveal(request) {
1552 this.removeAllNodeHighlights();
1553 const node = request[Network.NetworkLogView._networkNodeSymbol];
Tim van der Lippe1d6e57a2019-09-30 11:55:341554 if (!node || !node.dataGrid) {
Blink Reformat4c46d092018-04-07 15:32:371555 return null;
Tim van der Lippe1d6e57a2019-09-30 11:55:341556 }
Blink Reformat4c46d092018-04-07 15:32:371557 node.reveal();
1558 return node;
1559 }
1560
1561 /**
1562 * @param {!SDK.NetworkRequest} request
1563 */
1564 revealAndHighlightRequest(request) {
1565 const node = this._reveal(request);
Tim van der Lippe1d6e57a2019-09-30 11:55:341566 if (node) {
Blink Reformat4c46d092018-04-07 15:32:371567 this._highlightNode(node);
Tim van der Lippe1d6e57a2019-09-30 11:55:341568 }
Blink Reformat4c46d092018-04-07 15:32:371569 }
1570
1571 /**
1572 * @param {!SDK.NetworkRequest} request
1573 */
1574 selectRequest(request) {
Eugene Ostroukhovb600f662018-05-09 00:18:141575 this.setTextFilterValue('');
Blink Reformat4c46d092018-04-07 15:32:371576 const node = this._reveal(request);
Tim van der Lippe1d6e57a2019-09-30 11:55:341577 if (node) {
Blink Reformat4c46d092018-04-07 15:32:371578 node.select();
Tim van der Lippe1d6e57a2019-09-30 11:55:341579 }
Blink Reformat4c46d092018-04-07 15:32:371580 }
1581
1582 removeAllNodeHighlights() {
1583 if (this._highlightedNode) {
1584 this._highlightedNode.element().classList.remove('highlighted-row');
1585 this._highlightedNode = null;
1586 }
1587 }
1588
1589 /**
1590 * @param {!Network.NetworkRequestNode} node
1591 */
1592 _highlightNode(node) {
1593 UI.runCSSAnimationOnce(node.element(), 'highlighted-row');
1594 this._highlightedNode = node;
1595 }
1596
1597 /**
Harley Libcf41f92018-09-10 18:01:131598 * @param {!Array<!SDK.NetworkRequest>} requests
1599 * @return {!Array<!SDK.NetworkRequest>}
1600 */
1601 _filterOutBlobRequests(requests) {
1602 return requests.filter(request => !request.isBlobRequest());
1603 }
1604
1605 /**
Blink Reformat4c46d092018-04-07 15:32:371606 * @param {!SDK.NetworkRequest} request
1607 * @return {!Promise<string>}
1608 */
1609 async _generateFetchCall(request) {
1610 const ignoredHeaders = {
1611 // Internal headers
1612 'method': 1,
1613 'path': 1,
1614 'scheme': 1,
1615 'version': 1,
1616
1617 // Unsafe headers
1618 // Keep this list synchronized with src/net/http/http_util.cc
1619 'accept-charset': 1,
1620 'accept-encoding': 1,
1621 'access-control-request-headers': 1,
1622 'access-control-request-method': 1,
1623 'connection': 1,
1624 'content-length': 1,
1625 'cookie': 1,
1626 'cookie2': 1,
1627 'date': 1,
1628 'dnt': 1,
1629 'expect': 1,
1630 'host': 1,
1631 'keep-alive': 1,
1632 'origin': 1,
1633 'referer': 1,
1634 'te': 1,
1635 'trailer': 1,
1636 'transfer-encoding': 1,
1637 'upgrade': 1,
1638 'via': 1,
1639 // TODO(phistuck) - remove this once crbug.com/571722 is fixed.
1640 'user-agent': 1
1641 };
1642
1643 const credentialHeaders = {'cookie': 1, 'authorization': 1};
1644
1645 const url = JSON.stringify(request.url());
1646
1647 const requestHeaders = request.requestHeaders();
1648 const headerData = requestHeaders.reduce((result, header) => {
1649 const name = header.name;
1650
Tim van der Lippe1d6e57a2019-09-30 11:55:341651 if (!ignoredHeaders[name.toLowerCase()] && !name.includes(':')) {
Blink Reformat4c46d092018-04-07 15:32:371652 result.append(name, header.value);
Tim van der Lippe1d6e57a2019-09-30 11:55:341653 }
Blink Reformat4c46d092018-04-07 15:32:371654
1655 return result;
1656 }, new Headers());
1657
1658 const headers = {};
Tim van der Lippe1d6e57a2019-09-30 11:55:341659 for (const headerArray of headerData) {
PhistucK6ed0a3e2018-08-04 06:28:411660 headers[headerArray[0]] = headerArray[1];
Tim van der Lippe1d6e57a2019-09-30 11:55:341661 }
Blink Reformat4c46d092018-04-07 15:32:371662
1663 const credentials =
1664 request.requestCookies || requestHeaders.some(({name}) => credentialHeaders[name.toLowerCase()]) ? 'include' :
1665 'omit';
1666
1667 const referrerHeader = requestHeaders.find(({name}) => name.toLowerCase() === 'referer');
1668
1669 const referrer = referrerHeader ? referrerHeader.value : void 0;
1670
1671 const referrerPolicy = request.referrerPolicy() || void 0;
1672
1673 const requestBody = await request.requestFormData();
1674
1675 const fetchOptions = {
1676 credentials,
PhistucK6ed0a3e2018-08-04 06:28:411677 headers: Object.keys(headers).length ? headers : void 0,
Blink Reformat4c46d092018-04-07 15:32:371678 referrer,
1679 referrerPolicy,
1680 body: requestBody,
1681 method: request.requestMethod,
1682 mode: 'cors'
1683 };
1684
1685 const options = JSON.stringify(fetchOptions);
1686 return `fetch(${url}, ${options});`;
1687 }
1688
1689 /**
Harley Libcf41f92018-09-10 18:01:131690 * @param {!Array<!SDK.NetworkRequest>} requests
1691 * @return {!Promise<string>}
1692 */
1693 async _generateAllFetchCall(requests) {
1694 const nonBlobRequests = this._filterOutBlobRequests(requests);
1695 const commands = await Promise.all(nonBlobRequests.map(request => this._generateFetchCall(request)));
1696 return commands.join(' ;\n');
1697 }
1698
1699 /**
Blink Reformat4c46d092018-04-07 15:32:371700 * @param {!SDK.NetworkRequest} request
1701 * @param {string} platform
1702 * @return {!Promise<string>}
1703 */
1704 async _generateCurlCommand(request, platform) {
1705 let command = ['curl'];
1706 // These headers are derived from URL (except "version") and would be added by cURL anyway.
1707 const ignoredHeaders = {'host': 1, 'method': 1, 'path': 1, 'scheme': 1, 'version': 1};
1708
1709 function escapeStringWin(str) {
1710 /* If there are no new line characters do not escape the " characters
1711 since it only uglifies the command.
1712
1713 Because cmd.exe parser and MS Crt arguments parsers use some of the
1714 same escape characters, they can interact with each other in
1715 horrible ways, the order of operations is critical.
1716
1717 Replace \ with \\ first because it is an escape character for certain
1718 conditions in both parsers.
1719
1720 Replace all " with \" to ensure the first parser does not remove it.
1721
1722 Then escape all characters we are not sure about with ^ to ensure it
1723 gets to MS Crt parser safely.
1724
1725 The % character is special because MS Crt parser will try and look for
1726 ENV variables and fill them in it's place. We cannot escape them with %
1727 and cannot escape them with ^ (because it's cmd.exe's escape not MS Crt
1728 parser); So we can get cmd.exe parser to escape the character after it,
1729 if it is followed by a valid beginning character of an ENV variable.
1730 This ensures we do not try and double escape another ^ if it was placed
1731 by the previous replace.
1732
1733 Lastly we replace new lines with ^ and TWO new lines because the first
1734 new line is there to enact the escape command the second is the character
1735 to escape (in this case new line).
1736 */
1737 const encapsChars = /[\r\n]/.test(str) ? '^"' : '"';
1738 return encapsChars +
1739 str.replace(/\\/g, '\\\\')
1740 .replace(/"/g, '\\"')
1741 .replace(/[^a-zA-Z0-9\s_\-:=+~'\/.',?;()*`]/g, '^$&')
1742 .replace(/%(?=[a-zA-Z0-9_])/g, '%^')
1743 .replace(/\r\n|[\n\r]/g, '^\n\n') +
1744 encapsChars;
1745 }
1746
1747 /**
1748 * @param {string} str
1749 * @return {string}
1750 */
1751 function escapeStringPosix(str) {
1752 /**
1753 * @param {string} x
1754 * @return {string}
1755 */
1756 function escapeCharacter(x) {
Erik Luoaa676752018-08-21 05:52:221757 const code = x.charCodeAt(0);
Joey Arhar2d21f712019-05-20 21:07:121758 let hexString = code.toString(16);
1759 // Zero pad to four digits to comply with ANSI-C Quoting:
1760 // http://www.gnu.org/software/bash/manual/html_node/ANSI_002dC-Quoting.html
Tim van der Lippe1d6e57a2019-09-30 11:55:341761 while (hexString.length < 4) {
Joey Arhar2d21f712019-05-20 21:07:121762 hexString = '0' + hexString;
Tim van der Lippe1d6e57a2019-09-30 11:55:341763 }
Joey Arhar2d21f712019-05-20 21:07:121764
1765 return '\\u' + hexString;
Blink Reformat4c46d092018-04-07 15:32:371766 }
1767
Joey Arhar512e3742019-01-25 21:33:541768 if (/[\u0000-\u001f\u007f-\u009f!]|\'/.test(str)) {
Blink Reformat4c46d092018-04-07 15:32:371769 // Use ANSI-C quoting syntax.
1770 return '$\'' +
1771 str.replace(/\\/g, '\\\\')
1772 .replace(/\'/g, '\\\'')
1773 .replace(/\n/g, '\\n')
1774 .replace(/\r/g, '\\r')
Joey Arhar512e3742019-01-25 21:33:541775 .replace(/[\u0000-\u001f\u007f-\u009f!]/g, escapeCharacter) +
Blink Reformat4c46d092018-04-07 15:32:371776 '\'';
1777 } else {
1778 // Use single quote syntax.
1779 return '\'' + str + '\'';
1780 }
1781 }
1782
1783 // cURL command expected to run on the same platform that DevTools run
1784 // (it may be different from the inspected page platform).
1785 const escapeString = platform === 'win' ? escapeStringWin : escapeStringPosix;
1786
1787 command.push(escapeString(request.url()).replace(/[[{}\]]/g, '\\$&'));
1788
1789 let inferredMethod = 'GET';
1790 const data = [];
1791 const requestContentType = request.requestContentType();
1792 const formData = await request.requestFormData();
1793 if (requestContentType && requestContentType.startsWith('application/x-www-form-urlencoded') && formData) {
1794 data.push('--data');
1795 data.push(escapeString(formData));
1796 ignoredHeaders['content-length'] = true;
1797 inferredMethod = 'POST';
1798 } else if (formData) {
1799 data.push('--data-binary');
1800 data.push(escapeString(formData));
1801 ignoredHeaders['content-length'] = true;
1802 inferredMethod = 'POST';
1803 }
1804
1805 if (request.requestMethod !== inferredMethod) {
1806 command.push('-X');
1807 command.push(request.requestMethod);
1808 }
1809
1810 const requestHeaders = request.requestHeaders();
1811 for (let i = 0; i < requestHeaders.length; i++) {
1812 const header = requestHeaders[i];
1813 const name = header.name.replace(/^:/, ''); // Translate SPDY v3 headers to HTTP headers.
Tim van der Lippe1d6e57a2019-09-30 11:55:341814 if (name.toLowerCase() in ignoredHeaders) {
Blink Reformat4c46d092018-04-07 15:32:371815 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341816 }
Blink Reformat4c46d092018-04-07 15:32:371817 command.push('-H');
1818 command.push(escapeString(name + ': ' + header.value));
1819 }
1820 command = command.concat(data);
1821 command.push('--compressed');
1822
Tim van der Lippe1d6e57a2019-09-30 11:55:341823 if (request.securityState() === Protocol.Security.SecurityState.Insecure) {
Blink Reformat4c46d092018-04-07 15:32:371824 command.push('--insecure');
Tim van der Lippe1d6e57a2019-09-30 11:55:341825 }
Blink Reformat4c46d092018-04-07 15:32:371826 return command.join(' ');
1827 }
1828
1829 /**
Harley Libcf41f92018-09-10 18:01:131830 * @param {!Array<!SDK.NetworkRequest>} requests
1831 * @param {string} platform
1832 * @return {!Promise<string>}
1833 */
1834 async _generateAllCurlCommand(requests, platform) {
1835 const nonBlobRequests = this._filterOutBlobRequests(requests);
1836 const commands = await Promise.all(nonBlobRequests.map(request => this._generateCurlCommand(request, platform)));
Tim van der Lippe1d6e57a2019-09-30 11:55:341837 if (platform === 'win') {
Harley Libcf41f92018-09-10 18:01:131838 return commands.join(' &\r\n');
Tim van der Lippe1d6e57a2019-09-30 11:55:341839 } else {
Harley Libcf41f92018-09-10 18:01:131840 return commands.join(' ;\n');
Tim van der Lippe1d6e57a2019-09-30 11:55:341841 }
Harley Libcf41f92018-09-10 18:01:131842 }
1843
1844 /**
Blink Reformat4c46d092018-04-07 15:32:371845 * @param {!SDK.NetworkRequest} request
1846 * @return {!Promise<string>}
1847 */
1848 async _generatePowerShellCommand(request) {
1849 const command = ['Invoke-WebRequest'];
1850 const ignoredHeaders =
1851 new Set(['host', 'connection', 'proxy-connection', 'content-length', 'expect', 'range', 'content-type']);
1852
1853 /**
1854 * @param {string} str
1855 * @return {string}
1856 */
1857 function escapeString(str) {
1858 return '"' +
1859 str.replace(/[`\$"]/g, '`$&').replace(/[^\x20-\x7E]/g, char => '$([char]' + char.charCodeAt(0) + ')') + '"';
1860 }
1861
1862 command.push('-Uri');
1863 command.push(escapeString(request.url()));
1864
1865 if (request.requestMethod !== 'GET') {
1866 command.push('-Method');
1867 command.push(escapeString(request.requestMethod));
1868 }
1869
1870 const requestHeaders = request.requestHeaders();
1871 const headerNameValuePairs = [];
1872 for (const header of requestHeaders) {
1873 const name = header.name.replace(/^:/, ''); // Translate h2 headers to HTTP headers.
Tim van der Lippe1d6e57a2019-09-30 11:55:341874 if (ignoredHeaders.has(name.toLowerCase())) {
Blink Reformat4c46d092018-04-07 15:32:371875 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341876 }
Blink Reformat4c46d092018-04-07 15:32:371877 headerNameValuePairs.push(escapeString(name) + '=' + escapeString(header.value));
1878 }
1879 if (headerNameValuePairs.length) {
1880 command.push('-Headers');
1881 command.push('@{' + headerNameValuePairs.join('; ') + '}');
1882 }
1883
1884 const contentTypeHeader = requestHeaders.find(({name}) => name.toLowerCase() === 'content-type');
1885 if (contentTypeHeader) {
1886 command.push('-ContentType');
1887 command.push(escapeString(contentTypeHeader.value));
1888 }
1889
1890 const formData = await request.requestFormData();
1891 if (formData) {
1892 command.push('-Body');
1893 const body = escapeString(formData);
Tim van der Lippe1d6e57a2019-09-30 11:55:341894 if (/[^\x20-\x7E]/.test(formData)) {
Blink Reformat4c46d092018-04-07 15:32:371895 command.push('([System.Text.Encoding]::UTF8.GetBytes(' + body + '))');
Tim van der Lippe1d6e57a2019-09-30 11:55:341896 } else {
Blink Reformat4c46d092018-04-07 15:32:371897 command.push(body);
Tim van der Lippe1d6e57a2019-09-30 11:55:341898 }
Blink Reformat4c46d092018-04-07 15:32:371899 }
1900
1901 return command.join(' ');
1902 }
Harley Libcf41f92018-09-10 18:01:131903
1904 /**
1905 * @param {!Array<!SDK.NetworkRequest>} requests
1906 * @return {!Promise<string>}
1907 */
1908 async _generateAllPowerShellCommand(requests) {
1909 const nonBlobRequests = this._filterOutBlobRequests(requests);
1910 const commands = await Promise.all(nonBlobRequests.map(request => this._generatePowerShellCommand(request)));
1911 return commands.join(';\r\n');
1912 }
Joey Arhara86c14e2019-03-12 03:20:501913
1914 /**
1915 * @return {string}
1916 */
1917 static getDCLEventColor() {
Tim van der Lippe1d6e57a2019-09-30 11:55:341918 if (UI.themeSupport.themeName() === 'dark') {
Joey Arhara86c14e2019-03-12 03:20:501919 return '#03A9F4';
Tim van der Lippe1d6e57a2019-09-30 11:55:341920 }
Joey Arhara86c14e2019-03-12 03:20:501921 return '#0867CB';
1922 }
1923
1924 /**
1925 * @return {string}
1926 */
1927 static getLoadEventColor() {
1928 return UI.themeSupport.patchColorText('#B31412', UI.ThemeSupport.ColorUsage.Foreground);
1929 }
Blink Reformat4c46d092018-04-07 15:32:371930};
1931
1932Network.NetworkLogView._isFilteredOutSymbol = Symbol('isFilteredOut');
1933Network.NetworkLogView._networkNodeSymbol = Symbol('NetworkNode');
1934
1935Network.NetworkLogView.HTTPSchemas = {
1936 'http': true,
1937 'https': true,
1938 'ws': true,
1939 'wss': true
1940};
1941
1942/** @enum {symbol} */
1943Network.NetworkLogView.Events = {
1944 RequestSelected: Symbol('RequestSelected')
1945};
1946
1947/** @enum {string} */
1948Network.NetworkLogView.FilterType = {
1949 Domain: 'domain',
1950 HasResponseHeader: 'has-response-header',
1951 Is: 'is',
1952 LargerThan: 'larger-than',
1953 Method: 'method',
1954 MimeType: 'mime-type',
1955 MixedContent: 'mixed-content',
1956 Priority: 'priority',
1957 Scheme: 'scheme',
1958 SetCookieDomain: 'set-cookie-domain',
1959 SetCookieName: 'set-cookie-name',
1960 SetCookieValue: 'set-cookie-value',
1961 StatusCode: 'status-code'
1962};
1963
1964/** @enum {string} */
1965Network.NetworkLogView.MixedContentFilterValues = {
1966 All: 'all',
1967 Displayed: 'displayed',
1968 Blocked: 'blocked',
1969 BlockOverridden: 'block-overridden'
1970};
1971
1972/** @enum {string} */
1973Network.NetworkLogView.IsFilterType = {
1974 Running: 'running',
Joey Arhard183e7e2019-02-28 03:37:051975 FromCache: 'from-cache',
1976 ServiceWorkerIntercepted: 'service-worker-intercepted',
1977 ServiceWorkerInitiated: 'service-worker-initiated'
Blink Reformat4c46d092018-04-07 15:32:371978};
1979
1980/** @type {!Array<string>} */
1981Network.NetworkLogView._searchKeys =
1982 Object.keys(Network.NetworkLogView.FilterType).map(key => Network.NetworkLogView.FilterType[key]);
1983
1984/** @typedef {function(!SDK.NetworkRequest): boolean} */
1985Network.NetworkLogView.Filter;
1986
1987/**
1988 * @interface
1989 */
1990Network.GroupLookupInterface = function() {};
1991
1992Network.GroupLookupInterface.prototype = {
1993 /**
1994 * @param {!SDK.NetworkRequest} request
1995 * @return {?Network.NetworkGroupNode}
1996 */
1997 groupNodeForRequest: function(request) {},
1998
1999 reset: function() {}
2000};