From a34864a3045b339a4186b7fa24b504e42592ac8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcus=20=C3=96sterberg?= Date: Wed, 15 Jul 2026 16:30:19 +0200 Subject: [PATCH] Only analyze requests belonging to the navigated url's page A browsertime HAR can contain more than one page, for example when a concurrent browsertime run on the same host races for the same Chrome DevTools port and its crossed CDP session records another website's page load into this run's recording (see Webperf-se/webperf_core#1557). This analyzer scanned every entry in the whole HAR, and its first-html-as-primary fallback could pick another website's document, so a crossed-in recording could contaminate the robots.txt, security .txt, sitemap and feed analysis of the tested website. Filter entries to the ones belonging to the first page in the HAR's pages array, and verify that the recording's first request matches the navigated url's hostname (the URL API normalizes IDN hostnames to punycode on both sides). The check is per navigated url, so sitemaps legitimately hosted on another domain keep working. On mismatch nothing is analyzed. HARs without a pages array and entries without pageref behave as before. --- lib/harAnalyzer.js | 43 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/lib/harAnalyzer.js b/lib/harAnalyzer.js index 9cdff66..7074f09 100644 --- a/lib/harAnalyzer.js +++ b/lib/harAnalyzer.js @@ -149,18 +149,51 @@ export class HarAnalyzer { // HAR -> simplified data // --------------------------------------------------------------------------- - transform2SimplifiedData(harData, navUrl) { - const data = { url: navUrl, primary: null, htmls: [] }; - + getFirstPageEntries(navUrl, harData) { let log = harData; if (log && 'log' in log) { log = log.log; } if (!log || !Array.isArray(log.entries)) { - return data; + return []; + } + const entries = log.entries; + + // A HAR can contain more than one page, for example when a concurrent + // browsertime run ends up in the same browser session (crossed DevTools + // port) and navigates to another website mid-recording. Requests made + // by other pages must not be attributed to the tested website, and if + // the recording doesn't even start with the navigated url's host nothing + // in it can be trusted. + if (navUrl && entries.length > 0) { + const firstUrl = entries[0].request && entries[0].request.url; + if (firstUrl) { + try { + if (new URL(firstUrl).hostname !== new URL(navUrl).hostname) { + return []; + } + } catch { + // Unparsable URLs are handled by the entry loops as before + } + } } - for (const entry of log.entries) { + const pages = log.pages; + if (!Array.isArray(pages) || pages.length === 0) { + return entries; + } + const firstPageId = pages[0].id; + if (firstPageId === undefined) { + return entries; + } + return entries.filter(entry => + entry.pageref === undefined || entry.pageref === firstPageId); + } + + transform2SimplifiedData(harData, navUrl) { + const data = { url: navUrl, primary: null, htmls: [] }; + + for (const entry of this.getFirstPageEntries(navUrl, harData)) { const req = entry.request || {}; const res = entry.response || {}; const content = res.content || {};