| /* | |
| * 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. | |
| */ | |
| export class RequestHeadersView 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('object_ui/objectValue.css'); | |
| root.registerRequiredCSS('object_ui/objectPropertiesSection.css'); | |
| root.registerRequiredCSS('network/requestHeadersTree.css'); | |
| root.element.classList.add('request-headers-tree'); | |
| root.makeDense(); | |
| this.element.appendChild(root.element); | |
| const generalCategory = new Category(root, 'general', Common.UIString('General')); | |
| generalCategory.hidden = false; | |
| this._root = generalCategory; | |
| 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 Category(root, 'responseHeaders', ''); | |
| this._requestHeadersCategory = new Category(root, 'requestHeaders', ''); | |
| this._queryStringCategory = new Category(root, 'queryString', ''); | |
| this._formDataCategory = new Category(root, 'formData', ''); | |
| this._requestPayloadCategory = new 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(); | |
| this._root.select(/* omitFocus */ true, /* selectedByUser */ false); | |
| } | |
| /** | |
| * @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); | |
| treeElement.removeChildren(); | |
| treeElement.appendChild(sourceTreeElement); | |
| if (!trim) { | |
| return; | |
| } | |
| const showMoreButton = createElementWithClass('button', 'request-headers-show-more-button'); | |
| showMoreButton.textContent = Common.UIString('Show more'); | |
| function showMore() { | |
| showMoreButton.remove(); | |
| sourceTextElement.textContent = text; | |
| sourceTreeElement.listItemElement.removeEventListener('contextmenu', onContextMenuShowMore); | |
| } | |
| showMoreButton.addEventListener('click', showMore); | |
| /** | |
| * @param {!Event} event | |
| */ | |
| function onContextMenuShowMore(event) { | |
| const contextMenu = new UI.ContextMenu(event); | |
| const section = contextMenu.newSection(); | |
| section.appendItem(ls`Show more`, showMore); | |
| contextMenu.show(); | |
| } | |
| sourceTreeElement.listItemElement.addEventListener('contextmenu', onContextMenuShowMore); | |
| 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.createChild('div', 'selection fill'); | |
| paramsTreeElement.listItemElement.createTextChild(title); | |
| const headerCount = createElementWithClass('span', 'header-count'); | |
| headerCount.textContent = Common.UIString('\xA0(%d)', params.length); | |
| paramsTreeElement.listItemElement.appendChild(headerCount); | |
| const shouldViewSource = paramsTreeElement[_viewSourceSymbol]; | |
| if (shouldViewSource) { | |
| this._appendParamsSource(title, params, sourceText, paramsTreeElement); | |
| } else { | |
| this._appendParamsParsed(title, params, sourceText, paramsTreeElement); | |
| } | |
| } | |
| /** | |
| * @param {string} title | |
| * @param {?Array.<!SDK.NetworkRequest.NameValue>} params | |
| * @param {?string} sourceText | |
| * @param {!UI.TreeElement} paramsTreeElement | |
| */ | |
| _appendParamsSource(title, params, sourceText, paramsTreeElement) { | |
| this._populateTreeElementWithSourceText(paramsTreeElement, sourceText); | |
| const listItemElement = paramsTreeElement.listItemElement; | |
| /** | |
| * @param {!Event} event | |
| * @this {RequestHeadersView} | |
| */ | |
| const viewParsed = function(event) { | |
| listItemElement.removeEventListener('contextmenu', viewParsedContextMenu); | |
| paramsTreeElement[_viewSourceSymbol] = false; | |
| this._refreshParams(title, params, sourceText, paramsTreeElement); | |
| event.consume(); | |
| }; | |
| /** | |
| * @param {!Event} event | |
| * @this {RequestHeadersView} | |
| */ | |
| const viewParsedContextMenu = function(event) { | |
| if (!paramsTreeElement.expanded) { | |
| return; | |
| } | |
| const contextMenu = new UI.ContextMenu(event); | |
| contextMenu.newSection().appendItem(ls`View parsed`, viewParsed.bind(this, event)); | |
| contextMenu.show(); | |
| }.bind(this); | |
| const viewParsedButton = this._createViewSourceToggle(/* viewSource */ true, viewParsed.bind(this)); | |
| listItemElement.appendChild(viewParsedButton); | |
| listItemElement.addEventListener('contextmenu', viewParsedContextMenu); | |
| } | |
| /** | |
| * @param {string} title | |
| * @param {?Array.<!SDK.NetworkRequest.NameValue>} params | |
| * @param {?string} sourceText | |
| * @param {!UI.TreeElement} paramsTreeElement | |
| */ | |
| _appendParamsParsed(title, params, sourceText, paramsTreeElement) { | |
| 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); | |
| paramsTreeElement.appendChild(paramTreeElement); | |
| } | |
| const listItemElement = paramsTreeElement.listItemElement; | |
| /** | |
| * @param {!Event} event | |
| * @this {RequestHeadersView} | |
| */ | |
| const viewSource = function(event) { | |
| listItemElement.removeEventListener('contextmenu', viewSourceContextMenu); | |
| paramsTreeElement[_viewSourceSymbol] = true; | |
| this._refreshParams(title, params, sourceText, paramsTreeElement); | |
| event.consume(); | |
| }; | |
| /** | |
| * @param {!Event} event | |
| * @this {RequestHeadersView} | |
| */ | |
| const toggleURLDecoding = function(event) { | |
| listItemElement.removeEventListener('contextmenu', viewSourceContextMenu); | |
| this._toggleURLDecoding(event); | |
| }; | |
| /** | |
| * @param {!Event} event | |
| * @this {RequestHeadersView} | |
| */ | |
| const viewSourceContextMenu = function(event) { | |
| if (!paramsTreeElement.expanded) { | |
| return; | |
| } | |
| const contextMenu = new UI.ContextMenu(event); | |
| const section = contextMenu.newSection(); | |
| section.appendItem(ls`View source`, viewSource.bind(this, event)); | |
| const viewURLEncodedText = this._decodeRequestParameters ? ls`View URL encoded` : ls`View decoded`; | |
| section.appendItem(viewURLEncodedText, toggleURLDecoding.bind(this, event)); | |
| contextMenu.show(); | |
| }.bind(this); | |
| const viewSourceButton = this._createViewSourceToggle(/* viewSource */ false, viewSource.bind(this)); | |
| listItemElement.appendChild(viewSourceButton); | |
| const toggleTitle = this._decodeRequestParameters ? ls`view URL encoded` : ls`view decoded`; | |
| const toggleButton = this._createToggleButton(toggleTitle); | |
| toggleButton.addEventListener('click', toggleURLDecoding.bind(this), false); | |
| listItemElement.appendChild(toggleButton); | |
| listItemElement.addEventListener('contextmenu', viewSourceContextMenu); | |
| } | |
| /** | |
| * @param {*} parsedObject | |
| * @param {string} sourceText | |
| */ | |
| _refreshRequestJSONPayload(parsedObject, sourceText) { | |
| const rootListItem = this._requestPayloadCategory; | |
| rootListItem.removeChildren(); | |
| const rootListItemElement = rootListItem.listItemElement; | |
| rootListItemElement.removeChildren(); | |
| rootListItemElement.createChild('div', 'selection fill'); | |
| rootListItemElement.createTextChild(this._requestPayloadCategory.title); | |
| const shouldViewSource = rootListItem[_viewSourceSymbol]; | |
| if (shouldViewSource) { | |
| this._appendJSONPayloadSource(rootListItem, parsedObject, sourceText); | |
| } else { | |
| this._appendJSONPayloadParsed(rootListItem, parsedObject, sourceText); | |
| } | |
| } | |
| /** | |
| * @param {!Category} rootListItem | |
| * @param {*} parsedObject | |
| * @param {string} sourceText | |
| */ | |
| _appendJSONPayloadSource(rootListItem, parsedObject, sourceText) { | |
| const rootListItemElement = rootListItem.listItemElement; | |
| this._populateTreeElementWithSourceText(rootListItem, sourceText); | |
| /** | |
| * @param {!Event} event | |
| * @this {RequestHeadersView} | |
| */ | |
| const viewParsed = function(event) { | |
| rootListItemElement.removeEventListener('contextmenu', viewParsedContextMenu); | |
| rootListItem[_viewSourceSymbol] = false; | |
| this._refreshRequestJSONPayload(parsedObject, sourceText); | |
| event.consume(); | |
| }; | |
| const viewParsedButton = this._createViewSourceToggle(/* viewSource */ true, viewParsed.bind(this)); | |
| rootListItemElement.appendChild(viewParsedButton); | |
| /** | |
| * @param {!Event} event | |
| * @this {RequestHeadersView} | |
| */ | |
| const viewParsedContextMenu = function(event) { | |
| if (!rootListItem.expanded) { | |
| return; | |
| } | |
| const contextMenu = new UI.ContextMenu(event); | |
| contextMenu.newSection().appendItem(ls`View parsed`, viewParsed.bind(this, event)); | |
| contextMenu.show(); | |
| }.bind(this); | |
| rootListItemElement.addEventListener('contextmenu', viewParsedContextMenu); | |
| } | |
| /** | |
| * @param {!Category} rootListItem | |
| * @param {*} parsedObject | |
| * @param {string} sourceText | |
| */ | |
| _appendJSONPayloadParsed(rootListItem, parsedObject, sourceText) { | |
| const object = /** @type {!SDK.LocalJSONObject} */ (SDK.RemoteObject.fromLocalObject(parsedObject)); | |
| const section = new ObjectUI.ObjectPropertiesSection.RootElement(object); | |
| section.title = object.description; | |
| section.expand(); | |
| section.editable = false; | |
| rootListItem.childrenListElement.classList.add('source-code', 'object-properties-section'); | |
| rootListItem.appendChild(section); | |
| const rootListItemElement = rootListItem.listItemElement; | |
| /** | |
| * @param {!Event} event | |
| * @this {RequestHeadersView} | |
| */ | |
| const viewSource = function(event) { | |
| rootListItemElement.removeEventListener('contextmenu', viewSourceContextMenu); | |
| rootListItem[_viewSourceSymbol] = true; | |
| this._refreshRequestJSONPayload(parsedObject, sourceText); | |
| event.consume(); | |
| }; | |
| /** | |
| * @param {!Event} event | |
| * @this {RequestHeadersView} | |
| */ | |
| const viewSourceContextMenu = function(event) { | |
| if (!rootListItem.expanded) { | |
| return; | |
| } | |
| const contextMenu = new UI.ContextMenu(event); | |
| contextMenu.newSection().appendItem(ls`View source`, viewSource.bind(this, event)); | |
| contextMenu.show(); | |
| }.bind(this); | |
| const viewSourceButton = this._createViewSourceToggle(/* viewSource */ false, viewSource.bind(this)); | |
| rootListItemElement.appendChild(viewSourceButton); | |
| rootListItemElement.addEventListener('contextmenu', viewSourceContextMenu); | |
| } | |
| /** | |
| * @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, /* provisional */ false, | |
| this._request.blockedResponseCookies()); | |
| } | |
| 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 = ls`Status Code` + | |
| ': '; | |
| statusCodeFragment.createChild('span', 'header-separator'); | |
| const statusCodeImage = statusCodeFragment.createChild('span', '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(ls`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.cachedInMemory()) { | |
| statusText += ' ' + ls`(from memory cache)`; | |
| statusTextElement.classList.add('status-from-cache'); | |
| } else if (this._request.fetchedViaServiceWorker) { | |
| statusText += ' ' + ls`(from ServiceWorker)`; | |
| statusTextElement.classList.add('status-from-cache'); | |
| } else if ( | |
| this._request.redirectSource() && this._request.redirectSource().signedExchangeInfo() && | |
| !this._request.redirectSource().signedExchangeInfo().errors) { | |
| statusText += ' ' + ls`(from signed-exchange)`; | |
| statusTextElement.classList.add('status-from-cache'); | |
| } else if (this._request.fromPrefetchCache()) { | |
| statusText += ' ' + ls`(from prefetch cache)`; | |
| statusTextElement.classList.add('status-from-cache'); | |
| } else if (this._request.cached()) { | |
| statusText += ' ' + ls`(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.createChild('div', 'selection fill'); | |
| headersTreeElement.listItemElement.createTextChild(title); | |
| const headerCount = Common.UIString('\xA0(%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 | |
| * @param {!Array<!SDK.NetworkRequest.BlockedSetCookieWithReason>=} blockedResponseCookies | |
| */ | |
| _refreshHeaders(title, headers, headersTreeElement, provisionalHeaders, blockedResponseCookies) { | |
| 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('span', '', 'dt-icon-label').type = 'smallicon-warning'; | |
| cautionFragment.createChild('div', 'caution').textContent = cautionText; | |
| const cautionTreeElement = new UI.TreeElement(cautionFragment); | |
| headersTreeElement.appendChild(cautionTreeElement); | |
| } | |
| /** @type {!Map<string, !Array<!Protocol.Network.SetCookieBlockedReason>>} */ | |
| const blockedCookieLineToReasons = new Map(); | |
| if (blockedResponseCookies) { | |
| blockedResponseCookies.forEach(blockedCookie => { | |
| blockedCookieLineToReasons.set(blockedCookie.cookieLine, blockedCookie.blockedReasons); | |
| }); | |
| } | |
| 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[_headerNameSymbol] = headers[i].name; | |
| if (headers[i].name.toLowerCase() === 'set-cookie') { | |
| const matchingBlockedReasons = blockedCookieLineToReasons.get(headers[i].value); | |
| if (matchingBlockedReasons) { | |
| const icon = UI.Icon.create('smallicon-warning', ''); | |
| headerTreeElement.listItemElement.appendChild(icon); | |
| let titleText = ''; | |
| for (const blockedReason of matchingBlockedReasons) { | |
| if (titleText) { | |
| titleText += '\n'; | |
| } | |
| titleText += SDK.NetworkRequest.setCookieBlockedReasonToUiString(blockedReason); | |
| } | |
| icon.title = titleText; | |
| } | |
| } | |
| headersTreeElement.appendChild(headerTreeElement); | |
| } | |
| } | |
| /** | |
| * @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[_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); | |
| } | |
| } | |
| export const _headerNameSymbol = Symbol('HeaderName'); | |
| export const _viewSourceSymbol = Symbol('ViewSource'); | |
| /** | |
| * @unrestricted | |
| */ | |
| export class Category extends UI.TreeElement { | |
| /** | |
| * @param {!UI.TreeOutline} root | |
| * @param {string} name | |
| * @param {string=} title | |
| */ | |
| constructor(root, name, title) { | |
| super(title || '', true); | |
| 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(); | |
| this.appendChild(leaf); | |
| return leaf; | |
| } | |
| /** | |
| * @override | |
| */ | |
| onexpand() { | |
| this._expandedSetting.set(true); | |
| } | |
| /** | |
| * @override | |
| */ | |
| oncollapse() { | |
| this._expandedSetting.set(false); | |
| } | |
| } | |
| /* Legacy exported object */ | |
| self.Network = self.Network || {}; | |
| /* Legacy exported object */ | |
| Network = Network || {}; | |
| /** | |
| * @constructor | |
| */ | |
| Network.RequestHeadersView = RequestHeadersView; | |
| Network.RequestHeadersView._headerNameSymbol = _headerNameSymbol; | |
| Network.RequestHeadersView._viewSourceSymbol = _viewSourceSymbol; | |
| /** | |
| * @constructor | |
| */ | |
| Network.RequestHeadersView.Category = Category; |