diff --git a/packages/playwright-core/src/server/dispatchers/localUtilsDispatcher.ts b/packages/playwright-core/src/server/dispatchers/localUtilsDispatcher.ts index 958f635a18..84baa133aa 100644 --- a/packages/playwright-core/src/server/dispatchers/localUtilsDispatcher.ts +++ b/packages/playwright-core/src/server/dispatchers/localUtilsDispatcher.ts @@ -24,7 +24,7 @@ import type { DispatcherScope } from './dispatcher'; import { Dispatcher } from './dispatcher'; import { yazl, yauzl } from '../../zipBundle'; import { ZipFile } from '../../utils/zipFile'; -import type { HAREntry, HARFile } from '../../../types/har'; +import type { HAREntry, HARFile, HARHeader } from '../../../types/har'; import type { HeadersArray } from '../types'; export class LocalUtilsDispatcher extends Dispatcher<{ guid: string }, channels.LocalUtilsChannel> implements channels.LocalUtilsChannel { @@ -203,7 +203,7 @@ class HarBackend { if (entries.length > 1) { // Disambiguating requests - // 1. Disambiguate by postData - this covers GraphQL + // 1. Disambiguate using postData - this covers GraphQL if (!entry && postData) { for (const candidate of entries) { if (!candidate.request.postData) @@ -216,12 +216,21 @@ class HarBackend { } } - // TODO: disambiguate by headers. + // Last. Disambiguate using headers - then one with most matching headers wins. + if (!entry) { + const list: { candidate: HAREntry, matchingHeaders: number }[] = []; + for (const candidate of entries) { + const matchingHeaders = countMatchingHeaders(candidate.request.headers, headers); + list.push({ candidate, matchingHeaders }); + } + list.sort((a, b) => b.matchingHeaders - a.matchingHeaders); + entry = list[0].candidate; + } + + } else { + entry = entries[0]; } - // Fall back to first entry. - if (!entry) - entry = entries[0]; if (visited.has(entry)) throw new Error(`Found redirect cycle for ${url}`); @@ -249,3 +258,14 @@ class HarBackend { this._zipFile?.close(); } } + +function countMatchingHeaders(harHeaders: HARHeader[], headers: HeadersArray): number { + const set = new Set(headers.map(h => h.name.toLowerCase() + ':' + h.value)); + let matches = 0; + for (const h of harHeaders) { + if (set.has(h.name.toLowerCase() + ':' + h.value)) + ++matches; + } + return matches; +} +