blob: ad4cb5629b9408931f2d7675c6fa3bfbac3b43f1 [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);
126 this._resourceCategoryFilterUI.addEventListener(
127 UI.FilterUI.Events.FilterChanged, this._filterChanged.bind(this), this);
128 filterBar.addFilter(this._resourceCategoryFilterUI);
129
130 this._filterParser = new TextUtils.FilterParser(Network.NetworkLogView._searchKeys);
131 this._suggestionBuilder =
132 new UI.FilterSuggestionBuilder(Network.NetworkLogView._searchKeys, Network.NetworkLogView._sortSearchValues);
133 this._resetSuggestionBuilder();
134
135 this._dataGrid = this._columns.dataGrid();
136 this._setupDataGrid();
137 this._columns.sortByCurrentColumn();
Erik Luo0187a022018-05-31 18:35:49138 filterBar.filterButton().addEventListener(
139 UI.ToolbarButton.Events.Click, this._dataGrid.scheduleUpdate.bind(this._dataGrid, true /* isFromUser */));
Blink Reformat4c46d092018-04-07 15:32:37140
141 this._summaryBarElement = this.element.createChild('div', 'network-summary-bar');
142
143 new UI.DropTarget(
144 this.element, [UI.DropTarget.Type.File], Common.UIString('Drop HAR files here'), this._handleDrop.bind(this));
145
146 Common.moduleSetting('networkColorCodeResourceTypes')
147 .addChangeListener(this._invalidateAllItems.bind(this, false), this);
148
149 SDK.targetManager.observeModels(SDK.NetworkManager, this);
Pavel Feldman18d13562018-07-31 03:31:18150 SDK.networkLog.addEventListener(SDK.NetworkLog.Events.RequestAdded, this._onRequestUpdated, this);
151 SDK.networkLog.addEventListener(SDK.NetworkLog.Events.RequestUpdated, this._onRequestUpdated, this);
152 SDK.networkLog.addEventListener(SDK.NetworkLog.Events.Reset, this._reset, this);
Blink Reformat4c46d092018-04-07 15:32:37153
154 this._updateGroupByFrame();
155 Common.moduleSetting('network.group-by-frame').addChangeListener(() => this._updateGroupByFrame());
156
157 this._filterBar = filterBar;
Blink Reformat4c46d092018-04-07 15:32:37158 }
159
Blink Reformat4c46d092018-04-07 15:32:37160 _updateGroupByFrame() {
161 const value = Common.moduleSetting('network.group-by-frame').get();
162 this._setGrouping(value ? 'Frame' : null);
163 }
164
165 /**
166 * @param {string} key
167 * @param {!Array<string>} values
168 */
169 static _sortSearchValues(key, values) {
170 if (key === Network.NetworkLogView.FilterType.Priority) {
171 values.sort((a, b) => {
172 const aPriority = /** @type {!Protocol.Network.ResourcePriority} */ (PerfUI.uiLabelToNetworkPriority(a));
173 const bPriority = /** @type {!Protocol.Network.ResourcePriority} */ (PerfUI.uiLabelToNetworkPriority(b));
174 return PerfUI.networkPriorityWeight(aPriority) - PerfUI.networkPriorityWeight(bPriority);
175 });
176 } else {
177 values.sort();
178 }
179 }
180
181 /**
182 * @param {!Network.NetworkLogView.Filter} filter
183 * @param {!SDK.NetworkRequest} request
184 * @return {boolean}
185 */
186 static _negativeFilter(filter, request) {
187 return !filter(request);
188 }
189
190 /**
191 * @param {?RegExp} regex
192 * @param {!SDK.NetworkRequest} request
193 * @return {boolean}
194 */
195 static _requestPathFilter(regex, request) {
196 if (!regex)
197 return false;
198
199 return regex.test(request.path() + '/' + request.name());
200 }
201
202 /**
203 * @param {string} domain
204 * @return {!Array.<string>}
205 */
206 static _subdomains(domain) {
207 const result = [domain];
208 let indexOfPeriod = domain.indexOf('.');
209 while (indexOfPeriod !== -1) {
210 result.push('*' + domain.substring(indexOfPeriod));
211 indexOfPeriod = domain.indexOf('.', indexOfPeriod + 1);
212 }
213 return result;
214 }
215
216 /**
217 * @param {string} value
218 * @return {!Network.NetworkLogView.Filter}
219 */
220 static _createRequestDomainFilter(value) {
221 /**
222 * @param {string} string
223 * @return {string}
224 */
225 function escapeForRegExp(string) {
226 return string.escapeForRegExp();
227 }
228 const escapedPattern = value.split('*').map(escapeForRegExp).join('.*');
229 return Network.NetworkLogView._requestDomainFilter.bind(null, new RegExp('^' + escapedPattern + '$', 'i'));
230 }
231
232 /**
233 * @param {!RegExp} regex
234 * @param {!SDK.NetworkRequest} request
235 * @return {boolean}
236 */
237 static _requestDomainFilter(regex, request) {
238 return regex.test(request.domain);
239 }
240
241 /**
242 * @param {!SDK.NetworkRequest} request
243 * @return {boolean}
244 */
245 static _runningRequestFilter(request) {
246 return !request.finished;
247 }
248
249 /**
250 * @param {!SDK.NetworkRequest} request
251 * @return {boolean}
252 */
253 static _fromCacheRequestFilter(request) {
254 return request.cached();
255 }
256
257 /**
Joey Arhard183e7e2019-02-28 03:37:05258 * @param {!SDK.NetworkRequest} request
259 * @return {boolean}
260 */
261 static _interceptedByServiceWorkerFilter(request) {
262 return request.fetchedViaServiceWorker;
263 }
264
265 /**
266 * @param {!SDK.NetworkRequest} request
267 * @return {boolean}
268 */
269 static _initiatedByServiceWorkerFilter(request) {
270 return request.initiatedByServiceWorker();
271 }
272
273 /**
Blink Reformat4c46d092018-04-07 15:32:37274 * @param {string} value
275 * @param {!SDK.NetworkRequest} request
276 * @return {boolean}
277 */
278 static _requestResponseHeaderFilter(value, request) {
279 return request.responseHeaderValue(value) !== undefined;
280 }
281
282 /**
283 * @param {string} value
284 * @param {!SDK.NetworkRequest} request
285 * @return {boolean}
286 */
287 static _requestMethodFilter(value, request) {
288 return request.requestMethod === value;
289 }
290
291 /**
292 * @param {string} value
293 * @param {!SDK.NetworkRequest} request
294 * @return {boolean}
295 */
296 static _requestPriorityFilter(value, request) {
297 return request.priority() === value;
298 }
299
300 /**
301 * @param {string} value
302 * @param {!SDK.NetworkRequest} request
303 * @return {boolean}
304 */
305 static _requestMimeTypeFilter(value, request) {
306 return request.mimeType === value;
307 }
308
309 /**
310 * @param {!Network.NetworkLogView.MixedContentFilterValues} value
311 * @param {!SDK.NetworkRequest} request
312 * @return {boolean}
313 */
314 static _requestMixedContentFilter(value, request) {
315 if (value === Network.NetworkLogView.MixedContentFilterValues.Displayed)
316 return request.mixedContentType === Protocol.Security.MixedContentType.OptionallyBlockable;
317 else if (value === Network.NetworkLogView.MixedContentFilterValues.Blocked)
318 return request.mixedContentType === Protocol.Security.MixedContentType.Blockable && request.wasBlocked();
319 else if (value === Network.NetworkLogView.MixedContentFilterValues.BlockOverridden)
320 return request.mixedContentType === Protocol.Security.MixedContentType.Blockable && !request.wasBlocked();
321 else if (value === Network.NetworkLogView.MixedContentFilterValues.All)
322 return request.mixedContentType !== Protocol.Security.MixedContentType.None;
323
324 return false;
325 }
326
327 /**
328 * @param {string} value
329 * @param {!SDK.NetworkRequest} request
330 * @return {boolean}
331 */
332 static _requestSchemeFilter(value, request) {
333 return request.scheme === value;
334 }
335
336 /**
337 * @param {string} value
338 * @param {!SDK.NetworkRequest} request
339 * @return {boolean}
340 */
341 static _requestSetCookieDomainFilter(value, request) {
342 const cookies = request.responseCookies;
343 for (let i = 0, l = cookies ? cookies.length : 0; i < l; ++i) {
344 if (cookies[i].domain() === value)
345 return true;
346 }
347 return false;
348 }
349
350 /**
351 * @param {string} value
352 * @param {!SDK.NetworkRequest} request
353 * @return {boolean}
354 */
355 static _requestSetCookieNameFilter(value, request) {
356 const cookies = request.responseCookies;
357 for (let i = 0, l = cookies ? cookies.length : 0; i < l; ++i) {
358 if (cookies[i].name() === value)
359 return true;
360 }
361 return false;
362 }
363
364 /**
365 * @param {string} value
366 * @param {!SDK.NetworkRequest} request
367 * @return {boolean}
368 */
369 static _requestSetCookieValueFilter(value, request) {
370 const cookies = request.responseCookies;
371 for (let i = 0, l = cookies ? cookies.length : 0; i < l; ++i) {
372 if (cookies[i].value() === value)
373 return true;
374 }
375 return false;
376 }
377
378 /**
379 * @param {number} value
380 * @param {!SDK.NetworkRequest} request
381 * @return {boolean}
382 */
383 static _requestSizeLargerThanFilter(value, request) {
384 return request.transferSize >= value;
385 }
386
387 /**
388 * @param {string} value
389 * @param {!SDK.NetworkRequest} request
390 * @return {boolean}
391 */
392 static _statusCodeFilter(value, request) {
393 return ('' + request.statusCode) === value;
394 }
395
396 /**
397 * @param {!SDK.NetworkRequest} request
398 * @return {boolean}
399 */
400 static HTTPRequestsFilter(request) {
401 return request.parsedURL.isValid && (request.scheme in Network.NetworkLogView.HTTPSchemas);
402 }
403
404 /**
405 * @param {!SDK.NetworkRequest} request
406 * @return {boolean}
407 */
408 static FinishedRequestsFilter(request) {
409 return request.finished;
410 }
411
412 /**
413 * @param {number} windowStart
414 * @param {number} windowEnd
415 * @param {!SDK.NetworkRequest} request
416 * @return {boolean}
417 */
418 static _requestTimeFilter(windowStart, windowEnd, request) {
419 if (request.issueTime() > windowEnd)
420 return false;
421 if (request.endTime !== -1 && request.endTime < windowStart)
422 return false;
423 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 || '';
446 if (!request.contentType().isTextType())
447 content = Common.ContentProvider.contentAsDataURL(content, request.mimeType, contentData.encoded);
448 else if (contentData.encoded)
449 content = window.atob(content);
450 InspectorFrontendHost.copyText(content);
Blink Reformat4c46d092018-04-07 15:32:37451 }
452
453 /**
454 * @param {!DataTransfer} dataTransfer
455 */
456 _handleDrop(dataTransfer) {
457 const items = dataTransfer.items;
458 if (!items.length)
459 return;
460 const entry = items[0].webkitGetAsEntry();
461 if (entry.isDirectory)
462 return;
463
464 entry.file(this._onLoadFromFile.bind(this));
465 }
466
467 /**
468 * @param {!File} file
469 */
470 async _onLoadFromFile(file) {
471 const outputStream = new Common.StringOutputStream();
472 const reader = new Bindings.ChunkedFileReader(file, /* chunkSize */ 10000000);
473 const success = await reader.read(outputStream);
474 if (!success) {
475 this._harLoadFailed(reader.error().message);
476 return;
477 }
478 let harRoot;
479 try {
480 // HARRoot and JSON.parse might throw.
481 harRoot = new HARImporter.HARRoot(JSON.parse(outputStream.data()));
482 } catch (e) {
483 this._harLoadFailed(e);
484 return;
485 }
Pavel Feldman18d13562018-07-31 03:31:18486 SDK.networkLog.importRequests(HARImporter.Importer.requestsFromHARLog(harRoot.log));
Blink Reformat4c46d092018-04-07 15:32:37487 }
488
489 /**
490 * @param {string} message
491 */
492 _harLoadFailed(message) {
493 Common.console.error('Failed to load HAR file with following error: ' + message);
494 }
495
496 /**
497 * @param {?string} groupKey
498 */
499 _setGrouping(groupKey) {
500 if (this._activeGroupLookup)
501 this._activeGroupLookup.reset();
502 const groupLookup = groupKey ? this._groupLookups.get(groupKey) || null : null;
503 this._activeGroupLookup = groupLookup;
504 this._invalidateAllItems();
505 }
506
507 /**
508 * @return {number}
509 */
510 _computeRowHeight() {
511 return Math.round(this._rawRowHeight * window.devicePixelRatio) / window.devicePixelRatio;
512 }
513
514 /**
515 * @param {!SDK.NetworkRequest} request
516 * @return {?Network.NetworkRequestNode}
517 */
518 nodeForRequest(request) {
519 return request[Network.NetworkLogView._networkNodeSymbol] || null;
520 }
521
522 /**
523 * @return {number}
524 */
525 headerHeight() {
526 return this._headerHeight;
527 }
528
529 /**
530 * @param {boolean} recording
531 */
532 setRecording(recording) {
533 this._recording = recording;
534 this._updateSummaryBar();
535 }
536
537 /**
538 * @override
539 * @param {!SDK.NetworkManager} networkManager
540 */
541 modelAdded(networkManager) {
542 // TODO(allada) Remove dependency on networkManager and instead use NetworkLog and PageLoad for needed data.
543 if (networkManager.target().parentTarget())
544 return;
545 const resourceTreeModel = networkManager.target().model(SDK.ResourceTreeModel);
546 if (resourceTreeModel) {
547 resourceTreeModel.addEventListener(SDK.ResourceTreeModel.Events.Load, this._loadEventFired, this);
548 resourceTreeModel.addEventListener(
549 SDK.ResourceTreeModel.Events.DOMContentLoaded, this._domContentLoadedEventFired, this);
550 }
551 }
552
553 /**
554 * @override
555 * @param {!SDK.NetworkManager} networkManager
556 */
557 modelRemoved(networkManager) {
558 if (!networkManager.target().parentTarget()) {
559 const resourceTreeModel = networkManager.target().model(SDK.ResourceTreeModel);
560 if (resourceTreeModel) {
561 resourceTreeModel.removeEventListener(SDK.ResourceTreeModel.Events.Load, this._loadEventFired, this);
562 resourceTreeModel.removeEventListener(
563 SDK.ResourceTreeModel.Events.DOMContentLoaded, this._domContentLoadedEventFired, this);
564 }
565 }
566 }
567
568 /**
569 * @param {number} start
570 * @param {number} end
571 */
572 setWindow(start, end) {
573 if (!start && !end) {
574 this._timeFilter = null;
575 this._timeCalculator.setWindow(null);
576 } else {
577 this._timeFilter = Network.NetworkLogView._requestTimeFilter.bind(null, start, end);
578 this._timeCalculator.setWindow(new Network.NetworkTimeBoundary(start, end));
579 }
580 this._filterRequests();
581 }
582
583 clearSelection() {
584 if (this._dataGrid.selectedNode)
585 this._dataGrid.selectedNode.deselect();
586 }
587
588 _resetSuggestionBuilder() {
589 this._suggestionBuilder.clear();
590 this._suggestionBuilder.addItem(Network.NetworkLogView.FilterType.Is, Network.NetworkLogView.IsFilterType.Running);
591 this._suggestionBuilder.addItem(
592 Network.NetworkLogView.FilterType.Is, Network.NetworkLogView.IsFilterType.FromCache);
Joey Arhard183e7e2019-02-28 03:37:05593 this._suggestionBuilder.addItem(
594 Network.NetworkLogView.FilterType.Is, Network.NetworkLogView.IsFilterType.ServiceWorkerIntercepted);
595 this._suggestionBuilder.addItem(
596 Network.NetworkLogView.FilterType.Is, Network.NetworkLogView.IsFilterType.ServiceWorkerInitiated);
Blink Reformat4c46d092018-04-07 15:32:37597 this._suggestionBuilder.addItem(Network.NetworkLogView.FilterType.LargerThan, '100');
598 this._suggestionBuilder.addItem(Network.NetworkLogView.FilterType.LargerThan, '10k');
599 this._suggestionBuilder.addItem(Network.NetworkLogView.FilterType.LargerThan, '1M');
600 this._textFilterUI.setSuggestionProvider(this._suggestionBuilder.completions.bind(this._suggestionBuilder));
601 }
602
603 /**
604 * @param {!Common.Event} event
605 */
606 _filterChanged(event) {
607 this.removeAllNodeHighlights();
608 this._parseFilterQuery(this._textFilterUI.value());
609 this._filterRequests();
Blink Reformat4c46d092018-04-07 15:32:37610 }
611
612 _showRecordingHint() {
613 this._hideRecordingHint();
614 this._recordingHint = this.element.createChild('div', 'network-status-pane fill');
615 const hintText = this._recordingHint.createChild('div', 'recording-hint');
Joey Arhar0585e6f2018-10-30 23:11:18616
617 let reloadShortcutNode = null;
618 const reloadShortcutDescriptor = UI.shortcutRegistry.shortcutDescriptorsForAction('inspector_main.reload')[0];
619 if (reloadShortcutDescriptor) {
620 reloadShortcutNode = this._recordingHint.createChild('b');
621 reloadShortcutNode.textContent = reloadShortcutDescriptor.name;
622 }
Blink Reformat4c46d092018-04-07 15:32:37623
624 if (this._recording) {
625 const recordingText = hintText.createChild('span');
626 recordingText.textContent = Common.UIString('Recording network activity\u2026');
Joey Arhar0585e6f2018-10-30 23:11:18627 if (reloadShortcutNode) {
628 hintText.createChild('br');
629 hintText.appendChild(
630 UI.formatLocalized('Perform a request or hit %s to record the reload.', [reloadShortcutNode]));
631 }
Blink Reformat4c46d092018-04-07 15:32:37632 } else {
633 const recordNode = hintText.createChild('b');
634 recordNode.textContent = UI.shortcutRegistry.shortcutTitleForAction('network.toggle-recording');
Joey Arhar0585e6f2018-10-30 23:11:18635 if (reloadShortcutNode) {
636 hintText.appendChild(UI.formatLocalized(
637 'Record (%s) or reload (%s) to display network activity.', [recordNode, reloadShortcutNode]));
638 } else {
639 hintText.appendChild(UI.formatLocalized('Record (%s) to display network activity.', [recordNode]));
640 }
Blink Reformat4c46d092018-04-07 15:32:37641 }
Kayce Basques5444c1b2019-02-15 20:32:53642 hintText.createChild('br');
643 hintText.appendChild(UI.XLink.create(
644 'https://developers.google.com/web/tools/chrome-devtools/network/?utm_source=devtools&utm_campaign=2019Q1',
645 'Learn more'));
Blink Reformat4c46d092018-04-07 15:32:37646 }
647
648 _hideRecordingHint() {
649 if (this._recordingHint)
650 this._recordingHint.remove();
651 this._recordingHint = null;
652 }
653
654 /**
655 * @override
656 * @return {!Array.<!Element>}
657 */
658 elementsToRestoreScrollPositionsFor() {
659 if (!this._dataGrid) // Not initialized yet.
660 return [];
661 return [this._dataGrid.scrollContainer];
662 }
663
664 columnExtensionResolved() {
665 this._invalidateAllItems(true);
666 }
667
668 _setupDataGrid() {
669 this._dataGrid.setRowContextMenuCallback((contextMenu, node) => {
670 const request = node.request();
671 if (request)
672 this.handleContextMenuForRequest(contextMenu, request);
673 });
674 this._dataGrid.setStickToBottom(true);
675 this._dataGrid.setName('networkLog');
676 this._dataGrid.setResizeMethod(DataGrid.DataGrid.ResizeMethod.Last);
677 this._dataGrid.element.classList.add('network-log-grid');
678 this._dataGrid.element.addEventListener('mousedown', this._dataGridMouseDown.bind(this), true);
679 this._dataGrid.element.addEventListener('mousemove', this._dataGridMouseMove.bind(this), true);
680 this._dataGrid.element.addEventListener('mouseleave', () => this._setHoveredNode(null), true);
681 return this._dataGrid;
682 }
683
684 /**
685 * @param {!Event} event
686 */
687 _dataGridMouseMove(event) {
688 const node = (this._dataGrid.dataGridNodeFromNode(/** @type {!Node} */ (event.target)));
689 const highlightInitiatorChain = event.shiftKey;
690 this._setHoveredNode(node, highlightInitiatorChain);
691 }
692
693 /**
694 * @return {?Network.NetworkNode}
695 */
696 hoveredNode() {
697 return this._hoveredNode;
698 }
699
700 /**
701 * @param {?Network.NetworkNode} node
702 * @param {boolean=} highlightInitiatorChain
703 */
704 _setHoveredNode(node, highlightInitiatorChain) {
705 if (this._hoveredNode)
706 this._hoveredNode.setHovered(false, false);
707 this._hoveredNode = node;
708 if (this._hoveredNode)
709 this._hoveredNode.setHovered(true, !!highlightInitiatorChain);
710 }
711
712 /**
713 * @param {!Event} event
714 */
715 _dataGridMouseDown(event) {
716 if (!this._dataGrid.selectedNode && event.button)
717 event.consume();
718 }
719
720 _updateSummaryBar() {
721 this._hideRecordingHint();
722
723 let transferSize = 0;
Dan Beam87466b52018-12-01 18:41:20724 let resourceSize = 0;
Blink Reformat4c46d092018-04-07 15:32:37725 let selectedNodeNumber = 0;
726 let selectedTransferSize = 0;
Dan Beam87466b52018-12-01 18:41:20727 let selectedResourceSize = 0;
Blink Reformat4c46d092018-04-07 15:32:37728 let baseTime = -1;
729 let maxTime = -1;
730
731 let nodeCount = 0;
Pavel Feldman18d13562018-07-31 03:31:18732 for (const request of SDK.networkLog.requests()) {
Blink Reformat4c46d092018-04-07 15:32:37733 const node = request[Network.NetworkLogView._networkNodeSymbol];
734 if (!node)
735 continue;
736 nodeCount++;
737 const requestTransferSize = request.transferSize;
738 transferSize += requestTransferSize;
Dan Beam87466b52018-12-01 18:41:20739 const requestResourceSize = request.resourceSize;
740 resourceSize += requestResourceSize;
Blink Reformat4c46d092018-04-07 15:32:37741 if (!node[Network.NetworkLogView._isFilteredOutSymbol]) {
742 selectedNodeNumber++;
743 selectedTransferSize += requestTransferSize;
Dan Beam87466b52018-12-01 18:41:20744 selectedResourceSize += requestResourceSize;
Blink Reformat4c46d092018-04-07 15:32:37745 }
746 const networkManager = SDK.NetworkManager.forRequest(request);
747 // TODO(allada) inspectedURL should be stored in PageLoad used instead of target so HAR requests can have an
748 // inspected url.
749 if (networkManager && request.url() === networkManager.target().inspectedURL() &&
750 request.resourceType() === Common.resourceTypes.Document && !networkManager.target().parentTarget())
751 baseTime = request.startTime;
752 if (request.endTime > maxTime)
753 maxTime = request.endTime;
754 }
755
756 if (!nodeCount) {
757 this._showRecordingHint();
758 return;
759 }
760
761 const summaryBar = this._summaryBarElement;
762 summaryBar.removeChildren();
763 const separator = '\u2002\u2758\u2002';
764 let text = '';
765 /**
766 * @param {string} chunk
767 * @return {!Element}
768 */
769 function appendChunk(chunk) {
770 const span = summaryBar.createChild('span');
771 span.textContent = chunk;
772 text += chunk;
773 return span;
774 }
775
776 if (selectedNodeNumber !== nodeCount) {
777 appendChunk(Common.UIString('%d / %d requests', selectedNodeNumber, nodeCount));
778 appendChunk(separator);
779 appendChunk(Common.UIString(
780 '%s / %s transferred', Number.bytesToString(selectedTransferSize), Number.bytesToString(transferSize)));
Dan Beam87466b52018-12-01 18:41:20781 appendChunk(separator);
782 appendChunk(Common.UIString(
783 '%s / %s resources', Number.bytesToString(selectedResourceSize), Number.bytesToString(resourceSize)));
Blink Reformat4c46d092018-04-07 15:32:37784 } else {
785 appendChunk(Common.UIString('%d requests', nodeCount));
786 appendChunk(separator);
787 appendChunk(Common.UIString('%s transferred', Number.bytesToString(transferSize)));
Dan Beam87466b52018-12-01 18:41:20788 appendChunk(separator);
789 appendChunk(Common.UIString('%s resources', Number.bytesToString(resourceSize)));
Blink Reformat4c46d092018-04-07 15:32:37790 }
Dan Beam87466b52018-12-01 18:41:20791
Blink Reformat4c46d092018-04-07 15:32:37792 if (baseTime !== -1 && maxTime !== -1) {
793 appendChunk(separator);
794 appendChunk(Common.UIString('Finish: %s', Number.secondsToString(maxTime - baseTime)));
795 if (this._mainRequestDOMContentLoadedTime !== -1 && this._mainRequestDOMContentLoadedTime > baseTime) {
796 appendChunk(separator);
Alexei Filippovfdcd8a62018-12-17 21:32:30797 const domContentLoadedText =
798 ls`DOMContentLoaded: ${Number.secondsToString(this._mainRequestDOMContentLoadedTime - baseTime)}`;
799 appendChunk(domContentLoadedText).classList.add('summary-dcl-event');
Blink Reformat4c46d092018-04-07 15:32:37800 }
801 if (this._mainRequestLoadTime !== -1) {
802 appendChunk(separator);
Alexei Filippovfdcd8a62018-12-17 21:32:30803 const loadText = ls`Load: ${Number.secondsToString(this._mainRequestLoadTime - baseTime)}`;
804 appendChunk(loadText).classList.add('summary-load-event');
Blink Reformat4c46d092018-04-07 15:32:37805 }
806 }
807 summaryBar.title = text;
808 }
809
810 scheduleRefresh() {
811 if (this._needsRefresh)
812 return;
813
814 this._needsRefresh = true;
815
816 if (this.isShowing() && !this._refreshRequestId)
817 this._refreshRequestId = this.element.window().requestAnimationFrame(this._refresh.bind(this));
818 }
819
820 /**
821 * @param {!Array<number>} times
822 */
823 addFilmStripFrames(times) {
824 this._columns.addEventDividers(times, 'network-frame-divider');
825 }
826
827 /**
828 * @param {number} time
829 */
830 selectFilmStripFrame(time) {
831 this._columns.selectFilmStripFrame(time);
832 }
833
834 clearFilmStripFrame() {
835 this._columns.clearFilmStripFrame();
836 }
837
838 _refreshIfNeeded() {
839 if (this._needsRefresh)
840 this._refresh();
841 }
842
843 /**
844 * @param {boolean=} deferUpdate
845 */
846 _invalidateAllItems(deferUpdate) {
Pavel Feldman18d13562018-07-31 03:31:18847 this._staleRequests = new Set(SDK.networkLog.requests());
Blink Reformat4c46d092018-04-07 15:32:37848 if (deferUpdate)
849 this.scheduleRefresh();
850 else
851 this._refresh();
852 }
853
854 /**
855 * @return {!Network.NetworkTimeCalculator}
856 */
857 timeCalculator() {
858 return this._timeCalculator;
859 }
860
861 /**
862 * @return {!Network.NetworkTimeCalculator}
863 */
864 calculator() {
865 return this._calculator;
866 }
867
868 /**
869 * @param {!Network.NetworkTimeCalculator} x
870 */
871 setCalculator(x) {
872 if (!x || this._calculator === x)
873 return;
874
875 if (this._calculator !== x) {
876 this._calculator = x;
877 this._columns.setCalculator(this._calculator);
878 }
879 this._calculator.reset();
880
881 if (this._calculator.startAtZero)
882 this._columns.hideEventDividers();
883 else
884 this._columns.showEventDividers();
885
886 this._invalidateAllItems();
887 }
888
889 /**
890 * @param {!Common.Event} event
891 */
892 _loadEventFired(event) {
893 if (!this._recording)
894 return;
895
896 const time = /** @type {number} */ (event.data.loadTime);
897 if (time) {
898 this._mainRequestLoadTime = time;
Alexei Filippovfdcd8a62018-12-17 21:32:30899 this._columns.addEventDividers([time], 'network-load-divider');
Blink Reformat4c46d092018-04-07 15:32:37900 }
901 }
902
903 /**
904 * @param {!Common.Event} event
905 */
906 _domContentLoadedEventFired(event) {
907 if (!this._recording)
908 return;
909 const data = /** @type {number} */ (event.data);
910 if (data) {
911 this._mainRequestDOMContentLoadedTime = data;
Alexei Filippovfdcd8a62018-12-17 21:32:30912 this._columns.addEventDividers([data], 'network-dcl-divider');
Blink Reformat4c46d092018-04-07 15:32:37913 }
914 }
915
916 /**
917 * @override
918 */
919 wasShown() {
920 this._refreshIfNeeded();
921 this._columns.wasShown();
922 }
923
924 /**
925 * @override
926 */
927 willHide() {
928 this._columns.willHide();
929 }
930
931 /**
932 * @override
933 */
934 onResize() {
935 this._rowHeight = this._computeRowHeight();
936 }
937
938 /**
939 * @return {!Array<!Network.NetworkNode>}
940 */
941 flatNodesList() {
942 return this._dataGrid.rootNode().flatChildren();
943 }
944
945 stylesChanged() {
946 this._columns.scheduleRefresh();
947 }
948
949 _refresh() {
950 this._needsRefresh = false;
951
952 if (this._refreshRequestId) {
953 this.element.window().cancelAnimationFrame(this._refreshRequestId);
954 this._refreshRequestId = null;
955 }
956
957 this.removeAllNodeHighlights();
958
959 this._timeCalculator.updateBoundariesForEventTime(this._mainRequestLoadTime);
960 this._durationCalculator.updateBoundariesForEventTime(this._mainRequestLoadTime);
961 this._timeCalculator.updateBoundariesForEventTime(this._mainRequestDOMContentLoadedTime);
962 this._durationCalculator.updateBoundariesForEventTime(this._mainRequestDOMContentLoadedTime);
963
964 /** @type {!Map<!Network.NetworkNode, !Network.NetworkNode>} */
965 const nodesToInsert = new Map();
966 /** @type {!Array<!Network.NetworkNode>} */
967 const nodesToRefresh = [];
968
969 /** @type {!Set<!Network.NetworkRequestNode>} */
970 const staleNodes = new Set();
971
972 // While creating nodes it may add more entries into _staleRequests because redirect request nodes update the parent
973 // node so we loop until we have no more stale requests.
974 while (this._staleRequests.size) {
975 const request = this._staleRequests.firstValue();
976 this._staleRequests.delete(request);
977 let node = request[Network.NetworkLogView._networkNodeSymbol];
978 if (!node)
979 node = this._createNodeForRequest(request);
980 staleNodes.add(node);
981 }
982
983 for (const node of staleNodes) {
984 const isFilteredOut = !this._applyFilter(node);
985 if (isFilteredOut && node === this._hoveredNode)
986 this._setHoveredNode(null);
987
988 if (!isFilteredOut)
989 nodesToRefresh.push(node);
990 const request = node.request();
991 this._timeCalculator.updateBoundaries(request);
992 this._durationCalculator.updateBoundaries(request);
993 const newParent = this._parentNodeForInsert(node);
994 if (node[Network.NetworkLogView._isFilteredOutSymbol] === isFilteredOut && node.parent === newParent)
995 continue;
996 node[Network.NetworkLogView._isFilteredOutSymbol] = isFilteredOut;
997 const removeFromParent = node.parent && (isFilteredOut || node.parent !== newParent);
998 if (removeFromParent) {
999 let parent = node.parent;
1000 parent.removeChild(node);
1001 while (parent && !parent.hasChildren() && parent.dataGrid && parent.dataGrid.rootNode() !== parent) {
1002 const grandparent = parent.parent;
1003 grandparent.removeChild(parent);
1004 parent = grandparent;
1005 }
1006 }
1007
1008 if (!newParent || isFilteredOut)
1009 continue;
1010
1011 if (!newParent.dataGrid && !nodesToInsert.has(newParent)) {
1012 nodesToInsert.set(newParent, this._dataGrid.rootNode());
1013 nodesToRefresh.push(newParent);
1014 }
1015 nodesToInsert.set(node, newParent);
1016 }
1017
1018 for (const node of nodesToInsert.keys())
1019 nodesToInsert.get(node).appendChild(node);
1020
1021 for (const node of nodesToRefresh)
1022 node.refresh();
1023
1024 this._updateSummaryBar();
1025
1026 if (nodesToInsert.size)
1027 this._columns.sortByCurrentColumn();
1028
1029 this._dataGrid.updateInstantly();
1030 this._didRefreshForTest();
1031 }
1032
1033 _didRefreshForTest() {
1034 }
1035
1036 /**
1037 * @param {!Network.NetworkRequestNode} node
1038 * @return {?Network.NetworkNode}
1039 */
1040 _parentNodeForInsert(node) {
1041 if (!this._activeGroupLookup)
1042 return this._dataGrid.rootNode();
1043
1044 const groupNode = this._activeGroupLookup.groupNodeForRequest(node.request());
1045 if (!groupNode)
1046 return this._dataGrid.rootNode();
1047 return groupNode;
1048 }
1049
1050 _reset() {
1051 this.dispatchEventToListeners(Network.NetworkLogView.Events.RequestSelected, null);
1052
1053 this._setHoveredNode(null);
1054 this._columns.reset();
1055
1056 this._timeFilter = null;
1057 this._calculator.reset();
1058
1059 this._timeCalculator.setWindow(null);
1060 this.linkifier.reset();
1061 this.badgePool.reset();
1062
1063 if (this._activeGroupLookup)
1064 this._activeGroupLookup.reset();
1065 this._staleRequests.clear();
1066 this._resetSuggestionBuilder();
1067
1068 this._mainRequestLoadTime = -1;
1069 this._mainRequestDOMContentLoadedTime = -1;
1070
1071 this._dataGrid.rootNode().removeChildren();
1072 this._updateSummaryBar();
1073 this._dataGrid.setStickToBottom(true);
1074 this.scheduleRefresh();
1075 }
1076
1077 /**
1078 * @param {string} filterString
1079 */
1080 setTextFilterValue(filterString) {
1081 this._textFilterUI.setValue(filterString);
1082 this._dataURLFilterUI.setChecked(false);
1083 this._resourceCategoryFilterUI.reset();
1084 }
1085
1086 /**
1087 * @param {!SDK.NetworkRequest} request
1088 */
1089 _createNodeForRequest(request) {
1090 const node = new Network.NetworkRequestNode(this, request);
1091 request[Network.NetworkLogView._networkNodeSymbol] = node;
1092 node[Network.NetworkLogView._isFilteredOutSymbol] = true;
1093
1094 for (let redirect = request.redirectSource(); redirect; redirect = redirect.redirectSource())
1095 this._refreshRequest(redirect);
1096 return node;
1097 }
1098
1099 /**
1100 * @param {!Common.Event} event
1101 */
1102 _onRequestUpdated(event) {
1103 const request = /** @type {!SDK.NetworkRequest} */ (event.data);
1104 this._refreshRequest(request);
1105 }
1106
1107 /**
1108 * @param {!SDK.NetworkRequest} request
1109 */
1110 _refreshRequest(request) {
1111 Network.NetworkLogView._subdomains(request.domain)
1112 .forEach(
1113 this._suggestionBuilder.addItem.bind(this._suggestionBuilder, Network.NetworkLogView.FilterType.Domain));
1114 this._suggestionBuilder.addItem(Network.NetworkLogView.FilterType.Method, request.requestMethod);
1115 this._suggestionBuilder.addItem(Network.NetworkLogView.FilterType.MimeType, request.mimeType);
1116 this._suggestionBuilder.addItem(Network.NetworkLogView.FilterType.Scheme, '' + request.scheme);
1117 this._suggestionBuilder.addItem(Network.NetworkLogView.FilterType.StatusCode, '' + request.statusCode);
1118
1119 const priority = request.priority();
1120 if (priority) {
1121 this._suggestionBuilder.addItem(
1122 Network.NetworkLogView.FilterType.Priority, PerfUI.uiLabelForNetworkPriority(priority));
1123 }
1124
1125 if (request.mixedContentType !== Protocol.Security.MixedContentType.None) {
1126 this._suggestionBuilder.addItem(
1127 Network.NetworkLogView.FilterType.MixedContent, Network.NetworkLogView.MixedContentFilterValues.All);
1128 }
1129
1130 if (request.mixedContentType === Protocol.Security.MixedContentType.OptionallyBlockable) {
1131 this._suggestionBuilder.addItem(
1132 Network.NetworkLogView.FilterType.MixedContent, Network.NetworkLogView.MixedContentFilterValues.Displayed);
1133 }
1134
1135 if (request.mixedContentType === Protocol.Security.MixedContentType.Blockable) {
1136 const suggestion = request.wasBlocked() ? Network.NetworkLogView.MixedContentFilterValues.Blocked :
1137 Network.NetworkLogView.MixedContentFilterValues.BlockOverridden;
1138 this._suggestionBuilder.addItem(Network.NetworkLogView.FilterType.MixedContent, suggestion);
1139 }
1140
1141 const responseHeaders = request.responseHeaders;
1142 for (let i = 0, l = responseHeaders.length; i < l; ++i)
1143 this._suggestionBuilder.addItem(Network.NetworkLogView.FilterType.HasResponseHeader, responseHeaders[i].name);
1144 const cookies = request.responseCookies;
1145 for (let i = 0, l = cookies ? cookies.length : 0; i < l; ++i) {
1146 const cookie = cookies[i];
1147 this._suggestionBuilder.addItem(Network.NetworkLogView.FilterType.SetCookieDomain, cookie.domain());
1148 this._suggestionBuilder.addItem(Network.NetworkLogView.FilterType.SetCookieName, cookie.name());
1149 this._suggestionBuilder.addItem(Network.NetworkLogView.FilterType.SetCookieValue, cookie.value());
1150 }
1151
1152 this._staleRequests.add(request);
1153 this.scheduleRefresh();
1154 }
1155
1156 /**
1157 * @return {number}
1158 */
1159 rowHeight() {
1160 return this._rowHeight;
1161 }
1162
1163 /**
1164 * @param {boolean} gridMode
1165 */
1166 switchViewMode(gridMode) {
1167 this._columns.switchViewMode(gridMode);
1168 }
1169
1170 /**
1171 * @param {!UI.ContextMenu} contextMenu
1172 * @param {!SDK.NetworkRequest} request
1173 */
1174 handleContextMenuForRequest(contextMenu, request) {
1175 contextMenu.appendApplicableItems(request);
1176 let copyMenu = contextMenu.clipboardSection().appendSubMenuItem(Common.UIString('Copy'));
1177 const footerSection = copyMenu.footerSection();
1178 if (request) {
1179 copyMenu.defaultSection().appendItem(
1180 UI.copyLinkAddressLabel(), InspectorFrontendHost.copyText.bind(InspectorFrontendHost, request.contentURL()));
1181 if (request.requestHeadersText()) {
1182 copyMenu.defaultSection().appendItem(
1183 Common.UIString('Copy request headers'), Network.NetworkLogView._copyRequestHeaders.bind(null, request));
1184 }
1185
1186 if (request.responseHeadersText) {
1187 copyMenu.defaultSection().appendItem(
1188 Common.UIString('Copy response headers'), Network.NetworkLogView._copyResponseHeaders.bind(null, request));
1189 }
1190
1191 if (request.finished) {
1192 copyMenu.defaultSection().appendItem(
1193 Common.UIString('Copy response'), Network.NetworkLogView._copyResponse.bind(null, request));
1194 }
1195
Harley Libcf41f92018-09-10 18:01:131196 const disableIfBlob = request.isBlobRequest();
Blink Reformat4c46d092018-04-07 15:32:371197 if (Host.isWin()) {
1198 footerSection.appendItem(
Harley Libcf41f92018-09-10 18:01:131199 Common.UIString('Copy as PowerShell'), this._copyPowerShellCommand.bind(this, request), disableIfBlob);
Blink Reformat4c46d092018-04-07 15:32:371200 footerSection.appendItem(
Harley Libcf41f92018-09-10 18:01:131201 Common.UIString('Copy as fetch'), this._copyFetchCall.bind(this, request), disableIfBlob);
Blink Reformat4c46d092018-04-07 15:32:371202 footerSection.appendItem(
Harley Libcf41f92018-09-10 18:01:131203 Common.UIString('Copy as cURL (cmd)'), this._copyCurlCommand.bind(this, request, 'win'), disableIfBlob);
1204 footerSection.appendItem(
1205 Common.UIString('Copy as cURL (bash)'), this._copyCurlCommand.bind(this, request, 'unix'), disableIfBlob);
Blink Reformat4c46d092018-04-07 15:32:371206 footerSection.appendItem(Common.UIString('Copy all as PowerShell'), this._copyAllPowerShellCommand.bind(this));
1207 footerSection.appendItem(Common.UIString('Copy all as fetch'), this._copyAllFetchCall.bind(this));
1208 footerSection.appendItem(Common.UIString('Copy all as cURL (cmd)'), this._copyAllCurlCommand.bind(this, 'win'));
1209 footerSection.appendItem(
1210 Common.UIString('Copy all as cURL (bash)'), this._copyAllCurlCommand.bind(this, 'unix'));
1211 } else {
Harley Libcf41f92018-09-10 18:01:131212 footerSection.appendItem(
1213 Common.UIString('Copy as fetch'), this._copyFetchCall.bind(this, request), disableIfBlob);
1214 footerSection.appendItem(
1215 Common.UIString('Copy as cURL'), this._copyCurlCommand.bind(this, request, 'unix'), disableIfBlob);
Blink Reformat4c46d092018-04-07 15:32:371216 footerSection.appendItem(Common.UIString('Copy all as fetch'), this._copyAllFetchCall.bind(this));
1217 footerSection.appendItem(Common.UIString('Copy all as cURL'), this._copyAllCurlCommand.bind(this, 'unix'));
1218 }
1219 } else {
1220 copyMenu = contextMenu.clipboardSection().appendSubMenuItem(Common.UIString('Copy'));
1221 }
1222 footerSection.appendItem(Common.UIString('Copy all as HAR'), this._copyAll.bind(this));
1223
Joey Arhar076efbc2018-11-06 00:24:201224 contextMenu.saveSection().appendItem(Common.UIString('Save all as HAR with content'), this._exportAll.bind(this));
Blink Reformat4c46d092018-04-07 15:32:371225
1226 contextMenu.editSection().appendItem(Common.UIString('Clear browser cache'), this._clearBrowserCache.bind(this));
1227 contextMenu.editSection().appendItem(
1228 Common.UIString('Clear browser cookies'), this._clearBrowserCookies.bind(this));
1229
1230 if (request) {
1231 const maxBlockedURLLength = 20;
1232 const manager = SDK.multitargetNetworkManager;
1233 let patterns = manager.blockedPatterns();
1234
1235 const urlWithoutScheme = request.parsedURL.urlWithoutScheme();
1236 if (urlWithoutScheme && !patterns.find(pattern => pattern.url === urlWithoutScheme)) {
1237 contextMenu.debugSection().appendItem(
1238 Common.UIString('Block request URL'), addBlockedURL.bind(null, urlWithoutScheme));
1239 } else if (urlWithoutScheme) {
1240 const croppedURL = urlWithoutScheme.trimMiddle(maxBlockedURLLength);
1241 contextMenu.debugSection().appendItem(
1242 Common.UIString('Unblock %s', croppedURL), removeBlockedURL.bind(null, urlWithoutScheme));
1243 }
1244
1245 const domain = request.parsedURL.domain();
1246 if (domain && !patterns.find(pattern => pattern.url === domain)) {
1247 contextMenu.debugSection().appendItem(
1248 Common.UIString('Block request domain'), addBlockedURL.bind(null, domain));
1249 } else if (domain) {
1250 const croppedDomain = domain.trimMiddle(maxBlockedURLLength);
1251 contextMenu.debugSection().appendItem(
1252 Common.UIString('Unblock %s', croppedDomain), removeBlockedURL.bind(null, domain));
1253 }
1254
1255 if (SDK.NetworkManager.canReplayRequest(request)) {
1256 contextMenu.debugSection().appendItem(
1257 Common.UIString('Replay XHR'), SDK.NetworkManager.replayRequest.bind(null, request));
1258 }
1259
1260 /**
1261 * @param {string} url
1262 */
1263 function addBlockedURL(url) {
1264 patterns.push({enabled: true, url: url});
1265 manager.setBlockedPatterns(patterns);
1266 manager.setBlockingEnabled(true);
1267 UI.viewManager.showView('network.blocked-urls');
1268 }
1269
1270 /**
1271 * @param {string} url
1272 */
1273 function removeBlockedURL(url) {
1274 patterns = patterns.filter(pattern => pattern.url !== url);
1275 manager.setBlockedPatterns(patterns);
1276 UI.viewManager.showView('network.blocked-urls');
1277 }
1278 }
1279 }
1280
1281 _harRequests() {
Pavel Feldman18d13562018-07-31 03:31:181282 const httpRequests = SDK.networkLog.requests().filter(Network.NetworkLogView.HTTPRequestsFilter);
Blink Reformat4c46d092018-04-07 15:32:371283 return httpRequests.filter(Network.NetworkLogView.FinishedRequestsFilter);
1284 }
1285
1286 async _copyAll() {
Pavel Feldman18d13562018-07-31 03:31:181287 const harArchive = {log: await SDK.HARLog.build(this._harRequests())};
Blink Reformat4c46d092018-04-07 15:32:371288 InspectorFrontendHost.copyText(JSON.stringify(harArchive, null, 2));
1289 }
1290
1291 /**
1292 * @param {!SDK.NetworkRequest} request
1293 * @param {string} platform
1294 */
1295 async _copyCurlCommand(request, platform) {
1296 const command = await this._generateCurlCommand(request, platform);
1297 InspectorFrontendHost.copyText(command);
1298 }
1299
1300 /**
1301 * @param {string} platform
1302 */
1303 async _copyAllCurlCommand(platform) {
Harley Libcf41f92018-09-10 18:01:131304 const commands = await this._generateAllCurlCommand(SDK.networkLog.requests(), platform);
1305 InspectorFrontendHost.copyText(commands);
Blink Reformat4c46d092018-04-07 15:32:371306 }
1307
1308 /**
1309 * @param {!SDK.NetworkRequest} request
1310 * @param {string} platform
1311 */
1312 async _copyFetchCall(request, platform) {
1313 const command = await this._generateFetchCall(request);
1314 InspectorFrontendHost.copyText(command);
1315 }
1316
1317 async _copyAllFetchCall() {
Harley Libcf41f92018-09-10 18:01:131318 const commands = await this._generateAllFetchCall(SDK.networkLog.requests());
1319 InspectorFrontendHost.copyText(commands);
Blink Reformat4c46d092018-04-07 15:32:371320 }
1321
1322 /**
1323 * @param {!SDK.NetworkRequest} request
1324 */
1325 async _copyPowerShellCommand(request) {
1326 const command = await this._generatePowerShellCommand(request);
1327 InspectorFrontendHost.copyText(command);
1328 }
1329
1330 async _copyAllPowerShellCommand() {
Harley Libcf41f92018-09-10 18:01:131331 const commands = this._generateAllPowerShellCommand(SDK.networkLog.requests());
1332 InspectorFrontendHost.copyText(commands);
Blink Reformat4c46d092018-04-07 15:32:371333 }
1334
1335 async _exportAll() {
1336 const url = SDK.targetManager.mainTarget().inspectedURL();
1337 const parsedURL = url.asParsedURL();
1338 const filename = parsedURL ? parsedURL.host : 'network-log';
1339 const stream = new Bindings.FileOutputStream();
1340
1341 if (!await stream.open(filename + '.har'))
1342 return;
1343
1344 const progressIndicator = new UI.ProgressIndicator();
1345 this._progressBarContainer.appendChild(progressIndicator.element);
1346 await Network.HARWriter.write(stream, this._harRequests(), progressIndicator);
1347 progressIndicator.done();
1348 stream.close();
1349 }
1350
1351 _clearBrowserCache() {
1352 if (confirm(Common.UIString('Are you sure you want to clear browser cache?')))
1353 SDK.multitargetNetworkManager.clearBrowserCache();
1354 }
1355
1356 _clearBrowserCookies() {
1357 if (confirm(Common.UIString('Are you sure you want to clear browser cookies?')))
1358 SDK.multitargetNetworkManager.clearBrowserCookies();
1359 }
1360
1361 _removeAllHighlights() {
1362 this.removeAllNodeHighlights();
1363 for (let i = 0; i < this._highlightedSubstringChanges.length; ++i)
1364 UI.revertDomChanges(this._highlightedSubstringChanges[i]);
1365 this._highlightedSubstringChanges = [];
1366 }
1367
1368 /**
1369 * @param {!Network.NetworkRequestNode} node
1370 * @return {boolean}
1371 */
1372 _applyFilter(node) {
1373 const request = node.request();
1374 if (this._timeFilter && !this._timeFilter(request))
1375 return false;
1376 const categoryName = request.resourceType().category().title;
1377 if (!this._resourceCategoryFilterUI.accept(categoryName))
1378 return false;
Joey Arharba99d622019-02-01 19:10:481379 if (this._dataURLFilterUI.checked() && (request.parsedURL.isDataURL() || request.parsedURL.isBlobURL()))
Blink Reformat4c46d092018-04-07 15:32:371380 return false;
1381 if (request.statusText === 'Service Worker Fallback Required')
1382 return false;
1383 for (let i = 0; i < this._filters.length; ++i) {
1384 if (!this._filters[i](request))
1385 return false;
1386 }
1387 return true;
1388 }
1389
1390 /**
1391 * @param {string} query
1392 */
1393 _parseFilterQuery(query) {
1394 const descriptors = this._filterParser.parse(query);
1395 this._filters = descriptors.map(descriptor => {
1396 const key = descriptor.key;
1397 const text = descriptor.text || '';
1398 const regex = descriptor.regex;
1399 let filter;
1400 if (key) {
1401 const defaultText = (key + ':' + text).escapeForRegExp();
1402 filter = this._createSpecialFilter(/** @type {!Network.NetworkLogView.FilterType} */ (key), text) ||
1403 Network.NetworkLogView._requestPathFilter.bind(null, new RegExp(defaultText, 'i'));
1404 } else if (descriptor.regex) {
1405 filter = Network.NetworkLogView._requestPathFilter.bind(null, /** @type {!RegExp} */ (regex));
1406 } else {
1407 filter = Network.NetworkLogView._requestPathFilter.bind(null, new RegExp(text.escapeForRegExp(), 'i'));
1408 }
1409 return descriptor.negative ? Network.NetworkLogView._negativeFilter.bind(null, filter) : filter;
1410 });
1411 }
1412
1413 /**
1414 * @param {!Network.NetworkLogView.FilterType} type
1415 * @param {string} value
1416 * @return {?Network.NetworkLogView.Filter}
1417 */
1418 _createSpecialFilter(type, value) {
1419 switch (type) {
1420 case Network.NetworkLogView.FilterType.Domain:
1421 return Network.NetworkLogView._createRequestDomainFilter(value);
1422
1423 case Network.NetworkLogView.FilterType.HasResponseHeader:
1424 return Network.NetworkLogView._requestResponseHeaderFilter.bind(null, value);
1425
1426 case Network.NetworkLogView.FilterType.Is:
1427 if (value.toLowerCase() === Network.NetworkLogView.IsFilterType.Running)
1428 return Network.NetworkLogView._runningRequestFilter;
1429 if (value.toLowerCase() === Network.NetworkLogView.IsFilterType.FromCache)
1430 return Network.NetworkLogView._fromCacheRequestFilter;
Joey Arhard183e7e2019-02-28 03:37:051431 if (value.toLowerCase() === Network.NetworkLogView.IsFilterType.ServiceWorkerIntercepted)
1432 return Network.NetworkLogView._interceptedByServiceWorkerFilter;
1433 if (value.toLowerCase() === Network.NetworkLogView.IsFilterType.ServiceWorkerInitiated)
1434 return Network.NetworkLogView._initiatedByServiceWorkerFilter;
Blink Reformat4c46d092018-04-07 15:32:371435 break;
1436
1437 case Network.NetworkLogView.FilterType.LargerThan:
1438 return this._createSizeFilter(value.toLowerCase());
1439
1440 case Network.NetworkLogView.FilterType.Method:
1441 return Network.NetworkLogView._requestMethodFilter.bind(null, value);
1442
1443 case Network.NetworkLogView.FilterType.MimeType:
1444 return Network.NetworkLogView._requestMimeTypeFilter.bind(null, value);
1445
1446 case Network.NetworkLogView.FilterType.MixedContent:
1447 return Network.NetworkLogView._requestMixedContentFilter.bind(
1448 null, /** @type {!Network.NetworkLogView.MixedContentFilterValues} */ (value));
1449
1450 case Network.NetworkLogView.FilterType.Scheme:
1451 return Network.NetworkLogView._requestSchemeFilter.bind(null, value);
1452
1453 case Network.NetworkLogView.FilterType.SetCookieDomain:
1454 return Network.NetworkLogView._requestSetCookieDomainFilter.bind(null, value);
1455
1456 case Network.NetworkLogView.FilterType.SetCookieName:
1457 return Network.NetworkLogView._requestSetCookieNameFilter.bind(null, value);
1458
1459 case Network.NetworkLogView.FilterType.SetCookieValue:
1460 return Network.NetworkLogView._requestSetCookieValueFilter.bind(null, value);
1461
1462 case Network.NetworkLogView.FilterType.Priority:
1463 return Network.NetworkLogView._requestPriorityFilter.bind(null, PerfUI.uiLabelToNetworkPriority(value));
1464
1465 case Network.NetworkLogView.FilterType.StatusCode:
1466 return Network.NetworkLogView._statusCodeFilter.bind(null, value);
1467 }
1468 return null;
1469 }
1470
1471 /**
1472 * @param {string} value
1473 * @return {?Network.NetworkLogView.Filter}
1474 */
1475 _createSizeFilter(value) {
1476 let multiplier = 1;
1477 if (value.endsWith('k')) {
1478 multiplier = 1024;
1479 value = value.substring(0, value.length - 1);
1480 } else if (value.endsWith('m')) {
1481 multiplier = 1024 * 1024;
1482 value = value.substring(0, value.length - 1);
1483 }
1484 const quantity = Number(value);
1485 if (isNaN(quantity))
1486 return null;
1487 return Network.NetworkLogView._requestSizeLargerThanFilter.bind(null, quantity * multiplier);
1488 }
1489
1490 _filterRequests() {
1491 this._removeAllHighlights();
1492 this._invalidateAllItems();
1493 }
1494
1495 /**
1496 * @param {!SDK.NetworkRequest} request
1497 * @return {?Network.NetworkRequestNode}
1498 */
1499 _reveal(request) {
1500 this.removeAllNodeHighlights();
1501 const node = request[Network.NetworkLogView._networkNodeSymbol];
1502 if (!node || !node.dataGrid)
1503 return null;
1504 node.reveal();
1505 return node;
1506 }
1507
1508 /**
1509 * @param {!SDK.NetworkRequest} request
1510 */
1511 revealAndHighlightRequest(request) {
1512 const node = this._reveal(request);
1513 if (node)
1514 this._highlightNode(node);
1515 }
1516
1517 /**
1518 * @param {!SDK.NetworkRequest} request
1519 */
1520 selectRequest(request) {
Eugene Ostroukhovb600f662018-05-09 00:18:141521 this.setTextFilterValue('');
Blink Reformat4c46d092018-04-07 15:32:371522 const node = this._reveal(request);
1523 if (node)
1524 node.select();
1525 }
1526
1527 removeAllNodeHighlights() {
1528 if (this._highlightedNode) {
1529 this._highlightedNode.element().classList.remove('highlighted-row');
1530 this._highlightedNode = null;
1531 }
1532 }
1533
1534 /**
1535 * @param {!Network.NetworkRequestNode} node
1536 */
1537 _highlightNode(node) {
1538 UI.runCSSAnimationOnce(node.element(), 'highlighted-row');
1539 this._highlightedNode = node;
1540 }
1541
1542 /**
Harley Libcf41f92018-09-10 18:01:131543 * @param {!Array<!SDK.NetworkRequest>} requests
1544 * @return {!Array<!SDK.NetworkRequest>}
1545 */
1546 _filterOutBlobRequests(requests) {
1547 return requests.filter(request => !request.isBlobRequest());
1548 }
1549
1550 /**
Blink Reformat4c46d092018-04-07 15:32:371551 * @param {!SDK.NetworkRequest} request
1552 * @return {!Promise<string>}
1553 */
1554 async _generateFetchCall(request) {
1555 const ignoredHeaders = {
1556 // Internal headers
1557 'method': 1,
1558 'path': 1,
1559 'scheme': 1,
1560 'version': 1,
1561
1562 // Unsafe headers
1563 // Keep this list synchronized with src/net/http/http_util.cc
1564 'accept-charset': 1,
1565 'accept-encoding': 1,
1566 'access-control-request-headers': 1,
1567 'access-control-request-method': 1,
1568 'connection': 1,
1569 'content-length': 1,
1570 'cookie': 1,
1571 'cookie2': 1,
1572 'date': 1,
1573 'dnt': 1,
1574 'expect': 1,
1575 'host': 1,
1576 'keep-alive': 1,
1577 'origin': 1,
1578 'referer': 1,
1579 'te': 1,
1580 'trailer': 1,
1581 'transfer-encoding': 1,
1582 'upgrade': 1,
1583 'via': 1,
1584 // TODO(phistuck) - remove this once crbug.com/571722 is fixed.
1585 'user-agent': 1
1586 };
1587
1588 const credentialHeaders = {'cookie': 1, 'authorization': 1};
1589
1590 const url = JSON.stringify(request.url());
1591
1592 const requestHeaders = request.requestHeaders();
1593 const headerData = requestHeaders.reduce((result, header) => {
1594 const name = header.name;
1595
1596 if (!ignoredHeaders[name.toLowerCase()] && !name.includes(':'))
1597 result.append(name, header.value);
1598
1599 return result;
1600 }, new Headers());
1601
1602 const headers = {};
1603 for (const headerArray of headerData)
PhistucK6ed0a3e2018-08-04 06:28:411604 headers[headerArray[0]] = headerArray[1];
Blink Reformat4c46d092018-04-07 15:32:371605
1606 const credentials =
1607 request.requestCookies || requestHeaders.some(({name}) => credentialHeaders[name.toLowerCase()]) ? 'include' :
1608 'omit';
1609
1610 const referrerHeader = requestHeaders.find(({name}) => name.toLowerCase() === 'referer');
1611
1612 const referrer = referrerHeader ? referrerHeader.value : void 0;
1613
1614 const referrerPolicy = request.referrerPolicy() || void 0;
1615
1616 const requestBody = await request.requestFormData();
1617
1618 const fetchOptions = {
1619 credentials,
PhistucK6ed0a3e2018-08-04 06:28:411620 headers: Object.keys(headers).length ? headers : void 0,
Blink Reformat4c46d092018-04-07 15:32:371621 referrer,
1622 referrerPolicy,
1623 body: requestBody,
1624 method: request.requestMethod,
1625 mode: 'cors'
1626 };
1627
1628 const options = JSON.stringify(fetchOptions);
1629 return `fetch(${url}, ${options});`;
1630 }
1631
1632 /**
Harley Libcf41f92018-09-10 18:01:131633 * @param {!Array<!SDK.NetworkRequest>} requests
1634 * @return {!Promise<string>}
1635 */
1636 async _generateAllFetchCall(requests) {
1637 const nonBlobRequests = this._filterOutBlobRequests(requests);
1638 const commands = await Promise.all(nonBlobRequests.map(request => this._generateFetchCall(request)));
1639 return commands.join(' ;\n');
1640 }
1641
1642 /**
Blink Reformat4c46d092018-04-07 15:32:371643 * @param {!SDK.NetworkRequest} request
1644 * @param {string} platform
1645 * @return {!Promise<string>}
1646 */
1647 async _generateCurlCommand(request, platform) {
1648 let command = ['curl'];
1649 // These headers are derived from URL (except "version") and would be added by cURL anyway.
1650 const ignoredHeaders = {'host': 1, 'method': 1, 'path': 1, 'scheme': 1, 'version': 1};
1651
1652 function escapeStringWin(str) {
1653 /* If there are no new line characters do not escape the " characters
1654 since it only uglifies the command.
1655
1656 Because cmd.exe parser and MS Crt arguments parsers use some of the
1657 same escape characters, they can interact with each other in
1658 horrible ways, the order of operations is critical.
1659
1660 Replace \ with \\ first because it is an escape character for certain
1661 conditions in both parsers.
1662
1663 Replace all " with \" to ensure the first parser does not remove it.
1664
1665 Then escape all characters we are not sure about with ^ to ensure it
1666 gets to MS Crt parser safely.
1667
1668 The % character is special because MS Crt parser will try and look for
1669 ENV variables and fill them in it's place. We cannot escape them with %
1670 and cannot escape them with ^ (because it's cmd.exe's escape not MS Crt
1671 parser); So we can get cmd.exe parser to escape the character after it,
1672 if it is followed by a valid beginning character of an ENV variable.
1673 This ensures we do not try and double escape another ^ if it was placed
1674 by the previous replace.
1675
1676 Lastly we replace new lines with ^ and TWO new lines because the first
1677 new line is there to enact the escape command the second is the character
1678 to escape (in this case new line).
1679 */
1680 const encapsChars = /[\r\n]/.test(str) ? '^"' : '"';
1681 return encapsChars +
1682 str.replace(/\\/g, '\\\\')
1683 .replace(/"/g, '\\"')
1684 .replace(/[^a-zA-Z0-9\s_\-:=+~'\/.',?;()*`]/g, '^$&')
1685 .replace(/%(?=[a-zA-Z0-9_])/g, '%^')
1686 .replace(/\r\n|[\n\r]/g, '^\n\n') +
1687 encapsChars;
1688 }
1689
1690 /**
1691 * @param {string} str
1692 * @return {string}
1693 */
1694 function escapeStringPosix(str) {
1695 /**
1696 * @param {string} x
1697 * @return {string}
1698 */
1699 function escapeCharacter(x) {
Erik Luoaa676752018-08-21 05:52:221700 const code = x.charCodeAt(0);
1701 // Add leading zero when needed to not care about the next character.
1702 return code < 16 ? '\\u0' + code.toString(16) : '\\u' + code.toString(16);
Blink Reformat4c46d092018-04-07 15:32:371703 }
1704
Joey Arhar512e3742019-01-25 21:33:541705 if (/[\u0000-\u001f\u007f-\u009f!]|\'/.test(str)) {
Blink Reformat4c46d092018-04-07 15:32:371706 // Use ANSI-C quoting syntax.
1707 return '$\'' +
1708 str.replace(/\\/g, '\\\\')
1709 .replace(/\'/g, '\\\'')
1710 .replace(/\n/g, '\\n')
1711 .replace(/\r/g, '\\r')
Joey Arhar512e3742019-01-25 21:33:541712 .replace(/[\u0000-\u001f\u007f-\u009f!]/g, escapeCharacter) +
Blink Reformat4c46d092018-04-07 15:32:371713 '\'';
1714 } else {
1715 // Use single quote syntax.
1716 return '\'' + str + '\'';
1717 }
1718 }
1719
1720 // cURL command expected to run on the same platform that DevTools run
1721 // (it may be different from the inspected page platform).
1722 const escapeString = platform === 'win' ? escapeStringWin : escapeStringPosix;
1723
1724 command.push(escapeString(request.url()).replace(/[[{}\]]/g, '\\$&'));
1725
1726 let inferredMethod = 'GET';
1727 const data = [];
1728 const requestContentType = request.requestContentType();
1729 const formData = await request.requestFormData();
1730 if (requestContentType && requestContentType.startsWith('application/x-www-form-urlencoded') && formData) {
1731 data.push('--data');
1732 data.push(escapeString(formData));
1733 ignoredHeaders['content-length'] = true;
1734 inferredMethod = 'POST';
1735 } else if (formData) {
1736 data.push('--data-binary');
1737 data.push(escapeString(formData));
1738 ignoredHeaders['content-length'] = true;
1739 inferredMethod = 'POST';
1740 }
1741
1742 if (request.requestMethod !== inferredMethod) {
1743 command.push('-X');
1744 command.push(request.requestMethod);
1745 }
1746
1747 const requestHeaders = request.requestHeaders();
1748 for (let i = 0; i < requestHeaders.length; i++) {
1749 const header = requestHeaders[i];
1750 const name = header.name.replace(/^:/, ''); // Translate SPDY v3 headers to HTTP headers.
1751 if (name.toLowerCase() in ignoredHeaders)
1752 continue;
1753 command.push('-H');
1754 command.push(escapeString(name + ': ' + header.value));
1755 }
1756 command = command.concat(data);
1757 command.push('--compressed');
1758
1759 if (request.securityState() === Protocol.Security.SecurityState.Insecure)
1760 command.push('--insecure');
1761 return command.join(' ');
1762 }
1763
1764 /**
Harley Libcf41f92018-09-10 18:01:131765 * @param {!Array<!SDK.NetworkRequest>} requests
1766 * @param {string} platform
1767 * @return {!Promise<string>}
1768 */
1769 async _generateAllCurlCommand(requests, platform) {
1770 const nonBlobRequests = this._filterOutBlobRequests(requests);
1771 const commands = await Promise.all(nonBlobRequests.map(request => this._generateCurlCommand(request, platform)));
1772 if (platform === 'win')
1773 return commands.join(' &\r\n');
1774 else
1775 return commands.join(' ;\n');
1776 }
1777
1778 /**
Blink Reformat4c46d092018-04-07 15:32:371779 * @param {!SDK.NetworkRequest} request
1780 * @return {!Promise<string>}
1781 */
1782 async _generatePowerShellCommand(request) {
1783 const command = ['Invoke-WebRequest'];
1784 const ignoredHeaders =
1785 new Set(['host', 'connection', 'proxy-connection', 'content-length', 'expect', 'range', 'content-type']);
1786
1787 /**
1788 * @param {string} str
1789 * @return {string}
1790 */
1791 function escapeString(str) {
1792 return '"' +
1793 str.replace(/[`\$"]/g, '`$&').replace(/[^\x20-\x7E]/g, char => '$([char]' + char.charCodeAt(0) + ')') + '"';
1794 }
1795
1796 command.push('-Uri');
1797 command.push(escapeString(request.url()));
1798
1799 if (request.requestMethod !== 'GET') {
1800 command.push('-Method');
1801 command.push(escapeString(request.requestMethod));
1802 }
1803
1804 const requestHeaders = request.requestHeaders();
1805 const headerNameValuePairs = [];
1806 for (const header of requestHeaders) {
1807 const name = header.name.replace(/^:/, ''); // Translate h2 headers to HTTP headers.
1808 if (ignoredHeaders.has(name.toLowerCase()))
1809 continue;
1810 headerNameValuePairs.push(escapeString(name) + '=' + escapeString(header.value));
1811 }
1812 if (headerNameValuePairs.length) {
1813 command.push('-Headers');
1814 command.push('@{' + headerNameValuePairs.join('; ') + '}');
1815 }
1816
1817 const contentTypeHeader = requestHeaders.find(({name}) => name.toLowerCase() === 'content-type');
1818 if (contentTypeHeader) {
1819 command.push('-ContentType');
1820 command.push(escapeString(contentTypeHeader.value));
1821 }
1822
1823 const formData = await request.requestFormData();
1824 if (formData) {
1825 command.push('-Body');
1826 const body = escapeString(formData);
1827 if (/[^\x20-\x7E]/.test(formData))
1828 command.push('([System.Text.Encoding]::UTF8.GetBytes(' + body + '))');
1829 else
1830 command.push(body);
1831 }
1832
1833 return command.join(' ');
1834 }
Harley Libcf41f92018-09-10 18:01:131835
1836 /**
1837 * @param {!Array<!SDK.NetworkRequest>} requests
1838 * @return {!Promise<string>}
1839 */
1840 async _generateAllPowerShellCommand(requests) {
1841 const nonBlobRequests = this._filterOutBlobRequests(requests);
1842 const commands = await Promise.all(nonBlobRequests.map(request => this._generatePowerShellCommand(request)));
1843 return commands.join(';\r\n');
1844 }
Blink Reformat4c46d092018-04-07 15:32:371845};
1846
1847Network.NetworkLogView._isFilteredOutSymbol = Symbol('isFilteredOut');
1848Network.NetworkLogView._networkNodeSymbol = Symbol('NetworkNode');
1849
1850Network.NetworkLogView.HTTPSchemas = {
1851 'http': true,
1852 'https': true,
1853 'ws': true,
1854 'wss': true
1855};
1856
1857/** @enum {symbol} */
1858Network.NetworkLogView.Events = {
1859 RequestSelected: Symbol('RequestSelected')
1860};
1861
1862/** @enum {string} */
1863Network.NetworkLogView.FilterType = {
1864 Domain: 'domain',
1865 HasResponseHeader: 'has-response-header',
1866 Is: 'is',
1867 LargerThan: 'larger-than',
1868 Method: 'method',
1869 MimeType: 'mime-type',
1870 MixedContent: 'mixed-content',
1871 Priority: 'priority',
1872 Scheme: 'scheme',
1873 SetCookieDomain: 'set-cookie-domain',
1874 SetCookieName: 'set-cookie-name',
1875 SetCookieValue: 'set-cookie-value',
1876 StatusCode: 'status-code'
1877};
1878
1879/** @enum {string} */
1880Network.NetworkLogView.MixedContentFilterValues = {
1881 All: 'all',
1882 Displayed: 'displayed',
1883 Blocked: 'blocked',
1884 BlockOverridden: 'block-overridden'
1885};
1886
1887/** @enum {string} */
1888Network.NetworkLogView.IsFilterType = {
1889 Running: 'running',
Joey Arhard183e7e2019-02-28 03:37:051890 FromCache: 'from-cache',
1891 ServiceWorkerIntercepted: 'service-worker-intercepted',
1892 ServiceWorkerInitiated: 'service-worker-initiated'
Blink Reformat4c46d092018-04-07 15:32:371893};
1894
1895/** @type {!Array<string>} */
1896Network.NetworkLogView._searchKeys =
1897 Object.keys(Network.NetworkLogView.FilterType).map(key => Network.NetworkLogView.FilterType[key]);
1898
1899/** @typedef {function(!SDK.NetworkRequest): boolean} */
1900Network.NetworkLogView.Filter;
1901
1902/**
1903 * @interface
1904 */
1905Network.GroupLookupInterface = function() {};
1906
1907Network.GroupLookupInterface.prototype = {
1908 /**
1909 * @param {!SDK.NetworkRequest} request
1910 * @return {?Network.NetworkGroupNode}
1911 */
1912 groupNodeForRequest: function(request) {},
1913
1914 reset: function() {}
1915};