Skip to content

Commit 1127e54

Browse files
sathoshikmeta-codesync[bot]
authored andcommitted
Base64-encode binary response bodies in the C++ NetworkingModule (#57214)
Summary: Pull Request resolved: #57214 The ReactCxxPlatform `NetworkingModule` delivered response bodies to JS verbatim regardless of the requested `responseType`. For binary response types (`responseType` `arraybuffer`, which the JS `XMLHttpRequest` layer maps to the native `base64` type), JS calls `base64.toByteArray()` on the delivered string. Sending the raw bytes therefore caused the payload to be mis-decoded and corrupted — e.g. `JSON.parse` failures on responses fetched as `arraybuffer`. Encode the body with base64 for `base64` responses, matching the existing Android (`NetworkingModule.kt` via `Base64.encodeToString(..., NO_WRAP)`) and iOS (`RCTNetworking.mm` via `base64EncodedStringWithOptions:0`) implementations. The encoding reuses the shared `react/utils` `base64Encode` helper already used by `jsinspector-modern`. All other response types are delivered unchanged. The per-`responseType` decision lives in a file-local (anonymous-namespace) `encodeResponseBody` helper in `NetworkingModule.cpp`, so it adds no surface to the public C++ API. Changelog: [General][Fixed] - Base64-encode binary (arraybuffer/blob) response bodies in the C++ NetworkingModule so they are not corrupted when delivered to JS Reviewed By: zeyap Differential Revision: D108440201 fbshipit-source-id: 38467877ff99ce7fe4d55739662faeb15b7e0440
1 parent dad85ba commit 1127e54

2 files changed

Lines changed: 59 additions & 2 deletions

File tree

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
#include <gtest/gtest.h>
9+
#include <react/utils/Base64.h>
10+
#include <string>
11+
12+
namespace facebook::react {
13+
14+
TEST(Base64Tests, encodesAsciiString) {
15+
EXPECT_EQ(base64Encode("hello"), "aGVsbG8=");
16+
}
17+
18+
TEST(Base64Tests, encodesEmptyString) {
19+
EXPECT_EQ(base64Encode(""), "");
20+
}
21+
22+
// Padding depends on input length modulo 3.
23+
TEST(Base64Tests, encodesWithCorrectPadding) {
24+
EXPECT_EQ(base64Encode("a"), "YQ==");
25+
EXPECT_EQ(base64Encode("ab"), "YWI=");
26+
EXPECT_EQ(base64Encode("abc"), "YWJj");
27+
}
28+
29+
// Binary safety: bytes that are invalid UTF-8 / contain NULs must round-trip.
30+
// This is the case that matters for binary ('base64'/arraybuffer) response
31+
// bodies in the NetworkingModule -- sending such bytes verbatim corrupts them.
32+
TEST(Base64Tests, encodesBinaryBytes) {
33+
EXPECT_EQ(base64Encode(std::string("\x00\xff", 2)), "AP8=");
34+
}
35+
36+
} // namespace facebook::react

packages/react-native/ReactCxxPlatform/react/io/NetworkingModule.cpp

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "NetworkingModule.h"
99

1010
#include <react/debug/react_native_assert.h>
11+
#include <react/utils/Base64.h>
1112

1213
namespace facebook::react {
1314

@@ -270,15 +271,35 @@ int64_t NetworkingModule::didReceiveNetworkIncrementalData(
270271
return bytesRead;
271272
};
272273

274+
namespace {
275+
// Encodes a response body for delivery to JS according to responseType.
276+
//
277+
// The JS XMLHttpRequest layer base64-decodes the delivered string for
278+
// 'base64'-type responses (responseType 'arraybuffer'), so binary bodies must
279+
// be base64-encoded here, matching the Android and iOS NetworkingModule
280+
// implementations. Without this, base64.toByteArray() on the JS side
281+
// mis-decodes the raw payload and corrupts the response (e.g. JSON.parse
282+
// failures on arraybuffer fetches). All other response types are delivered
283+
// unchanged.
284+
std::string encodeResponseBody(
285+
const std::string& responseType,
286+
std::string body) {
287+
if (responseType == "base64") {
288+
return base64Encode(body);
289+
}
290+
return body;
291+
}
292+
} // namespace
293+
273294
void NetworkingModule::didReceiveNetworkData(
274295
uint32_t requestId,
275-
const std::string& /*responseType*/,
296+
const std::string& responseType,
276297
std::unique_ptr<folly::IOBuf> buf) {
277298
if (requests_.isStopped()) {
278299
return;
279300
}
280301

281-
auto responseData = buf->toString();
302+
auto responseData = encodeResponseBody(responseType, buf->toString());
282303
emitDeviceEvent(
283304
"didReceiveNetworkData",
284305
[requestId,

0 commit comments

Comments
 (0)