UNPKG

chrome-devtools-frontend

Version:
60 lines (52 loc) 3.08 kB
// Copyright 2026 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import type * as Handlers from '../handlers/handlers.js'; import type * as Types from '../types/types.js'; import {get as getStackTrace} from './StackTraceForEvent.js'; /** * There are bugs in the backend tracing that means that network requests are * often incorrectly tied to an initiator. This function exists as a utility to * look up an event's initiator regardless of the type of event, but also to * provide a post-parsing fix for network initiators. * The TL;DR is that images injected by a script will incorrectly have their * initiator set to the root document. To fix this, we look at the stack trace * when the request was sent, and use that. */ export function getNetworkInitiator(data: Handlers.Types.HandlerData, event: Types.Events.SyntheticNetworkRequest): Types.Events.SyntheticNetworkRequest|undefined { const networkHandlerInitiator = data.NetworkRequests.incompleteInitiator.get(event); if (networkHandlerInitiator?.args.data.mimeType === 'text/css') { // The bugs in tracing & initiators apply mostly to scripts; we have not // seen a case where the trace events identify a CSS stylesheet as the // initiator that is incorrect. Therefore, if a stylesheet is identified as // the initiator, we trust that it is accurate and can exit early. return networkHandlerInitiator; } // For network requests, it is more reliable to calculate the initiator via // the stack trace if we have one. // We have to use the raw source event (`ResourceSendRequest`) as that is // the event with the `sampleStackId` property which is required to // calculate this stacktrace correctly. const stack = getStackTrace(event.rawSourceEvent, data); // If the resource was injected by a script, it will have a parent call // frame that points to the script. Otherwise, there is no parent and // therefore we fallthrough to looking at the initiator directly on the // network request. const initiatorCallFrame = stack?.parent?.callFrames.at(0); if (!initiatorCallFrame) { return networkHandlerInitiator; } // Find all the requests for the URL we are searching for. Most of the time // there is only 1, but there can be multiple requests for the same URL. The // filtering by the timestamp ensures that we can never pick an initiator // that happened after the initiated event. const matchingRequestIds = data.NetworkRequests.requestIdsByURL.get(initiatorCallFrame.url) ?? []; const matchingRequests = matchingRequestIds.map(id => data.NetworkRequests.byId.get(id)) .filter(req => req !== undefined) .filter(req => req.ts < event.ts); // Now we have filtered and have a list of requests that are before the // event, we take the last one - the one closest to the initiated event. // In the case that there are >1 requests, this is an educated guess. return matchingRequests.at(-1); }