first commit

This commit is contained in:
2026-03-10 16:18:05 +00:00
commit 11f9c069b5
31635 changed files with 3187747 additions and 0 deletions

View File

@@ -0,0 +1,30 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
cmake_minimum_required(VERSION 3.13)
set(CMAKE_VERBOSE_MAKEFILE on)
include(${REACT_COMMON_DIR}/cmake-utils/react-native-flags.cmake)
file(GLOB react_networking_SRC CONFIGURE_DEPENDS *.cpp)
add_library(react_networking OBJECT ${react_networking_SRC})
target_compile_reactnative_options(react_networking PRIVATE)
target_compile_options(react_networking PRIVATE -Wpedantic)
target_include_directories(react_networking PUBLIC ${REACT_COMMON_DIR})
target_link_libraries(react_networking
folly_runtime
jsinspector_network
jsinspector_tracing
react_performance_timeline
react_timing)
if(${CMAKE_BUILD_TYPE} MATCHES Debug OR REACT_NATIVE_DEBUG_OPTIMIZED)
target_compile_options(react_networking PRIVATE
-DREACT_NATIVE_DEBUGGER_ENABLED=1
-DREACT_NATIVE_DEBUGGER_ENABLED_DEVONLY=1
)
endif ()

View File

@@ -0,0 +1,251 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "NetworkReporter.h"
#ifdef REACT_NATIVE_DEBUGGER_ENABLED
#include <jsinspector-modern/network/CdpNetwork.h>
#include <jsinspector-modern/network/NetworkHandler.h>
#include <jsinspector-modern/tracing/PerformanceTracer.h>
#endif
#include <jsinspector-modern/network/HttpUtils.h>
#include <react/featureflags/ReactNativeFeatureFlags.h>
#include <react/performance/timeline/PerformanceEntryReporter.h>
namespace facebook::react {
NetworkReporter& NetworkReporter::getInstance() {
static NetworkReporter instance;
return instance;
}
bool NetworkReporter::isDebuggingEnabled() const {
#ifdef REACT_NATIVE_DEBUGGER_ENABLED
return jsinspector_modern::NetworkHandler::getInstance().isEnabled();
#else
return false;
#endif
}
void NetworkReporter::reportRequestStart(
const std::string& requestId,
const RequestInfo& requestInfo,
int encodedDataLength,
const std::optional<ResponseInfo>& redirectResponse) {
auto now = HighResTimeStamp::now();
// All builds: Annotate PerformanceResourceTiming metadata
{
std::lock_guard<std::mutex> lock(perfTimingsMutex_);
perfTimingsBuffer_.emplace(
requestId,
ResourceTimingData{
.url = requestInfo.url,
.fetchStart = now,
.requestStart = now,
});
}
#ifdef REACT_NATIVE_DEBUGGER_ENABLED
auto headers = requestInfo.headers.value_or(Headers{});
// Debugger enabled: CDP event handling
jsinspector_modern::NetworkHandler::getInstance().onRequestWillBeSent(
requestId,
{
.url = requestInfo.url,
.method = requestInfo.httpMethod,
.headers = headers,
.postData = requestInfo.httpBody,
},
redirectResponse.has_value()
? std::optional<jsinspector_modern::cdp::network::Response>(
jsinspector_modern::cdp::network::Response::fromInputParams(
redirectResponse->url,
redirectResponse->statusCode,
redirectResponse->headers.value_or(Headers{}),
encodedDataLength))
: std::nullopt);
// Debugger enabled: Add trace events to Performance timeline
auto& performanceTracer =
jsinspector_modern::tracing::PerformanceTracer::getInstance();
performanceTracer.reportResourceSendRequest(
requestId, now, requestInfo.url, requestInfo.httpMethod, headers);
#endif
}
void NetworkReporter::reportConnectionTiming(
const std::string& requestId,
const std::optional<Headers>& headers) {
auto now = HighResTimeStamp::now();
// All builds: Annotate PerformanceResourceTiming metadata
{
std::lock_guard<std::mutex> lock(perfTimingsMutex_);
auto it = perfTimingsBuffer_.find(requestId);
if (it != perfTimingsBuffer_.end()) {
it->second.connectStart = now;
}
}
#ifdef REACT_NATIVE_DEBUGGER_ENABLED
// Debugger enabled: CDP event handling
jsinspector_modern::NetworkHandler::getInstance()
.onRequestWillBeSentExtraInfo(requestId, headers.value_or(Headers{}));
#endif
}
void NetworkReporter::reportResponseStart(
const std::string& requestId,
const ResponseInfo& responseInfo,
int encodedDataLength) {
auto now = HighResTimeStamp::now();
auto headers = responseInfo.headers.value_or(Headers{});
// All builds: Annotate PerformanceResourceTiming metadata
{
std::lock_guard<std::mutex> lock(perfTimingsMutex_);
auto it = perfTimingsBuffer_.find(requestId);
if (it != perfTimingsBuffer_.end()) {
auto contentType = jsinspector_modern::mimeTypeFromHeaders(headers);
it->second.connectEnd = now;
it->second.responseStart = now;
it->second.responseStatus = responseInfo.statusCode;
it->second.contentType = contentType;
it->second.encodedBodySize = encodedDataLength;
it->second.decodedBodySize = encodedDataLength;
}
}
#ifdef REACT_NATIVE_DEBUGGER_ENABLED
// Debugger enabled: CDP event handling
jsinspector_modern::NetworkHandler::getInstance().onResponseReceived(
requestId,
jsinspector_modern::cdp::network::Response::fromInputParams(
responseInfo.url,
responseInfo.statusCode,
headers,
encodedDataLength));
// Debugger enabled: Add trace event to Performance timeline
{
folly::dynamic timingData = folly::dynamic::object();
std::lock_guard<std::mutex> lock(perfTimingsMutex_);
auto it = perfTimingsBuffer_.find(requestId);
if (it != perfTimingsBuffer_.end()) {
// TODO(T238364329): All relative values in timingData should be based on
// fetchStart, once implemented.
auto requestStart = it->second.requestStart;
timingData["requestTime"] = requestStart.toDOMHighResTimeStamp() / 1000;
timingData["sendStart"] = 0;
timingData["sendEnd"] =
(*it->second.connectStart - requestStart).toDOMHighResTimeStamp();
timingData["receiveHeadersStart"] =
(*it->second.connectStart - requestStart).toDOMHighResTimeStamp();
timingData["receiveHeadersEnd"] =
(now - requestStart).toDOMHighResTimeStamp();
}
jsinspector_modern::tracing::PerformanceTracer::getInstance()
.reportResourceReceiveResponse(
requestId,
now,
responseInfo.statusCode,
headers,
encodedDataLength,
std::move(timingData));
}
#endif
}
void NetworkReporter::reportDataReceived(
const std::string& requestId,
int dataLength,
const std::optional<int>& encodedDataLength) {
#ifdef REACT_NATIVE_DEBUGGER_ENABLED
// Debugger enabled: CDP event handling
jsinspector_modern::NetworkHandler::getInstance().onDataReceived(
requestId, dataLength, encodedDataLength.value_or(dataLength));
#endif
}
void NetworkReporter::reportResponseEnd(
const std::string& requestId,
int encodedDataLength) {
auto now = HighResTimeStamp::now();
if (ReactNativeFeatureFlags::enableResourceTimingAPI()) {
// All builds: Report PerformanceResourceTiming event
{
std::lock_guard<std::mutex> lock(perfTimingsMutex_);
auto it = perfTimingsBuffer_.find(requestId);
if (it != perfTimingsBuffer_.end()) {
auto& eventData = it->second;
PerformanceEntryReporter::getInstance()->reportResourceTiming(
eventData.url,
eventData.fetchStart,
eventData.requestStart,
eventData.connectStart.value_or(now),
eventData.connectEnd.value_or(now),
eventData.responseStart.value_or(now),
now,
eventData.responseStatus,
eventData.contentType,
eventData.encodedBodySize,
eventData.decodedBodySize);
perfTimingsBuffer_.erase(requestId);
}
}
}
#ifdef REACT_NATIVE_DEBUGGER_ENABLED
// Debugger enabled: CDP event handling
jsinspector_modern::NetworkHandler::getInstance().onLoadingFinished(
requestId, encodedDataLength);
// Debugger enabled: Add trace event to Performance timeline
{
int decodedBodyLength = 0;
std::lock_guard<std::mutex> lock(perfTimingsMutex_);
auto it = perfTimingsBuffer_.find(requestId);
if (it != perfTimingsBuffer_.end() &&
it->second.contentType.starts_with("image/")) {
decodedBodyLength = it->second.decodedBodySize;
}
jsinspector_modern::tracing::PerformanceTracer::getInstance()
.reportResourceFinish(
requestId, now, encodedDataLength, decodedBodyLength);
}
#endif
}
void NetworkReporter::reportRequestFailed(
const std::string& requestId,
bool cancelled) const {
#ifdef REACT_NATIVE_DEBUGGER_ENABLED
// Debugger enabled: CDP event handling
jsinspector_modern::NetworkHandler::getInstance().onLoadingFailed(
requestId, cancelled);
#endif
}
void NetworkReporter::storeResponseBody(
const std::string& requestId,
std::string_view body,
bool base64Encoded) {
#ifdef REACT_NATIVE_DEBUGGER_ENABLED
// Debugger enabled: Store fetched response body for later CDP retrieval
jsinspector_modern::NetworkHandler::getInstance().storeResponseBody(
requestId, body, base64Encoded);
#endif
}
} // namespace facebook::react

View File

@@ -0,0 +1,148 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include "NetworkTypes.h"
#include <folly/dynamic.h>
#include <react/timing/primitives.h>
#include <mutex>
#include <string>
#include <unordered_map>
namespace facebook::react {
/**
* Container for static network event metadata aligning with the
* `PerformanceResourceTiming` interface.
*
* This is a lightweight type stored in `perfTimingsBuffer_` and used for
* reporting complete events to the Web Performance subsystem. Not used for CDP
* reporting.
*/
struct ResourceTimingData {
std::string url{};
HighResTimeStamp fetchStart{};
HighResTimeStamp requestStart{};
std::optional<HighResTimeStamp> connectStart{};
std::optional<HighResTimeStamp> connectEnd{};
std::optional<HighResTimeStamp> responseStart{};
int responseStatus = 0;
std::string contentType{};
int encodedBodySize = 0;
int decodedBodySize = 0;
};
/**
* [Experimental] An interface for reporting network events to the modern
* debugger server and Web Performance APIs.
*
* In a production (non dev or profiling) build, CDP reporting is disabled.
*/
class NetworkReporter {
public:
static NetworkReporter &getInstance();
/**
* Returns whether network tracking over CDP is currently enabled.
*/
bool isDebuggingEnabled() const;
/**
* Report a network request that is about to be sent.
*
* - Corresponds to `Network.requestWillBeSent` and the
* "ResourceWillSendRequest" trace event in CDP.
* - Corresponds to `PerformanceResourceTiming.requestStart` (specifically,
* marking when the native request was initiated).
*
* https://w3c.github.io/resource-timing/#dom-performanceresourcetiming-requeststart
*/
void reportRequestStart(
const std::string &requestId,
const RequestInfo &requestInfo,
int encodedDataLength,
const std::optional<ResponseInfo> &redirectResponse);
/**
* Report timestamp for sending the network request, and (in a debug build)
* provide final headers to be reported via CDP.
*
* - Corresponds to `Network.requestWillBeSentExtraInfo` and the
* "ResourceSendRequest" trace event in CDP.
* - Corresponds to `PerformanceResourceTiming.domainLookupStart`,
* `PerformanceResourceTiming.connectStart`. Defined as "immediately before
* the browser starts to establish the connection to the server".
*
* https://w3c.github.io/resource-timing/#dom-performanceresourcetiming-connectstart
*/
void reportConnectionTiming(const std::string &requestId, const std::optional<Headers> &headers);
/**
* Report when HTTP response headers have been received, corresponding to
* when the first byte of the response is available.
*
* - Corresponds to `Network.responseReceived` and the
* "ResourceReceiveResponse" trace event in CDP.
* - Corresponds to `PerformanceResourceTiming.responseStart`.
*
* https://w3c.github.io/resource-timing/#dom-performanceresourcetiming-responsestart
*/
void reportResponseStart(const std::string &requestId, const ResponseInfo &responseInfo, int encodedDataLength);
/**
* Report when additional chunks of the response body have been received.
*
* Corresponds to `Network.dataReceived` in CDP (used for progress bar
* rendering).
*/
void reportDataReceived(const std::string &requestId, int dataLength, const std::optional<int> &encodedDataLength);
/**
* Report when a network request is complete and we are no longer receiving
* response data.
*
* - Corresponds to `Network.loadingFinished` and the "ResourceFinish" trace
* event in CDP.
* - Corresponds to `PerformanceResourceTiming.responseEnd`.
*
* https://w3c.github.io/resource-timing/#dom-performanceresourcetiming-responseend
*/
void reportResponseEnd(const std::string &requestId, int encodedDataLength);
/**
* Report when a network request has failed.
*
* Corresponds to `Network.loadingFailed` in CDP.
*/
void reportRequestFailed(const std::string &requestId, bool cancelled) const;
/**
* Store the fetched response body for a text or image network response.
* These may be retrieved by CDP clients to to render a response preview via
* `Network.getReponseBody`.
*
* Reponse bodies are stored in a bounded buffer with a fixed maximum memory
* size, where oldest responses will be evicted if the buffer is exceeded.
*
* Should be called after checking \ref NetworkReporter::isDebuggingEnabled.
*/
void storeResponseBody(const std::string &requestId, std::string_view body, bool base64Encoded);
private:
NetworkReporter() = default;
NetworkReporter(const NetworkReporter &) = delete;
NetworkReporter &operator=(const NetworkReporter &) = delete;
~NetworkReporter() = default;
std::unordered_map<std::string, ResourceTimingData> perfTimingsBuffer_{};
std::mutex perfTimingsMutex_;
};
} // namespace facebook::react

View File

@@ -0,0 +1,42 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <map>
#include <optional>
#include <string>
// Defines generic input object types for NetworkReporter.
namespace facebook::react {
/**
* A collection of parsed HTTP headers.
*/
using Headers = std::map<std::string, std::string>;
/**
* Request info from the request caller.
*/
struct RequestInfo {
std::string url;
std::string httpMethod;
std::optional<Headers> headers;
std::optional<std::string> httpBody;
};
/**
* Response info from the request caller.
*/
struct ResponseInfo {
std::string url;
uint16_t statusCode;
std::optional<Headers> headers;
};
} // namespace facebook::react

View File

@@ -0,0 +1,52 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
require "json"
package = JSON.parse(File.read(File.join(__dir__, "..", "..", "..", "package.json")))
version = package['version']
source = { :git => 'https://github.com/facebook/react-native.git' }
if version == '1000.0.0'
# This is an unpublished version, use the latest commit hash of the react-native repo, which were presumably in.
source[:commit] = `git rev-parse HEAD`.strip if system("git rev-parse --git-dir > /dev/null 2>&1")
else
source[:tag] = "v#{version}"
end
header_search_paths = []
if ENV['USE_FRAMEWORKS']
header_search_paths << "\"$(PODS_TARGET_SRCROOT)/../..\"" # this is needed to allow the feature flags access its own files
end
Pod::Spec.new do |s|
s.name = "React-networking"
s.version = version
s.summary = "Common networking modules for React Native"
s.homepage = "https://reactnative.dev/"
s.license = package["license"]
s.author = "Meta Platforms, Inc. and its affiliates"
s.platforms = min_supported_versions
s.source = source
s.source_files = podspec_sources("*.{cpp,h}", "*.h")
s.header_dir = "react/networking"
s.pod_target_xcconfig = { "CLANG_CXX_LANGUAGE_STANDARD" => rct_cxx_language_standard(),
"HEADER_SEARCH_PATHS" => header_search_paths.join(' '),
"DEFINES_MODULE" => "YES" }
if ENV['USE_FRAMEWORKS'] && ReactNativeCoreUtils.build_rncore_from_source()
s.module_name = "React_networking"
s.header_mappings_dir = "../.."
end
add_dependency(s, "React-featureflags")
add_dependency(s, "React-jsinspectornetwork", :framework_name => 'jsinspector_modernnetwork')
add_dependency(s, "React-jsinspectortracing", :framework_name => 'jsinspector_moderntracing')
s.dependency "React-performancetimeline"
s.dependency "React-timing"
add_rn_third_party_dependencies(s)
add_rncore_dependency(s)
end