From 08818d8a9fccb425f90c5207c8fa8d2468dda0b1 Mon Sep 17 00:00:00 2001 From: Abhijeet Prasad Date: Wed, 22 Nov 2023 12:40:18 -0500 Subject: [PATCH] fix(tracing): Filter out invalid resource sizes (#9641) There's a bug in some browsers that attaches huge resource sizes that are completely unrealistic. Here's an example in chromium: https://bugs.chromium.org/p/chromium/issues/detail?id=1324812#c25 To get around this, we add a filter to enforce that resource sizes should only be attached if the size is < 2147483647 bytes (size of maximum value of integer in c/c++). --- .../src/browser/metrics/index.ts | 26 ++++++++++++------- .../test/browser/metrics/index.test.ts | 20 ++++++++++++++ 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/packages/tracing-internal/src/browser/metrics/index.ts b/packages/tracing-internal/src/browser/metrics/index.ts index edeedcee679f..4d28f6102cde 100644 --- a/packages/tracing-internal/src/browser/metrics/index.ts +++ b/packages/tracing-internal/src/browser/metrics/index.ts @@ -15,6 +15,8 @@ import { getVisibilityWatcher } from '../web-vitals/lib/getVisibilityWatcher'; import type { NavigatorDeviceMemory, NavigatorNetworkInformation } from '../web-vitals/types'; import { _startChild, isMeasurementValue } from './utils'; +const MAX_INT_AS_BYTES = 2147483647; + /** * Converts from milliseconds to seconds * @param time time in ms @@ -402,15 +404,9 @@ export function _addResourceSpans( // eslint-disable-next-line @typescript-eslint/no-explicit-any const data: Record = {}; - if ('transferSize' in entry) { - data['http.response_transfer_size'] = entry.transferSize; - } - if ('encodedBodySize' in entry) { - data['http.response_content_length'] = entry.encodedBodySize; - } - if ('decodedBodySize' in entry) { - data['http.decoded_response_content_length'] = entry.decodedBodySize; - } + setResourceEntrySizeData(data, entry, 'transferSize', 'http.response_transfer_size'); + setResourceEntrySizeData(data, entry, 'encodedBodySize', 'http.response_content_length'); + setResourceEntrySizeData(data, entry, 'decodedBodySize', 'http.decoded_response_content_length'); if ('renderBlockingStatus' in entry) { data['resource.render_blocking_status'] = entry.renderBlockingStatus; } @@ -493,3 +489,15 @@ function _tagMetricInfo(transaction: Transaction): void { ); } } + +function setResourceEntrySizeData( + data: Record, + entry: ResourceEntry, + key: keyof Pick, + dataKey: 'http.response_transfer_size' | 'http.response_content_length' | 'http.decoded_response_content_length', +): void { + const entryVal = entry[key]; + if (entryVal !== undefined && entryVal < MAX_INT_AS_BYTES) { + data[dataKey] = entryVal; + } +} diff --git a/packages/tracing-internal/test/browser/metrics/index.test.ts b/packages/tracing-internal/test/browser/metrics/index.test.ts index 41b4cd9c1940..a549b2549a37 100644 --- a/packages/tracing-internal/test/browser/metrics/index.test.ts +++ b/packages/tracing-internal/test/browser/metrics/index.test.ts @@ -169,4 +169,24 @@ describe('_addResourceSpans', () => { }), ); }); + + it('does not attach resource sizes that exceed MAX_INT bytes', () => { + const entry: ResourceEntry = { + initiatorType: 'css', + transferSize: 2147483647, + encodedBodySize: 2147483647, + decodedBodySize: 2147483647, + }; + + _addResourceSpans(transaction, entry, '/assets/to/css', 100, 23, 345); + + // eslint-disable-next-line @typescript-eslint/unbound-method + expect(transaction.startChild).toHaveBeenCalledTimes(1); + // eslint-disable-next-line @typescript-eslint/unbound-method + expect(transaction.startChild).toHaveBeenLastCalledWith( + expect.objectContaining({ + data: {}, + }), + ); + }); });