UNPKG

chrome-devtools-frontend

Version:
168 lines (151 loc) • 5.91 kB
// Copyright 2018 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import type * as Common from '../../core/common/common.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 Logs from '../../models/logs/logs.js'; import type * as TextUtils from '../../models/text_utils/text_utils.js'; import type * as Search from '../search/search.js'; import * as NetworkForward from '../../panels/network/forward/forward.js'; const UIStrings = { /** *@description Text for web URLs */ url: 'URL', }; const str_ = i18n.i18n.registerUIStrings('panels/network/NetworkSearchScope.ts', UIStrings); const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_); export class NetworkSearchScope implements Search.SearchConfig.SearchScope { performIndexing(progress: Common.Progress.Progress): void { queueMicrotask(() => { progress.done(); }); } async performSearch( searchConfig: Search.SearchConfig.SearchConfig, progress: Common.Progress.Progress, searchResultCallback: (arg0: Search.SearchConfig.SearchResult) => void, searchFinishedCallback: (arg0: boolean) => void): Promise<void> { const promises = []; const requests = Logs.NetworkLog.NetworkLog.instance().requests().filter( request => searchConfig.filePathMatchesFileQuery(request.url())); progress.setTotalWork(requests.length); for (const request of requests) { const promise = this.searchRequest(searchConfig, request, progress); promises.push(promise); } const resultsWithNull = await Promise.all(promises); const results = (resultsWithNull.filter(result => result !== null) as NetworkSearchResult[]); if (progress.isCanceled()) { searchFinishedCallback(false); return; } for (const result of results.sort((r1, r2) => r1.label().localeCompare(r2.label()))) { if (result.matchesCount() > 0) { searchResultCallback(result); } } progress.done(); searchFinishedCallback(true); } private async searchRequest( searchConfig: Search.SearchConfig.SearchConfig, request: SDK.NetworkRequest.NetworkRequest, progress: Common.Progress.Progress): Promise<NetworkSearchResult|null> { let bodyMatches: TextUtils.ContentProvider.SearchMatch[] = []; if (request.contentType().isTextType()) { bodyMatches = await request.searchInContent(searchConfig.query(), !searchConfig.ignoreCase(), searchConfig.isRegex()); } if (progress.isCanceled()) { return null; } const locations = []; if (stringMatchesQuery(request.url())) { locations.push(NetworkForward.UIRequestLocation.UIRequestLocation.urlMatch(request)); } for (const header of request.requestHeaders()) { if (headerMatchesQuery(header)) { locations.push(NetworkForward.UIRequestLocation.UIRequestLocation.requestHeaderMatch(request, header)); } } for (const header of request.responseHeaders) { if (headerMatchesQuery(header)) { locations.push(NetworkForward.UIRequestLocation.UIRequestLocation.responseHeaderMatch(request, header)); } } for (const match of bodyMatches) { locations.push(NetworkForward.UIRequestLocation.UIRequestLocation.bodyMatch(request, match)); } progress.incrementWorked(); return new NetworkSearchResult(request, locations); function headerMatchesQuery(header: SDK.NetworkRequest.NameValue): boolean { return stringMatchesQuery(`${header.name}: ${header.value}`); } function stringMatchesQuery(string: string): boolean { const flags = searchConfig.ignoreCase() ? 'i' : ''; const regExps = searchConfig.queries().map(query => new RegExp(Platform.StringUtilities.escapeForRegExp(query), flags)); let pos = 0; for (const regExp of regExps) { const match = string.substr(pos).match(regExp); if (!match || match.index === undefined) { return false; } pos += match.index + match[0].length; } return true; } } stopSearch(): void { } } export class NetworkSearchResult implements Search.SearchConfig.SearchResult { private readonly request: SDK.NetworkRequest.NetworkRequest; private readonly locations: NetworkForward.UIRequestLocation.UIRequestLocation[]; constructor( request: SDK.NetworkRequest.NetworkRequest, locations: NetworkForward.UIRequestLocation.UIRequestLocation[]) { this.request = request; this.locations = locations; } matchesCount(): number { return this.locations.length; } label(): string { return this.request.displayName; } description(): string { const parsedUrl = this.request.parsedURL; if (!parsedUrl) { return this.request.url(); } return parsedUrl.urlWithoutScheme(); } matchLineContent(index: number): string { const location = this.locations[index]; if (location.isUrlMatch) { return this.request.url(); } const header = location?.header?.header; if (header) { return header.value; } return (location.searchMatch as TextUtils.ContentProvider.SearchMatch).lineContent; } matchRevealable(index: number): Object { return this.locations[index]; } matchLabel(index: number): string { const location = this.locations[index]; if (location.isUrlMatch) { return i18nString(UIStrings.url); } const header = location?.header?.header; if (header) { return `${header.name}:`; } // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration) // @ts-expect-error return (location.searchMatch as TextUtils.ContentProvider.SearchMatch).lineNumber + 1; } }