| // Copyright 2022 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import '../../../ui/kit/kit.js'; |
| |
| import * as i18n from '../../../core/i18n/i18n.js'; |
| import * as Platform from '../../../core/platform/platform.js'; |
| import type * as SDK from '../../../core/sdk/sdk.js'; |
| import * as UI from '../../../ui/legacy/legacy.js'; |
| import * as Lit from '../../../ui/lit/lit.js'; |
| import * as VisualLogging from '../../../ui/visual_logging/visual_logging.js'; |
| import * as NetworkForward from '../forward/forward.js'; |
| |
| import {EditingAllowedStatus, type HeaderDescriptor} from './HeaderSectionRow.js'; |
| import requestHeaderSectionStyles from './RequestHeaderSection.css.js'; |
| import requestHeadersViewStyles from './RequestHeadersView.css.js'; |
| |
| export {requestHeadersViewStyles}; |
| |
| const {render, html} = Lit; |
| |
| const UIStrings = { |
| /** |
| * @description Text that is usually a hyperlink to more documentation |
| */ |
| learnMore: 'Learn more', |
| /** |
| * @description Message to explain lack of raw headers for a particular network request |
| */ |
| provisionalHeadersAreShownDisableCache: 'Provisional headers are shown. Disable cache to see full headers.', |
| /** |
| * @description Tooltip to explain lack of raw headers for a particular network request |
| */ |
| onlyProvisionalHeadersAre: |
| 'Only provisional headers are available because this request was not sent over the network and instead was served from a local cache, which doesn’t store the original request headers. Disable cache to see full request headers.', |
| /** |
| * @description Message to explain lack of raw headers for a particular network request |
| */ |
| provisionalHeadersAreShown: 'Provisional headers are shown.', |
| } as const; |
| |
| const str_ = i18n.i18n.registerUIStrings('panels/network/components/RequestHeaderSection.ts', UIStrings); |
| const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_); |
| |
| export interface ViewInput { |
| headers: HeaderDescriptor[]; |
| isProvisionalHeaders: boolean; |
| isRequestCached: boolean; |
| } |
| |
| export type View = (input: ViewInput, output: undefined, target: HTMLElement|ShadowRoot) => void; |
| |
| export const DEFAULT_VIEW: View = (input, output, target) => { |
| const headers = input.headers; |
| |
| // Disabled until https://crbug.com/1079231 is fixed. |
| // clang-format off |
| render(html` |
| <style>${requestHeaderSectionStyles}</style> |
| ${input.isProvisionalHeaders ? renderProvisionalHeadersWarning(input.isRequestCached) : Lit.nothing} |
| ${headers.map(header => html` |
| <devtools-header-section-row |
| .data=${{ header }} |
| jslog=${VisualLogging.item('request-header')} |
| ></devtools-header-section-row> |
| `)} |
| `, target); |
| // clang-format on |
| }; |
| |
| function renderProvisionalHeadersWarning(isRequestCached: boolean): Lit.LitTemplate { |
| let cautionText; |
| let cautionTitle = ''; |
| if (isRequestCached) { |
| cautionText = i18nString(UIStrings.provisionalHeadersAreShownDisableCache); |
| cautionTitle = i18nString(UIStrings.onlyProvisionalHeadersAre); |
| } else { |
| cautionText = i18nString(UIStrings.provisionalHeadersAreShown); |
| } |
| // Disabled until https://crbug.com/1079231 is fixed. |
| // clang-format off |
| return html` |
| <div class="call-to-action"> |
| <div class="call-to-action-body"> |
| <div class="explanation" title=${cautionTitle}> |
| <devtools-icon class="inline-icon medium" name='warning-filled'> |
| </devtools-icon> |
| ${cautionText} <devtools-link href="https://developer.chrome.com/docs/devtools/network/reference/#provisional-headers" class="link">${i18nString(UIStrings.learnMore)}</devtools-link> |
| </div> |
| </div> |
| </div> |
| `; |
| // clang-format on |
| } |
| |
| export class RequestHeaderSection extends UI.Widget.Widget { |
| #request: Readonly<SDK.NetworkRequest.NetworkRequest>|null = null; |
| #headers: HeaderDescriptor[] = []; |
| #view: View; |
| |
| constructor(element?: HTMLElement, view: View = DEFAULT_VIEW) { |
| super(element, {useShadowDom: true}); |
| this.#view = view; |
| } |
| |
| set toReveal(toReveal: {section: NetworkForward.UIRequestLocation.UIHeaderSection, header?: string}|undefined) { |
| if (!toReveal) { |
| return; |
| } |
| if (toReveal.section === NetworkForward.UIRequestLocation.UIHeaderSection.REQUEST) { |
| this.#headers.filter(header => header.name === toReveal.header?.toLowerCase()).forEach(header => { |
| header.highlight = true; |
| }); |
| } |
| |
| this.requestUpdate(); |
| } |
| |
| set request(request: Readonly<SDK.NetworkRequest.NetworkRequest>) { |
| this.#request = request; |
| this.#headers = this.#request.requestHeaders().map(header => ({ |
| name: Platform.StringUtilities.toLowerCaseString(header.name), |
| value: header.value, |
| valueEditable: EditingAllowedStatus.FORBIDDEN, |
| })); |
| this.#headers.sort((a, b) => Platform.StringUtilities.compare(a.name, b.name)); |
| this.requestUpdate(); |
| } |
| |
| override performUpdate(): void { |
| if (!this.#request) { |
| return; |
| } |
| this.#view( |
| { |
| headers: this.#headers, |
| isProvisionalHeaders: this.#request.requestHeadersText() === undefined, |
| isRequestCached: this.#request.cached() || this.#request.cachedInMemory(), |
| }, |
| undefined, this.contentElement); |
| } |
| } |