mirror of
https://github.com/react/react-native-devtools-frontend.git
synced 2026-10-10 21:54:47 +08:00
This incorporats with dgozman's comments in crrev.com/c/1004890 - Change "from SignedExchange" to "from signed-exchange" in NetworkRequestNode. - Show the signed exchagne url as the initiator of certificate request. - Show "from signed-exchange" in the headers tab of the inner request. - Add "View request" link in the preview tab of signed exchange to show the inner request. - Add "Learn more" link in the preview tab of signed exchange. Bug: 830505 Change-Id: Ica7ae52e563efb283c600c812be196951a12a336 Reviewed-on: https://chromium-review.googlesource.com/1065558 Commit-Queue: Tsuyoshi Horo <horo@chromium.org> Reviewed-by: Dmitry Gozman <dgozman@chromium.org> Reviewed-by: Kunihiko Sakamoto <ksakamoto@chromium.org> Cr-Original-Commit-Position: refs/heads/master@{#560287} Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src Cr-Mirrored-Commit: 4ac04d63b06db0e81a986691346f67ba8ad7f865
607 lines
22 KiB
JavaScript
607 lines
22 KiB
JavaScript
/*
|
|
* Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
|
|
* Copyright (C) IBM Corp. 2009 All rights reserved.
|
|
* Copyright (C) 2010 Google Inc. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
|
|
* its contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
|
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
Network.RequestHeadersView = class extends UI.VBox {
|
|
/**
|
|
* @param {!SDK.NetworkRequest} request
|
|
*/
|
|
constructor(request) {
|
|
super();
|
|
this.registerRequiredCSS('network/requestHeadersView.css');
|
|
this.element.classList.add('request-headers-view');
|
|
|
|
this._request = request;
|
|
this._decodeRequestParameters = true;
|
|
this._showRequestHeadersText = false;
|
|
this._showResponseHeadersText = false;
|
|
|
|
/** @type {?UI.TreeElement} */
|
|
this._highlightedElement = null;
|
|
|
|
const root = new UI.TreeOutlineInShadow();
|
|
root.registerRequiredCSS('network/requestHeadersTree.css');
|
|
root.element.classList.add('request-headers-tree');
|
|
root.setFocusable(false);
|
|
root.makeDense();
|
|
root.expandTreeElementsWhenArrowing = true;
|
|
this.element.appendChild(root.element);
|
|
|
|
const generalCategory = new Network.RequestHeadersView.Category(root, 'general', Common.UIString('General'));
|
|
generalCategory.hidden = false;
|
|
this._urlItem = generalCategory.createLeaf();
|
|
this._requestMethodItem = generalCategory.createLeaf();
|
|
this._statusCodeItem = generalCategory.createLeaf();
|
|
this._remoteAddressItem = generalCategory.createLeaf();
|
|
this._remoteAddressItem.hidden = true;
|
|
this._referrerPolicyItem = generalCategory.createLeaf();
|
|
this._referrerPolicyItem.hidden = true;
|
|
|
|
this._responseHeadersCategory = new Network.RequestHeadersView.Category(root, 'responseHeaders', '');
|
|
this._requestHeadersCategory = new Network.RequestHeadersView.Category(root, 'requestHeaders', '');
|
|
this._queryStringCategory = new Network.RequestHeadersView.Category(root, 'queryString', '');
|
|
this._formDataCategory = new Network.RequestHeadersView.Category(root, 'formData', '');
|
|
this._requestPayloadCategory =
|
|
new Network.RequestHeadersView.Category(root, 'requestPayload', Common.UIString('Request Payload'));
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
*/
|
|
wasShown() {
|
|
this._clearHighlight();
|
|
this._request.addEventListener(SDK.NetworkRequest.Events.RemoteAddressChanged, this._refreshRemoteAddress, this);
|
|
this._request.addEventListener(SDK.NetworkRequest.Events.RequestHeadersChanged, this._refreshRequestHeaders, this);
|
|
this._request.addEventListener(
|
|
SDK.NetworkRequest.Events.ResponseHeadersChanged, this._refreshResponseHeaders, this);
|
|
this._request.addEventListener(SDK.NetworkRequest.Events.FinishedLoading, this._refreshHTTPInformation, this);
|
|
|
|
this._refreshURL();
|
|
this._refreshQueryString();
|
|
this._refreshRequestHeaders();
|
|
this._refreshResponseHeaders();
|
|
this._refreshHTTPInformation();
|
|
this._refreshRemoteAddress();
|
|
this._refreshReferrerPolicy();
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
*/
|
|
willHide() {
|
|
this._request.removeEventListener(SDK.NetworkRequest.Events.RemoteAddressChanged, this._refreshRemoteAddress, this);
|
|
this._request.removeEventListener(
|
|
SDK.NetworkRequest.Events.RequestHeadersChanged, this._refreshRequestHeaders, this);
|
|
this._request.removeEventListener(
|
|
SDK.NetworkRequest.Events.ResponseHeadersChanged, this._refreshResponseHeaders, this);
|
|
this._request.removeEventListener(SDK.NetworkRequest.Events.FinishedLoading, this._refreshHTTPInformation, this);
|
|
}
|
|
|
|
/**
|
|
* @param {string} name
|
|
* @param {string} value
|
|
* @return {!DocumentFragment}
|
|
*/
|
|
_formatHeader(name, value) {
|
|
const fragment = createDocumentFragment();
|
|
fragment.createChild('div', 'header-name').textContent = name + ': ';
|
|
fragment.createChild('span', 'header-separator');
|
|
fragment.createChild('div', 'header-value source-code').textContent = value;
|
|
|
|
return fragment;
|
|
}
|
|
|
|
/**
|
|
* @param {string} value
|
|
* @param {string} className
|
|
* @param {boolean} decodeParameters
|
|
* @return {!Element}
|
|
*/
|
|
_formatParameter(value, className, decodeParameters) {
|
|
let errorDecoding = false;
|
|
|
|
if (decodeParameters) {
|
|
value = value.replace(/\+/g, ' ');
|
|
if (value.indexOf('%') >= 0) {
|
|
try {
|
|
value = decodeURIComponent(value);
|
|
} catch (e) {
|
|
errorDecoding = true;
|
|
}
|
|
}
|
|
}
|
|
const div = createElementWithClass('div', className);
|
|
if (value === '')
|
|
div.classList.add('empty-value');
|
|
if (errorDecoding)
|
|
div.createChild('span', 'header-decode-error').textContent = Common.UIString('(unable to decode value)');
|
|
else
|
|
div.textContent = value;
|
|
return div;
|
|
}
|
|
|
|
_refreshURL() {
|
|
this._urlItem.title = this._formatHeader(Common.UIString('Request URL'), this._request.url());
|
|
}
|
|
|
|
_refreshQueryString() {
|
|
const queryString = this._request.queryString();
|
|
const queryParameters = this._request.queryParameters;
|
|
this._queryStringCategory.hidden = !queryParameters;
|
|
if (queryParameters) {
|
|
this._refreshParams(
|
|
Common.UIString('Query String Parameters'), queryParameters, queryString, this._queryStringCategory);
|
|
}
|
|
}
|
|
|
|
async _refreshFormData() {
|
|
this._formDataCategory.hidden = true;
|
|
this._requestPayloadCategory.hidden = true;
|
|
|
|
const formData = await this._request.requestFormData();
|
|
if (!formData)
|
|
return;
|
|
|
|
const formParameters = await this._request.formParameters();
|
|
if (formParameters) {
|
|
this._formDataCategory.hidden = false;
|
|
this._refreshParams(Common.UIString('Form Data'), formParameters, formData, this._formDataCategory);
|
|
} else {
|
|
this._requestPayloadCategory.hidden = false;
|
|
try {
|
|
const json = JSON.parse(formData);
|
|
this._refreshRequestJSONPayload(json, formData);
|
|
} catch (e) {
|
|
this._populateTreeElementWithSourceText(this._requestPayloadCategory, formData);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {!UI.TreeElement} treeElement
|
|
* @param {?string} sourceText
|
|
*/
|
|
_populateTreeElementWithSourceText(treeElement, sourceText) {
|
|
const max_len = 3000;
|
|
const text = (sourceText || '').trim();
|
|
const trim = text.length > max_len;
|
|
|
|
const sourceTextElement = createElementWithClass('span', 'header-value source-code');
|
|
sourceTextElement.textContent = trim ? text.substr(0, max_len) : text;
|
|
|
|
const sourceTreeElement = new UI.TreeElement(sourceTextElement);
|
|
sourceTreeElement.selectable = false;
|
|
treeElement.removeChildren();
|
|
treeElement.appendChild(sourceTreeElement);
|
|
if (!trim)
|
|
return;
|
|
|
|
const showMoreButton = createElementWithClass('button', 'request-headers-show-more-button');
|
|
showMoreButton.textContent = Common.UIString('Show more');
|
|
showMoreButton.addEventListener('click', () => {
|
|
showMoreButton.remove();
|
|
sourceTextElement.textContent = text;
|
|
});
|
|
sourceTextElement.appendChild(showMoreButton);
|
|
}
|
|
|
|
/**
|
|
* @param {string} title
|
|
* @param {?Array.<!SDK.NetworkRequest.NameValue>} params
|
|
* @param {?string} sourceText
|
|
* @param {!UI.TreeElement} paramsTreeElement
|
|
*/
|
|
_refreshParams(title, params, sourceText, paramsTreeElement) {
|
|
paramsTreeElement.removeChildren();
|
|
|
|
paramsTreeElement.listItemElement.removeChildren();
|
|
paramsTreeElement.listItemElement.createTextChild(title);
|
|
|
|
const headerCount = createElementWithClass('span', 'header-count');
|
|
headerCount.textContent = Common.UIString('\u00A0(%d)', params.length);
|
|
paramsTreeElement.listItemElement.appendChild(headerCount);
|
|
|
|
/**
|
|
* @param {!Event} event
|
|
* @this {Network.RequestHeadersView}
|
|
*/
|
|
function toggleViewSource(event) {
|
|
paramsTreeElement[Network.RequestHeadersView._viewSourceSymbol] =
|
|
!paramsTreeElement[Network.RequestHeadersView._viewSourceSymbol];
|
|
this._refreshParams(title, params, sourceText, paramsTreeElement);
|
|
event.consume();
|
|
}
|
|
|
|
paramsTreeElement.listItemElement.appendChild(this._createViewSourceToggle(
|
|
paramsTreeElement[Network.RequestHeadersView._viewSourceSymbol], toggleViewSource.bind(this)));
|
|
|
|
if (paramsTreeElement[Network.RequestHeadersView._viewSourceSymbol]) {
|
|
this._populateTreeElementWithSourceText(paramsTreeElement, sourceText);
|
|
return;
|
|
}
|
|
|
|
const toggleTitle =
|
|
this._decodeRequestParameters ? Common.UIString('view URL encoded') : Common.UIString('view decoded');
|
|
const toggleButton = this._createToggleButton(toggleTitle);
|
|
toggleButton.addEventListener('click', this._toggleURLDecoding.bind(this), false);
|
|
paramsTreeElement.listItemElement.appendChild(toggleButton);
|
|
|
|
for (let i = 0; i < params.length; ++i) {
|
|
const paramNameValue = createDocumentFragment();
|
|
if (params[i].name !== '') {
|
|
const name = this._formatParameter(params[i].name + ': ', 'header-name', this._decodeRequestParameters);
|
|
const value = this._formatParameter(params[i].value, 'header-value source-code', this._decodeRequestParameters);
|
|
paramNameValue.appendChild(name);
|
|
paramNameValue.createChild('span', 'header-separator');
|
|
paramNameValue.appendChild(value);
|
|
} else {
|
|
paramNameValue.appendChild(
|
|
this._formatParameter(Common.UIString('(empty)'), 'empty-request-header', this._decodeRequestParameters));
|
|
}
|
|
|
|
const paramTreeElement = new UI.TreeElement(paramNameValue);
|
|
paramTreeElement.selectable = false;
|
|
paramsTreeElement.appendChild(paramTreeElement);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {*} parsedObject
|
|
* @param {string} sourceText
|
|
*/
|
|
_refreshRequestJSONPayload(parsedObject, sourceText) {
|
|
const treeElement = this._requestPayloadCategory;
|
|
treeElement.removeChildren();
|
|
|
|
const listItem = this._requestPayloadCategory.listItemElement;
|
|
listItem.removeChildren();
|
|
listItem.createTextChild(this._requestPayloadCategory.title);
|
|
|
|
/**
|
|
* @param {!Event} event
|
|
* @this {Network.RequestHeadersView}
|
|
*/
|
|
function toggleViewSource(event) {
|
|
treeElement[Network.RequestHeadersView._viewSourceSymbol] =
|
|
!treeElement[Network.RequestHeadersView._viewSourceSymbol];
|
|
this._refreshRequestJSONPayload(parsedObject, sourceText);
|
|
event.consume();
|
|
}
|
|
|
|
listItem.appendChild(this._createViewSourceToggle(
|
|
treeElement[Network.RequestHeadersView._viewSourceSymbol], toggleViewSource.bind(this)));
|
|
if (treeElement[Network.RequestHeadersView._viewSourceSymbol]) {
|
|
this._populateTreeElementWithSourceText(this._requestPayloadCategory, sourceText);
|
|
} else {
|
|
const object = SDK.RemoteObject.fromLocalObject(parsedObject);
|
|
const section = new ObjectUI.ObjectPropertiesSection(object, object.description);
|
|
section.expand();
|
|
section.editable = false;
|
|
treeElement.appendChild(new UI.TreeElement(section.element));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {boolean} viewSource
|
|
* @param {function(!Event)} handler
|
|
* @return {!Element}
|
|
*/
|
|
_createViewSourceToggle(viewSource, handler) {
|
|
const viewSourceToggleTitle = viewSource ? Common.UIString('view parsed') : Common.UIString('view source');
|
|
const viewSourceToggleButton = this._createToggleButton(viewSourceToggleTitle);
|
|
viewSourceToggleButton.addEventListener('click', handler, false);
|
|
return viewSourceToggleButton;
|
|
}
|
|
|
|
/**
|
|
* @param {!Event} event
|
|
*/
|
|
_toggleURLDecoding(event) {
|
|
this._decodeRequestParameters = !this._decodeRequestParameters;
|
|
this._refreshQueryString();
|
|
this._refreshFormData();
|
|
event.consume();
|
|
}
|
|
|
|
_refreshRequestHeaders() {
|
|
const treeElement = this._requestHeadersCategory;
|
|
const headers = this._request.requestHeaders().slice();
|
|
headers.sort(function(a, b) {
|
|
return a.name.toLowerCase().compareTo(b.name.toLowerCase());
|
|
});
|
|
const headersText = this._request.requestHeadersText();
|
|
|
|
if (this._showRequestHeadersText && headersText)
|
|
this._refreshHeadersText(Common.UIString('Request Headers'), headers.length, headersText, treeElement);
|
|
else
|
|
this._refreshHeaders(Common.UIString('Request Headers'), headers, treeElement, headersText === undefined);
|
|
|
|
if (headersText) {
|
|
const toggleButton = this._createHeadersToggleButton(this._showRequestHeadersText);
|
|
toggleButton.addEventListener('click', this._toggleRequestHeadersText.bind(this), false);
|
|
treeElement.listItemElement.appendChild(toggleButton);
|
|
}
|
|
|
|
this._refreshFormData();
|
|
}
|
|
|
|
_refreshResponseHeaders() {
|
|
const treeElement = this._responseHeadersCategory;
|
|
const headers = this._request.sortedResponseHeaders.slice();
|
|
const headersText = this._request.responseHeadersText;
|
|
|
|
if (this._showResponseHeadersText)
|
|
this._refreshHeadersText(Common.UIString('Response Headers'), headers.length, headersText, treeElement);
|
|
else
|
|
this._refreshHeaders(Common.UIString('Response Headers'), headers, treeElement);
|
|
|
|
if (headersText) {
|
|
const toggleButton = this._createHeadersToggleButton(this._showResponseHeadersText);
|
|
toggleButton.addEventListener('click', this._toggleResponseHeadersText.bind(this), false);
|
|
treeElement.listItemElement.appendChild(toggleButton);
|
|
}
|
|
}
|
|
|
|
_refreshHTTPInformation() {
|
|
const requestMethodElement = this._requestMethodItem;
|
|
requestMethodElement.hidden = !this._request.statusCode;
|
|
const statusCodeElement = this._statusCodeItem;
|
|
statusCodeElement.hidden = !this._request.statusCode;
|
|
|
|
if (this._request.statusCode) {
|
|
const statusCodeFragment = createDocumentFragment();
|
|
statusCodeFragment.createChild('div', 'header-name').textContent = Common.UIString('Status Code') + ': ';
|
|
statusCodeFragment.createChild('span', 'header-separator');
|
|
|
|
const statusCodeImage = statusCodeFragment.createChild('label', 'resource-status-image', 'dt-icon-label');
|
|
statusCodeImage.title = this._request.statusCode + ' ' + this._request.statusText;
|
|
|
|
if (this._request.statusCode < 300 || this._request.statusCode === 304)
|
|
statusCodeImage.type = 'smallicon-green-ball';
|
|
else if (this._request.statusCode < 400)
|
|
statusCodeImage.type = 'smallicon-orange-ball';
|
|
else
|
|
statusCodeImage.type = 'smallicon-red-ball';
|
|
|
|
requestMethodElement.title = this._formatHeader(Common.UIString('Request Method'), this._request.requestMethod);
|
|
|
|
const statusTextElement = statusCodeFragment.createChild('div', 'header-value source-code');
|
|
let statusText = this._request.statusCode + ' ' + this._request.statusText;
|
|
if (this._request.fetchedViaServiceWorker) {
|
|
statusText += ' ' + Common.UIString('(from ServiceWorker)');
|
|
statusTextElement.classList.add('status-from-cache');
|
|
} else if (this._request.redirectSource() && this._request.redirectSource().signedExchangeInfo()) {
|
|
statusText += ' ' + Common.UIString('(from signed-exchange)');
|
|
statusTextElement.classList.add('status-from-cache');
|
|
} else if (this._request.cached()) {
|
|
if (this._request.cachedInMemory())
|
|
statusText += ' ' + Common.UIString('(from memory cache)');
|
|
else
|
|
statusText += ' ' + Common.UIString('(from disk cache)');
|
|
statusTextElement.classList.add('status-from-cache');
|
|
}
|
|
statusTextElement.textContent = statusText;
|
|
|
|
statusCodeElement.title = statusCodeFragment;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {string} title
|
|
* @param {!UI.TreeElement} headersTreeElement
|
|
* @param {number} headersLength
|
|
*/
|
|
_refreshHeadersTitle(title, headersTreeElement, headersLength) {
|
|
headersTreeElement.listItemElement.removeChildren();
|
|
headersTreeElement.listItemElement.createTextChild(title);
|
|
|
|
const headerCount = Common.UIString('\u00A0(%d)', headersLength);
|
|
headersTreeElement.listItemElement.createChild('span', 'header-count').textContent = headerCount;
|
|
}
|
|
|
|
/**
|
|
* @param {string} title
|
|
* @param {!Array.<!SDK.NetworkRequest.NameValue>} headers
|
|
* @param {!UI.TreeElement} headersTreeElement
|
|
* @param {boolean=} provisionalHeaders
|
|
*/
|
|
_refreshHeaders(title, headers, headersTreeElement, provisionalHeaders) {
|
|
headersTreeElement.removeChildren();
|
|
|
|
const length = headers.length;
|
|
this._refreshHeadersTitle(title, headersTreeElement, length);
|
|
|
|
if (provisionalHeaders) {
|
|
const cautionText = Common.UIString('Provisional headers are shown');
|
|
const cautionFragment = createDocumentFragment();
|
|
cautionFragment.createChild('label', '', 'dt-icon-label').type = 'smallicon-warning';
|
|
cautionFragment.createChild('div', 'caution').textContent = cautionText;
|
|
const cautionTreeElement = new UI.TreeElement(cautionFragment);
|
|
cautionTreeElement.selectable = false;
|
|
headersTreeElement.appendChild(cautionTreeElement);
|
|
}
|
|
|
|
headersTreeElement.hidden = !length && !provisionalHeaders;
|
|
for (let i = 0; i < length; ++i) {
|
|
const headerTreeElement = new UI.TreeElement(this._formatHeader(headers[i].name, headers[i].value));
|
|
headerTreeElement.selectable = false;
|
|
headersTreeElement.appendChild(headerTreeElement);
|
|
headerTreeElement[Network.RequestHeadersView._headerNameSymbol] = headers[i].name;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {string} title
|
|
* @param {number} count
|
|
* @param {string} headersText
|
|
* @param {!UI.TreeElement} headersTreeElement
|
|
*/
|
|
_refreshHeadersText(title, count, headersText, headersTreeElement) {
|
|
this._populateTreeElementWithSourceText(headersTreeElement, headersText);
|
|
this._refreshHeadersTitle(title, headersTreeElement, count);
|
|
}
|
|
|
|
_refreshRemoteAddress() {
|
|
const remoteAddress = this._request.remoteAddress();
|
|
const treeElement = this._remoteAddressItem;
|
|
treeElement.hidden = !remoteAddress;
|
|
if (remoteAddress)
|
|
treeElement.title = this._formatHeader(Common.UIString('Remote Address'), remoteAddress);
|
|
}
|
|
|
|
_refreshReferrerPolicy() {
|
|
const referrerPolicy = this._request.referrerPolicy();
|
|
const treeElement = this._referrerPolicyItem;
|
|
treeElement.hidden = !referrerPolicy;
|
|
if (referrerPolicy)
|
|
treeElement.title = this._formatHeader(Common.UIString('Referrer Policy'), referrerPolicy);
|
|
}
|
|
|
|
/**
|
|
* @param {!Event} event
|
|
*/
|
|
_toggleRequestHeadersText(event) {
|
|
this._showRequestHeadersText = !this._showRequestHeadersText;
|
|
this._refreshRequestHeaders();
|
|
event.consume();
|
|
}
|
|
|
|
/**
|
|
* @param {!Event} event
|
|
*/
|
|
_toggleResponseHeadersText(event) {
|
|
this._showResponseHeadersText = !this._showResponseHeadersText;
|
|
this._refreshResponseHeaders();
|
|
event.consume();
|
|
}
|
|
|
|
/**
|
|
* @param {string} title
|
|
* @return {!Element}
|
|
*/
|
|
_createToggleButton(title) {
|
|
const button = createElementWithClass('span', 'header-toggle');
|
|
button.textContent = title;
|
|
return button;
|
|
}
|
|
|
|
/**
|
|
* @param {boolean} isHeadersTextShown
|
|
* @return {!Element}
|
|
*/
|
|
_createHeadersToggleButton(isHeadersTextShown) {
|
|
const toggleTitle = isHeadersTextShown ? Common.UIString('view parsed') : Common.UIString('view source');
|
|
return this._createToggleButton(toggleTitle);
|
|
}
|
|
|
|
_clearHighlight() {
|
|
if (this._highlightedElement)
|
|
this._highlightedElement.listItemElement.classList.remove('header-highlight');
|
|
this._highlightedElement = null;
|
|
}
|
|
|
|
|
|
/**
|
|
* @param {?UI.TreeElement} category
|
|
* @param {string} name
|
|
*/
|
|
_revealAndHighlight(category, name) {
|
|
this._clearHighlight();
|
|
for (const element of category.children()) {
|
|
if (element[Network.RequestHeadersView._headerNameSymbol] !== name)
|
|
continue;
|
|
this._highlightedElement = element;
|
|
element.reveal();
|
|
element.listItemElement.classList.add('header-highlight');
|
|
return;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {string} header
|
|
*/
|
|
revealRequestHeader(header) {
|
|
this._revealAndHighlight(this._requestHeadersCategory, header);
|
|
}
|
|
|
|
/**
|
|
* @param {string} header
|
|
*/
|
|
revealResponseHeader(header) {
|
|
this._revealAndHighlight(this._responseHeadersCategory, header);
|
|
}
|
|
};
|
|
|
|
Network.RequestHeadersView._headerNameSymbol = Symbol('HeaderName');
|
|
Network.RequestHeadersView._viewSourceSymbol = Symbol('ViewSource');
|
|
|
|
/**
|
|
* @unrestricted
|
|
*/
|
|
Network.RequestHeadersView.Category = class extends UI.TreeElement {
|
|
/**
|
|
* @param {!UI.TreeOutline} root
|
|
* @param {string} name
|
|
* @param {string=} title
|
|
*/
|
|
constructor(root, name, title) {
|
|
super(title || '', true);
|
|
this.selectable = false;
|
|
this.toggleOnClick = true;
|
|
this.hidden = true;
|
|
this._expandedSetting = Common.settings.createSetting('request-info-' + name + '-category-expanded', true);
|
|
this.expanded = this._expandedSetting.get();
|
|
root.appendChild(this);
|
|
}
|
|
|
|
/**
|
|
* @return {!UI.TreeElement}
|
|
*/
|
|
createLeaf() {
|
|
const leaf = new UI.TreeElement();
|
|
leaf.selectable = false;
|
|
this.appendChild(leaf);
|
|
return leaf;
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
*/
|
|
onexpand() {
|
|
this._expandedSetting.set(true);
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
*/
|
|
oncollapse() {
|
|
this._expandedSetting.set(false);
|
|
}
|
|
};
|