From b47d78ff5b8f75166f1c1a8a21cad967a20c5f9b Mon Sep 17 00:00:00 2001 From: Gregory Moskaliuk Date: Sat, 31 Oct 2026 12:58:07 +0100 Subject: [PATCH] Encode fetch responses for DevTools only when a debugger is attached NetworkEventUtil.onDataReceived Base64-encodes every response handled by a ResponseHandler, which is the blob path fetch uses by default, and passes it to InspectorNetworkReporter.maybeStoreResponseBody. The reporter drops the string unless debugging is enabled, so release builds do this work for every response and throw the result away. Check isDebuggingEnabled() before encoding. Co-Authored-By: Claude Opus 5.5 --- .../react/modules/network/NetworkEventUtil.kt | 12 +++--- .../modules/network/NetworkEventUtilTest.kt | 38 +++++++++++++++++++ 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkEventUtil.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkEventUtil.kt index 3edd4781341d..73882edd231f 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkEventUtil.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkEventUtil.kt @@ -139,11 +139,13 @@ internal object NetworkEventUtil { data: WritableMap, rawData: ByteArray, ) { - InspectorNetworkReporter.maybeStoreResponseBody( - devToolsRequestId, - Base64.encodeToString(rawData, Base64.NO_WRAP), - true, - ) + if (InspectorNetworkReporter.isDebuggingEnabled()) { + InspectorNetworkReporter.maybeStoreResponseBody( + devToolsRequestId, + Base64.encodeToString(rawData, Base64.NO_WRAP), + true, + ) + } reactContext?.emitDeviceEvent( "didReceiveNetworkData", Arguments.createArray().apply { diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/modules/network/NetworkEventUtilTest.kt b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/modules/network/NetworkEventUtilTest.kt index 63bdc127bd42..2fc4bc5117d0 100644 --- a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/modules/network/NetworkEventUtilTest.kt +++ b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/modules/network/NetworkEventUtilTest.kt @@ -9,10 +9,12 @@ package com.facebook.react.modules.network +import android.util.Base64 import com.facebook.react.bridge.Arguments import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.bridge.WritableArray import com.facebook.react.bridge.WritableMap +import com.facebook.react.common.annotations.UnstableReactNativeAPI import com.facebook.testutils.shadows.ShadowArguments import com.facebook.testutils.shadows.ShadowInspectorNetworkReporter import com.facebook.testutils.shadows.ShadowSoLoader @@ -26,6 +28,7 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor +import org.mockito.Mockito.mockStatic import org.mockito.kotlin.any import org.mockito.kotlin.mock import org.mockito.kotlin.never @@ -173,6 +176,41 @@ class NetworkEventUtilTest { assertThat(args.getMap(1)).isEqualTo(data) } + @Test + fun testOnDataReceivedMapDoesNotEncodeBodyWithoutDebugger() { + mockStatic(Base64::class.java).use { base64 -> + NetworkEventUtil.onDataReceived( + reactContext, + 1, + "devToolsRequestId", + Arguments.createMap(), + byteArrayOf(1, 2, 3), + ) + + base64.verifyNoInteractions() + } + } + + @OptIn(UnstableReactNativeAPI::class) + @Test + fun testOnDataReceivedMapStoresEncodedBodyWithDebugger() { + mockStatic(InspectorNetworkReporter::class.java).use { reporter -> + reporter.`when` { InspectorNetworkReporter.isDebuggingEnabled() }.thenReturn(true) + + NetworkEventUtil.onDataReceived( + reactContext, + 1, + "devToolsRequestId", + Arguments.createMap(), + byteArrayOf(1, 2, 3), + ) + + reporter.verify { + InspectorNetworkReporter.maybeStoreResponseBody("devToolsRequestId", "AQID", true) + } + } + } + @Test fun testOnRequestError() { val requestId = 1