{"version":3,"file":"NetworkAnalyzer.js","sourceRoot":"","sources":["../../../../../../../../front_end/models/trace/lantern/core/NetworkAnalyzer.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport type * as Lantern from '../types/types.js';\n\nimport {LanternError} from './LanternError.js';\n\nclass UrlUtils {\n  /**\n   * There is fancy URL rewriting logic for the chrome://settings page that we need to work around.\n   * Why? Special handling was added by Chrome team to allow a pushState transition between chrome:// pages.\n   * As a result, the network URL (chrome://chrome/settings/) doesn't match the final document URL (chrome://settings/).\n   */\n  static rewriteChromeInternalUrl(url: string): string {\n    if (!url?.startsWith('chrome://')) {\n      return url;\n    }\n    // Chrome adds a trailing slash to `chrome://` URLs, but the spec does not.\n    //   https://github.com/GoogleChrome/lighthouse/pull/3941#discussion_r154026009\n    if (url.endsWith('/')) {\n      url = url.replace(/\\/$/, '');\n    }\n    return url.replace(/^chrome:\\/\\/chrome\\//, 'chrome://');\n  }\n\n  /**\n   * Determine if url1 equals url2, ignoring URL fragments.\n   */\n  static equalWithExcludedFragments(url1: string, url2: string): boolean {\n    [url1, url2] = [url1, url2].map(this.rewriteChromeInternalUrl);\n    try {\n      const urla = new URL(url1);\n      urla.hash = '';\n\n      const urlb = new URL(url2);\n      urlb.hash = '';\n\n      return urla.href === urlb.href;\n    } catch {\n      return false;\n    }\n  }\n}\n\ninterface Summary {\n  min: number;\n  max: number;\n  avg: number;\n  median: number;\n}\n\ninterface RTTEstimateOptions {\n  /**\n   * TCP connection handshake information will be used when available, but in\n   * some circumstances this data can be unreliable. This flag exposes an\n   * option to ignore the handshake data and use the coarse download/TTFB timing data.\n   */\n  forceCoarseEstimates?: boolean;\n  /**\n   * Coarse estimates include lots of extra time and noise multiply by some factor\n   * to deflate the estimates a bit.\n   */\n  coarseEstimateMultiplier?: number;\n  /** Useful for testing to isolate the different methods of estimation. */\n  useDownloadEstimates?: boolean;\n  /** Useful for testing to isolate the different methods of estimation. */\n  useSendStartEstimates?: boolean;\n  /** Useful for testing to isolate the different methods of estimation. */\n  useHeadersEndEstimates?: boolean;\n}\n\ninterface RequestInfo {\n  request: Lantern.NetworkRequest;\n  timing: Lantern.ResourceTiming;\n  connectionReused?: boolean;\n}\n\nconst INITIAL_CWD = 14 * 1024;\n\n// Assume that 40% of TTFB was server response time by default for static assets\nconst DEFAULT_SERVER_RESPONSE_PERCENTAGE = 0.4;\n\n/**\n * For certain resource types, server response time takes up a greater percentage of TTFB (dynamic\n * assets like HTML documents, XHR/API calls, etc)\n */\nconst SERVER_RESPONSE_PERCENTAGE_OF_TTFB: Partial<Record<Lantern.ResourceType, number>> = {\n  Document: 0.9,\n  XHR: 0.9,\n  Fetch: 0.9,\n};\n\nclass NetworkAnalyzer {\n  static get summary(): string {\n    return '__SUMMARY__';\n  }\n\n  static groupByOrigin(records: Lantern.NetworkRequest[]): Map<string, Lantern.NetworkRequest[]> {\n    const grouped = new Map();\n    records.forEach(item => {\n      const key = item.parsedURL.securityOrigin;\n      const group = grouped.get(key) || [];\n      group.push(item);\n      grouped.set(key, group);\n    });\n    return grouped;\n  }\n\n  static getSummary(values: number[]): Summary {\n    values.sort((a, b) => a - b);\n\n    let median;\n    if (values.length === 0) {\n      median = values[0];\n    } else if (values.length % 2 === 0) {\n      const a = values[Math.floor((values.length - 1) / 2)];\n      const b = values[Math.floor((values.length - 1) / 2) + 1];\n      median = (a + b) / 2;\n    } else {\n      median = values[Math.floor((values.length - 1) / 2)];\n    }\n\n    return {\n      min: values[0],\n      max: values[values.length - 1],\n      avg: values.reduce((a, b) => a + b, 0) / values.length,\n      median,\n    };\n  }\n\n  static summarize(values: Map<string, number[]>): Map<string, Summary> {\n    const summaryByKey = new Map();\n    const allEstimates = [];\n    for (const [key, estimates] of values) {\n      summaryByKey.set(key, NetworkAnalyzer.getSummary(estimates));\n      allEstimates.push(...estimates);\n    }\n\n    summaryByKey.set(NetworkAnalyzer.summary, NetworkAnalyzer.getSummary(allEstimates));\n    return summaryByKey;\n  }\n\n  static estimateValueByOrigin(\n      requests: Lantern.NetworkRequest[],\n      iteratee: (e: RequestInfo) => number | number[] | undefined): Map<string, number[]> {\n    const connectionWasReused = NetworkAnalyzer.estimateIfConnectionWasReused(requests);\n    const groupedByOrigin = NetworkAnalyzer.groupByOrigin(requests);\n\n    const estimates = new Map();\n    for (const [origin, originRequests] of groupedByOrigin.entries()) {\n      let originEstimates: number[] = [];\n\n      for (const request of originRequests) {\n        const timing = request.timing;\n        if (!timing) {\n          continue;\n        }\n\n        const value = iteratee({\n          request,\n          timing,\n          connectionReused: connectionWasReused.get(request.requestId),\n        });\n        if (typeof value !== 'undefined') {\n          originEstimates = originEstimates.concat(value);\n        }\n      }\n\n      if (!originEstimates.length) {\n        continue;\n      }\n      estimates.set(origin, originEstimates);\n    }\n\n    return estimates;\n  }\n\n  /**\n   * Estimates the observed RTT to each origin based on how long the connection setup.\n   * For h1 and h2, this could includes two estimates - one for the TCP handshake, another for\n   * SSL negotiation.\n   * For h3, we get only one estimate since QUIC establishes a secure connection in a\n   * single handshake.\n   * This is the most accurate and preferred method of measurement when the data is available.\n   */\n  static estimateRTTViaConnectionTiming(info: RequestInfo): number[]|number|undefined {\n    const {timing, connectionReused, request} = info;\n    if (connectionReused) {\n      return;\n    }\n\n    const {connectStart, sslStart, sslEnd, connectEnd} = timing;\n    if (connectEnd >= 0 && connectStart >= 0 && request.protocol.startsWith('h3')) {\n      // These values are equal to sslStart and sslEnd for h3.\n      return connectEnd - connectStart;\n    }\n    if (sslStart >= 0 && sslEnd >= 0 && sslStart !== connectStart) {\n      // SSL can also be more than 1 RT but assume False Start was used.\n      return [connectEnd - sslStart, sslStart - connectStart];\n    }\n    if (connectStart >= 0 && connectEnd >= 0) {\n      return connectEnd - connectStart;\n    }\n\n    return;\n  }\n\n  /**\n   * Estimates the observed RTT to each origin based on how long a download took on a fresh connection.\n   * NOTE: this will tend to overestimate the actual RTT quite significantly as the download can be\n   * slow for other reasons as well such as bandwidth constraints.\n   */\n  static estimateRTTViaDownloadTiming(info: RequestInfo): number|undefined {\n    const {timing, connectionReused, request} = info;\n    if (connectionReused) {\n      return;\n    }\n\n    // Only look at downloads that went past the initial congestion window\n    if (request.transferSize <= INITIAL_CWD) {\n      return;\n    }\n    if (!Number.isFinite(timing.receiveHeadersEnd) || timing.receiveHeadersEnd < 0) {\n      return;\n    }\n\n    // Compute the amount of time downloading everything after the first congestion window took\n    const totalTime = request.networkEndTime - request.networkRequestTime;\n    const downloadTimeAfterFirstByte = totalTime - timing.receiveHeadersEnd;\n    const numberOfRoundTrips = Math.log2(request.transferSize / INITIAL_CWD);\n\n    // Ignore requests that required a high number of round trips since bandwidth starts to play\n    // a larger role than latency\n    if (numberOfRoundTrips > 5) {\n      return;\n    }\n\n    return downloadTimeAfterFirstByte / numberOfRoundTrips;\n  }\n\n  /**\n   * Estimates the observed RTT to each origin based on how long it took until Chrome could\n   * start sending the actual request when a new connection was required.\n   * NOTE: this will tend to overestimate the actual RTT as the request can be delayed for other\n   * reasons as well such as more SSL handshakes if TLS False Start is not enabled.\n   */\n  static estimateRTTViaSendStartTiming(info: RequestInfo): number|undefined {\n    const {timing, connectionReused, request} = info;\n    if (connectionReused) {\n      return;\n    }\n\n    if (!Number.isFinite(timing.sendStart) || timing.sendStart < 0) {\n      return;\n    }\n\n    // Assume everything before sendStart was just DNS + (SSL)? + TCP handshake\n    // 1 RT for DNS, 1 RT (maybe) for SSL, 1 RT for TCP\n    let roundTrips = 1;\n    // TCP\n    if (!request.protocol.startsWith('h3')) {\n      roundTrips += 1;\n    }\n    if (request.parsedURL.scheme === 'https') {\n      roundTrips += 1;\n    }\n    return timing.sendStart / roundTrips;\n  }\n\n  /**\n   * Estimates the observed RTT to each origin based on how long it took until Chrome received the\n   * headers of the response (~TTFB).\n   * NOTE: this is the most inaccurate way to estimate the RTT, but in some environments it's all\n   * we have access to :(\n   */\n  static estimateRTTViaHeadersEndTiming(info: RequestInfo): number|undefined {\n    const {timing, connectionReused, request} = info;\n    if (!Number.isFinite(timing.receiveHeadersEnd) || timing.receiveHeadersEnd < 0) {\n      return;\n    }\n    if (!request.resourceType) {\n      return;\n    }\n\n    const serverResponseTimePercentage =\n        SERVER_RESPONSE_PERCENTAGE_OF_TTFB[request.resourceType] || DEFAULT_SERVER_RESPONSE_PERCENTAGE;\n    const estimatedServerResponseTime = timing.receiveHeadersEnd * serverResponseTimePercentage;\n\n    // When connection was reused...\n    // TTFB = 1 RT for request + server response time\n    let roundTrips = 1;\n\n    // When connection was fresh...\n    // TTFB = DNS + (SSL)? + TCP handshake + 1 RT for request + server response time\n    if (!connectionReused) {\n      roundTrips += 1;  // DNS\n      if (!request.protocol.startsWith('h3')) {\n        roundTrips += 1;  // TCP\n      }\n      if (request.parsedURL.scheme === 'https') {\n        roundTrips += 1;  // SSL\n      }\n    }\n\n    // subtract out our estimated server response time\n    return Math.max((timing.receiveHeadersEnd - estimatedServerResponseTime) / roundTrips, 3);\n  }\n\n  /**\n   * Given the RTT to each origin, estimates the observed server response times.\n   */\n  static estimateResponseTimeByOrigin(records: Lantern.NetworkRequest[], rttByOrigin: Map<string, number>):\n      Map<string, number[]> {\n    return NetworkAnalyzer.estimateValueByOrigin(records, ({request, timing}) => {\n      if (request.serverResponseTime !== undefined) {\n        return request.serverResponseTime;\n      }\n\n      if (!Number.isFinite(timing.receiveHeadersEnd) || timing.receiveHeadersEnd < 0) {\n        return;\n      }\n      if (!Number.isFinite(timing.sendEnd) || timing.sendEnd < 0) {\n        return;\n      }\n\n      const ttfb = timing.receiveHeadersEnd - timing.sendEnd;\n      const origin = request.parsedURL.securityOrigin;\n      const rtt = rttByOrigin.get(origin) || rttByOrigin.get(NetworkAnalyzer.summary) || 0;\n      return Math.max(ttfb - rtt, 0);\n    });\n  }\n\n  static canTrustConnectionInformation(requests: Lantern.NetworkRequest[]): boolean {\n    const connectionIdWasStarted = new Map();\n    for (const request of requests) {\n      const started = connectionIdWasStarted.get(request.connectionId) || !request.connectionReused;\n      connectionIdWasStarted.set(request.connectionId, started);\n    }\n\n    // We probably can't trust the network information if all the connection IDs were the same\n    if (connectionIdWasStarted.size <= 1) {\n      return false;\n    }\n    // Or if there were connections that were always reused (a connection had to have started at some point)\n    return Array.from(connectionIdWasStarted.values()).every(started => started);\n  }\n\n  /**\n   * Returns a map of requestId -> connectionReused, estimating the information if the information\n   * available in the records themselves appears untrustworthy.\n   */\n  static estimateIfConnectionWasReused(records: Lantern.NetworkRequest[], options?: {forceCoarseEstimates: boolean}):\n      Map<string, boolean> {\n    const {forceCoarseEstimates = false} = options || {};\n\n    // Check if we can trust the connection information coming from the protocol\n    if (!forceCoarseEstimates && NetworkAnalyzer.canTrustConnectionInformation(records)) {\n      return new Map(records.map(request => [request.requestId, Boolean(request.connectionReused)]));\n    }\n\n    // Otherwise we're on our own, a request may not have needed a fresh connection if...\n    //   - It was not the first request to the domain\n    //   - It was H2\n    //   - It was after the first request to the domain ended\n    const connectionWasReused = new Map();\n    const groupedByOrigin = NetworkAnalyzer.groupByOrigin(records);\n    for (const originRecords of groupedByOrigin.values()) {\n      const earliestReusePossible =\n          originRecords.map(request => request.networkEndTime).reduce((a, b) => Math.min(a, b), Infinity);\n\n      for (const request of originRecords) {\n        connectionWasReused.set(\n            request.requestId,\n            request.networkRequestTime >= earliestReusePossible || request.protocol === 'h2',\n        );\n      }\n\n      const firstRecord = originRecords.reduce((a, b) => {\n        return a.networkRequestTime > b.networkRequestTime ? b : a;\n      });\n      connectionWasReused.set(firstRecord.requestId, false);\n    }\n\n    return connectionWasReused;\n  }\n\n  /**\n   * Estimates the RTT to each origin by examining observed network timing information.\n   * Attempts to use the most accurate information first and falls back to coarser estimates when it\n   * is unavailable.\n   */\n  static estimateRTTByOrigin(records: Lantern.NetworkRequest[], options?: RTTEstimateOptions): Map<string, Summary> {\n    const {\n      forceCoarseEstimates = false,\n      // coarse estimates include lots of extra time and noise\n      // multiply by some factor to deflate the estimates a bit.\n      coarseEstimateMultiplier = 0.3,\n      useDownloadEstimates = true,\n      useSendStartEstimates = true,\n      useHeadersEndEstimates = true,\n    } = options || {};\n\n    const connectionWasReused = NetworkAnalyzer.estimateIfConnectionWasReused(records);\n    const groupedByOrigin = NetworkAnalyzer.groupByOrigin(records);\n\n    const estimatesByOrigin = new Map();\n    for (const [origin, originRequests] of groupedByOrigin.entries()) {\n      const originEstimates: number[] = [];\n\n      function collectEstimates(estimator: (e: RequestInfo) => number[] | number | undefined, multiplier = 1): void {\n        for (const request of originRequests) {\n          const timing = request.timing;\n          if (!timing || !request.transferSize) {\n            continue;\n          }\n\n          const estimates = estimator({\n            request,\n            timing,\n            connectionReused: connectionWasReused.get(request.requestId),\n          });\n          if (estimates === undefined) {\n            continue;\n          }\n\n          if (!Array.isArray(estimates)) {\n            originEstimates.push(estimates * multiplier);\n          } else {\n            originEstimates.push(...estimates.map(e => e * multiplier));\n          }\n        }\n      }\n\n      if (!forceCoarseEstimates) {\n        collectEstimates(this.estimateRTTViaConnectionTiming);\n      }\n\n      // Connection timing can be missing for a few reasons:\n      // - Origin was preconnected, which we don't have instrumentation for.\n      // - Trace began recording after a connection has already been established (for example, in timespan mode)\n      // - Perhaps Chrome established a connection already in the background (service worker? Just guessing here)\n      // - Not provided in LR netstack.\n      if (!originEstimates.length) {\n        if (useDownloadEstimates) {\n          collectEstimates(this.estimateRTTViaDownloadTiming, coarseEstimateMultiplier);\n        }\n        if (useSendStartEstimates) {\n          collectEstimates(this.estimateRTTViaSendStartTiming, coarseEstimateMultiplier);\n        }\n        if (useHeadersEndEstimates) {\n          collectEstimates(this.estimateRTTViaHeadersEndTiming, coarseEstimateMultiplier);\n        }\n      }\n\n      if (originEstimates.length) {\n        estimatesByOrigin.set(origin, originEstimates);\n      }\n    }\n\n    if (!estimatesByOrigin.size) {\n      throw new LanternError('No timing information available');\n    }\n    return NetworkAnalyzer.summarize(estimatesByOrigin);\n  }\n\n  /**\n   * Estimates the server response time of each origin. RTT times can be passed in or will be\n   * estimated automatically if not provided.\n   */\n  static estimateServerResponseTimeByOrigin(records: Lantern.NetworkRequest[], options?: RTTEstimateOptions&{\n    rttByOrigin?: Map<string, number>,\n  }): Map<string, Summary> {\n    let rttByOrigin = options?.rttByOrigin;\n    if (!rttByOrigin) {\n      rttByOrigin = new Map();\n\n      const rttSummaryByOrigin = NetworkAnalyzer.estimateRTTByOrigin(records, options);\n      for (const [origin, summary] of rttSummaryByOrigin.entries()) {\n        rttByOrigin.set(origin, summary.min);\n      }\n    }\n\n    const estimatesByOrigin = NetworkAnalyzer.estimateResponseTimeByOrigin(records, rttByOrigin);\n    return NetworkAnalyzer.summarize(estimatesByOrigin);\n  }\n\n  /**\n   * Computes the average throughput for the given requests in bits/second.\n   * Excludes data URI, failed or otherwise incomplete, and cached requests.\n   * Returns null if there were no analyzable network requests.\n   */\n  static estimateThroughput(records: Lantern.NetworkRequest[]): number|null {\n    let totalBytes = 0;\n\n    // We will measure throughput by summing the total bytes downloaded by the total time spent\n    // downloading those bytes. We slice up all the network requests into start/end boundaries, so\n    // it's easier to deal with the gaps in downloading.\n    const timeBoundaries = records\n                               .reduce(\n                                   (boundaries, request) => {\n                                     const scheme = request.parsedURL?.scheme;\n                                     // Requests whose bodies didn't come over the network or didn't completely finish will mess\n                                     // with the computation, just skip over them.\n                                     if (scheme === 'data' || request.failed || !request.finished ||\n                                         request.statusCode > 300 || !request.transferSize) {\n                                       return boundaries;\n                                     }\n\n                                     // If we've made it this far, all the times we need should be valid (i.e. not undefined/-1).\n                                     totalBytes += request.transferSize;\n                                     boundaries.push({time: request.responseHeadersEndTime / 1000, isStart: true});\n                                     boundaries.push({time: request.networkEndTime / 1000, isStart: false});\n                                     return boundaries;\n                                   },\n                                   [] as Array<{time: number, isStart: boolean}>)\n                               .sort((a, b) => a.time - b.time);\n\n    if (!timeBoundaries.length) {\n      return null;\n    }\n\n    let inflight = 0;\n    let currentStart = 0;\n    let totalDuration = 0;\n\n    timeBoundaries.forEach(boundary => {\n      if (boundary.isStart) {\n        if (inflight === 0) {\n          // We just ended a quiet period, keep track of when the download period started\n          currentStart = boundary.time;\n        }\n        inflight++;\n      } else {\n        inflight--;\n        if (inflight === 0) {\n          // We just entered a quiet period, update our duration with the time we spent downloading\n          totalDuration += boundary.time - currentStart;\n        }\n      }\n    });\n\n    return totalBytes * 8 / totalDuration;\n  }\n\n  static computeRTTAndServerResponseTime(records: Lantern.NetworkRequest[]):\n      {rtt: number, additionalRttByOrigin: Map<string, number>, serverResponseTimeByOrigin: Map<string, number>} {\n    // First pass compute the estimated observed RTT to each origin's servers.\n    const rttByOrigin = new Map<string, number>();\n    for (const [origin, summary] of NetworkAnalyzer.estimateRTTByOrigin(records).entries()) {\n      rttByOrigin.set(origin, summary.min);\n    }\n\n    // We'll use the minimum RTT as the assumed connection latency since we care about how much addt'l\n    // latency each origin introduces as Lantern will be simulating with its own connection latency.\n    const minimumRtt = Math.min(...Array.from(rttByOrigin.values()));\n    // We'll use the observed RTT information to help estimate the server response time\n    const responseTimeSummaries = NetworkAnalyzer.estimateServerResponseTimeByOrigin(records, {\n      rttByOrigin,\n    });\n\n    const additionalRttByOrigin = new Map<string, number>();\n    const serverResponseTimeByOrigin = new Map<string, number>();\n    for (const [origin, summary] of responseTimeSummaries.entries()) {\n      // Not all origins have usable timing data, we'll default to using no additional latency.\n      const rttForOrigin = rttByOrigin.get(origin) || minimumRtt;\n      additionalRttByOrigin.set(origin, rttForOrigin - minimumRtt);\n      serverResponseTimeByOrigin.set(origin, summary.median);\n    }\n\n    return {\n      rtt: minimumRtt,\n      additionalRttByOrigin,\n      serverResponseTimeByOrigin,\n    };\n  }\n\n  static analyze(records: Lantern.NetworkRequest[]): Lantern.Simulation.Settings['networkAnalysis']|null {\n    const throughput = NetworkAnalyzer.estimateThroughput(records);\n    if (throughput === null) {\n      return null;\n    }\n\n    return {\n      throughput,\n      ...NetworkAnalyzer.computeRTTAndServerResponseTime(records),\n    };\n  }\n\n  static findResourceForUrl<T extends Lantern.NetworkRequest>(records: T[], resourceUrl: string): T|undefined {\n    // equalWithExcludedFragments is expensive, so check that the resourceUrl starts with the request url first\n    return records.find(\n        request => resourceUrl.startsWith(request.url) && UrlUtils.equalWithExcludedFragments(request.url, resourceUrl),\n    );\n  }\n\n  static findLastDocumentForUrl<T extends Lantern.NetworkRequest>(records: T[], resourceUrl: string): T|undefined {\n    // equalWithExcludedFragments is expensive, so check that the resourceUrl starts with the request url first\n    const matchingRequests = records.filter(\n        request => request.resourceType === 'Document' && !request.failed &&\n            // Note: `request.url` should never have a fragment, else this optimization gives wrong results.\n            resourceUrl.startsWith(request.url) && UrlUtils.equalWithExcludedFragments(request.url, resourceUrl),\n    );\n    return matchingRequests[matchingRequests.length - 1];\n  }\n\n  /**\n   * Resolves redirect chain given a main document.\n   * See: {@link NetworkAnalyzer.findLastDocumentForUrl} for how to retrieve main document.\n   */\n  static resolveRedirects<T extends Lantern.NetworkRequest>(request: T): T {\n    while (request.redirectDestination) {\n      request = request.redirectDestination as T;\n    }\n    return request;\n  }\n}\n\nexport {NetworkAnalyzer};\n"]}