UNPKG

chrome-devtools-frontend

Version:
313 lines (282 loc) • 14.4 kB
// Copyright 2011 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import * as Common from '../../core/common/common.js'; import * as i18n from '../../core/i18n/i18n.js'; import * as SDK from '../../core/sdk/sdk.js'; import * as Protocol from '../../generated/protocol.js'; import * as uiI18n from '../../ui/i18n/i18n.js'; import * as CookieTable from '../../ui/legacy/components/cookie_table/cookie_table.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 requestCookiesViewStyles from './requestCookiesView.css.js'; const {render, html} = Lit; const UIStrings = { /** * @description Text in Request Cookies View of the Network panel */ thisRequestHasNoCookies: 'This request has no cookies.', /** * @description Title for a table which shows all of the cookies associated with a selected network * request, in the Network panel. Noun phrase. */ requestCookies: 'Request Cookies', /** * @description Tooltip to explain what request cookies are */ cookiesThatWereSentToTheServerIn: 'Cookies that were sent to the server in the \'cookie\' header of the request', /** * @description Label for showing request cookies that were not actually sent */ showFilteredOutRequestCookies: 'show filtered out request cookies', /** * @description Text in Request Headers View of the Network Panel */ noRequestCookiesWereSent: 'No request cookies were sent.', /** * @description Text in Request Cookies View of the Network panel */ responseCookies: 'Response Cookies', /** * @description Tooltip to explain what response cookies are */ cookiesThatWereReceivedFromThe: 'Cookies that were received from the server in the \'`set-cookie`\' header of the response', /** * @description Label for response cookies with invalid syntax */ malformedResponseCookies: 'Malformed Response Cookies', /** * @description Tooltip to explain what malformed response cookies are. Malformed cookies are * cookies that did not match the expected format and could not be interpreted, and are invalid. */ cookiesThatWereReceivedFromTheServer: 'Cookies that were received from the server in the \'`set-cookie`\' header of the response but were malformed', /** * @description Informational text to explain that there were other cookies * that were not used and not shown in the list. * @example {Learn more} PH1 * */ siteHasCookieInOtherPartition: 'This site has cookies in another partition, that were not sent with this request. {PH1}', /** * @description Title of a link to the developer documentation. */ learnMore: 'Learn more', } as const; const str_ = i18n.i18n.registerUIStrings('panels/network/RequestCookiesView.ts', UIStrings); const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_); interface ViewInput { requestCookies: CookieTable.CookiesTable.CookiesTableData; responseCookies: CookieTable.CookiesTable.CookiesTableData; malformedResponseCookies: SDK.NetworkRequest.BlockedSetCookieWithReason[]; showFilteredOutCookies: boolean; hasBlockedCookies: boolean; gotCookies: boolean; onShowFilteredOutCookiesChange: (checked: boolean) => void; siteHasCookieInOtherPartition: boolean; } type ViewFunction = (input: ViewInput, output: undefined, target: HTMLElement) => void; export const DEFAULT_VIEW: ViewFunction = (input, _output, target) => { // clang-format off render( html` <style>${requestCookiesViewStyles}</style> <style>${UI.inspectorCommonStyles}</style> <div class="request-cookies-view"> ${input.gotCookies ? Lit.nothing : html` <devtools-widget .widgetConfig=${UI.Widget.widgetConfig(UI.EmptyWidget.EmptyWidget, { header: i18nString(UIStrings.thisRequestHasNoCookies)})}></devtools-widget> `} <div class=${input.requestCookies.cookies.length || input.hasBlockedCookies ? '' : 'hidden'}> <span class="request-cookies-title" title=${i18nString(UIStrings.cookiesThatWereSentToTheServerIn)}> ${i18nString(UIStrings.requestCookies)} </span> <devtools-checkbox @change=${(e: Event) => input.onShowFilteredOutCookiesChange((e.target as HTMLInputElement).checked)} .checked=${input.showFilteredOutCookies}> ${i18nString(UIStrings.showFilteredOutRequestCookies)} </devtools-checkbox> </div> <div class="cookies-panel-item ${!input.requestCookies.cookies.length && input.hasBlockedCookies ? '' : 'hidden'}"> ${i18nString(UIStrings.noRequestCookiesWereSent)} </div> ${input.requestCookies.cookies.length > 0 ? html` <devtools-widget .widgetConfig=${UI.Widget.widgetConfig(CookieTable.CookiesTable.CookiesTable, { cookiesData: input.requestCookies, inline: true })} class="cookie-table cookies-panel-item"></devtools-widget> ` : Lit.nothing} <div class="cookies-panel-item site-has-cookies-in-other-partition ${input.siteHasCookieInOtherPartition ? '' : 'hidden'}"> ${uiI18n.getFormatLocalizedString(str_, UIStrings.siteHasCookieInOtherPartition, { PH1: UI.XLink.XLink.create( 'https://developer.chrome.com/en/docs/privacy-sandbox/chips/', i18nString(UIStrings.learnMore), undefined, undefined, 'learn-more'),})} </div> <div class="request-cookies-title ${input.responseCookies.cookies.length ? '' : 'hidden'}" title=${i18nString(UIStrings.cookiesThatWereReceivedFromThe)}> ${i18nString(UIStrings.responseCookies)} </div> ${input.responseCookies.cookies.length ? html` <devtools-widget .widgetConfig=${UI.Widget.widgetConfig(CookieTable.CookiesTable.CookiesTable, { cookiesData: input.responseCookies, inline: true })} class="cookie-table cookies-panel-item"></devtools-widget> ` : Lit.nothing} <div class="request-cookies-title ${input.malformedResponseCookies.length ? '' : 'hidden'}" title=${i18nString(UIStrings.cookiesThatWereReceivedFromTheServer)}> ${i18nString(UIStrings.malformedResponseCookies)} </div> <div class=${input.malformedResponseCookies.length ? '' : 'hidden'}> ${input.malformedResponseCookies.map(malformedCookie => html` <span class="cookie-line source-code" title=${getMalformedCookieTooltip(malformedCookie)}> <devtools-icon class="cookie-warning-icon small" .name=${'cross-circle-filled'}></devtools-icon> ${malformedCookie.cookieLine} </span> `)} </div> </div> `, target); // clang-format on }; function getMalformedCookieTooltip(malformedCookie: SDK.NetworkRequest.BlockedSetCookieWithReason): string { if (malformedCookie.blockedReasons.includes(Protocol.Network.SetCookieBlockedReason.NameValuePairExceedsMaxSize)) { return SDK.NetworkRequest.setCookieBlockedReasonToUiString( Protocol.Network.SetCookieBlockedReason.NameValuePairExceedsMaxSize); } return SDK.NetworkRequest.setCookieBlockedReasonToUiString(Protocol.Network.SetCookieBlockedReason.SyntaxError); } export class RequestCookiesView extends UI.Widget.Widget { private request: SDK.NetworkRequest.NetworkRequest; private readonly showFilteredOutCookiesSetting: Common.Settings.Setting<boolean>; private readonly view: ViewFunction; constructor(request: SDK.NetworkRequest.NetworkRequest, view: ViewFunction = DEFAULT_VIEW) { super({jslog: `${VisualLogging.pane('cookies').track({resize: true})}`}); this.request = request; this.showFilteredOutCookiesSetting = Common.Settings.Settings.instance().createSetting( 'show-filtered-out-request-cookies', /* defaultValue */ false); this.view = view; } private getRequestCookies(): { requestCookies: SDK.Cookie.Cookie[], requestCookieToBlockedReasons: Map<SDK.Cookie.Cookie, SDK.CookieModel.BlockedReason[]>, requestCookieToExemptionReason: Map<SDK.Cookie.Cookie, SDK.CookieModel.ExemptionReason>, } { const requestCookieToBlockedReasons = new Map<SDK.Cookie.Cookie, SDK.CookieModel.BlockedReason[]>(); const requestCookieToExemptionReason = new Map<SDK.Cookie.Cookie, SDK.CookieModel.ExemptionReason>(); const requestCookies = this.request.includedRequestCookies().map(includedRequestCookie => includedRequestCookie.cookie); if (this.showFilteredOutCookiesSetting.get()) { for (const blockedCookie of this.request.blockedRequestCookies()) { requestCookieToBlockedReasons.set(blockedCookie.cookie, blockedCookie.blockedReasons.map(blockedReason => { return { attribute: SDK.NetworkRequest.cookieBlockedReasonToAttribute(blockedReason), uiString: SDK.NetworkRequest.cookieBlockedReasonToUiString(blockedReason), }; })); requestCookies.push(blockedCookie.cookie); } } for (const includedCookie of this.request.includedRequestCookies()) { if (includedCookie.exemptionReason) { requestCookieToExemptionReason.set(includedCookie.cookie, { uiString: SDK.NetworkRequest.cookieExemptionReasonToUiString(includedCookie.exemptionReason), }); } } return {requestCookies, requestCookieToBlockedReasons, requestCookieToExemptionReason}; } private getResponseCookies(): { responseCookies: SDK.Cookie.Cookie[], responseCookieToBlockedReasons: Map<SDK.Cookie.Cookie, SDK.CookieModel.BlockedReason[]>, responseCookieToExemptionReason: Map<SDK.Cookie.Cookie, SDK.CookieModel.ExemptionReason>, malformedResponseCookies: SDK.NetworkRequest.BlockedSetCookieWithReason[], } { let responseCookies: SDK.Cookie.Cookie[] = []; const responseCookieToBlockedReasons = new Map<SDK.Cookie.Cookie, SDK.CookieModel.BlockedReason[]>(); const responseCookieToExemptionReason = new Map<SDK.Cookie.Cookie, SDK.CookieModel.ExemptionReason>(); const malformedResponseCookies: SDK.NetworkRequest.BlockedSetCookieWithReason[] = []; if (this.request.responseCookies.length) { responseCookies = this.request.nonBlockedResponseCookies(); for (const blockedCookie of this.request.blockedResponseCookies()) { const parsedCookies = SDK.CookieParser.CookieParser.parseSetCookie(blockedCookie.cookieLine); if ((parsedCookies && !parsedCookies.length) || blockedCookie.blockedReasons.includes(Protocol.Network.SetCookieBlockedReason.SyntaxError) || blockedCookie.blockedReasons.includes( Protocol.Network.SetCookieBlockedReason.NameValuePairExceedsMaxSize)) { malformedResponseCookies.push(blockedCookie); continue; } let cookie: SDK.Cookie.Cookie|(SDK.Cookie.Cookie | null) = blockedCookie.cookie; if (!cookie && parsedCookies) { cookie = parsedCookies[0]; } if (cookie) { responseCookieToBlockedReasons.set(cookie, blockedCookie.blockedReasons.map(blockedReason => { return { attribute: SDK.NetworkRequest.setCookieBlockedReasonToAttribute(blockedReason), uiString: SDK.NetworkRequest.setCookieBlockedReasonToUiString(blockedReason), }; })); responseCookies.push(cookie); } } for (const exemptedCookie of this.request.exemptedResponseCookies()) { // `responseCookies` are generated from `Set-Cookie` header, which should include the exempted cookies, whereas // exempted cookies are received via CDP as objects of type cookie. Therefore they are different objects in // DevTools and need to be matched here in order for the rendering logic to be able to lookup a potential // exemption reason for a cookie. const matchedResponseCookie = responseCookies.find(responseCookie => exemptedCookie.cookieLine === responseCookie.getCookieLine()); if (matchedResponseCookie) { responseCookieToExemptionReason.set(matchedResponseCookie, { uiString: SDK.NetworkRequest.cookieExemptionReasonToUiString(exemptedCookie.exemptionReason), }); } } } return {responseCookies, responseCookieToBlockedReasons, responseCookieToExemptionReason, malformedResponseCookies}; } override performUpdate(): void { if (!this.isShowing()) { return; } const {requestCookies, requestCookieToBlockedReasons, requestCookieToExemptionReason} = this.getRequestCookies(); const {responseCookies, responseCookieToBlockedReasons, responseCookieToExemptionReason, malformedResponseCookies} = this.getResponseCookies(); const input: ViewInput = { gotCookies: this.request.hasRequestCookies() || this.request.responseCookies.length > 0, requestCookies: { cookies: requestCookies, cookieToBlockedReasons: requestCookieToBlockedReasons, cookieToExemptionReason: requestCookieToExemptionReason, }, responseCookies: { cookies: responseCookies, cookieToBlockedReasons: responseCookieToBlockedReasons, cookieToExemptionReason: responseCookieToExemptionReason, }, malformedResponseCookies, showFilteredOutCookies: this.showFilteredOutCookiesSetting.get(), onShowFilteredOutCookiesChange: (checked: boolean) => { this.showFilteredOutCookiesSetting.set(checked); this.requestUpdate(); }, siteHasCookieInOtherPartition: this.request.siteHasCookieInOtherPartition(), hasBlockedCookies: this.request.blockedRequestCookies().length > 0, }; this.view(input, undefined, this.contentElement); } override wasShown(): void { super.wasShown(); this.request.addEventListener(SDK.NetworkRequest.Events.REQUEST_HEADERS_CHANGED, this.requestUpdate, this); this.request.addEventListener(SDK.NetworkRequest.Events.RESPONSE_HEADERS_CHANGED, this.requestUpdate, this); this.requestUpdate(); } override willHide(): void { super.willHide(); this.request.removeEventListener(SDK.NetworkRequest.Events.REQUEST_HEADERS_CHANGED, this.requestUpdate, this); this.request.removeEventListener(SDK.NetworkRequest.Events.RESPONSE_HEADERS_CHANGED, this.requestUpdate, this); } }