Skip to content

Commit 5ccd01f

Browse files
motiz88meta-codesync[bot]
authored andcommitted
Support using the Network domain in multiple concurrent sessions
Summary: Changelog: [General][Fixed] Send network events to all CDP clients with the Network domain enabled Differential Revision: D90888854
1 parent eecfe00 commit 5ccd01f

File tree

5 files changed

+111
-39
lines changed

5 files changed

+111
-39
lines changed

packages/react-native/ReactCommon/jsinspector-modern/NetworkIOAgent.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,13 @@ class Stream : public NetworkRequestListener,
259259
};
260260
} // namespace
261261

262+
NetworkIOAgent::~NetworkIOAgent() {
263+
if (networkAgentId_) {
264+
NetworkHandler::getInstance().disableAgent(*networkAgentId_);
265+
networkAgentId_ = std::nullopt;
266+
}
267+
}
268+
262269
bool NetworkIOAgent::handleRequest(
263270
const cdp::PreparsedRequest& req,
264271
LoadNetworkResourceDelegate& delegate) {
@@ -278,15 +285,17 @@ bool NetworkIOAgent::handleRequest(
278285

279286
// @cdp Network.enable support is experimental.
280287
if (req.method == "Network.enable") {
281-
networkHandler.setFrontendChannel(frontendChannel_);
282-
networkHandler.enable();
288+
networkAgentId_ = networkHandler.enableAgent(frontendChannel_);
283289
// NOTE: Domain enable/disable responses are sent by HostAgent.
284290
return false;
285291
}
286292

287293
// @cdp Network.disable support is experimental.
288294
if (req.method == "Network.disable") {
289-
networkHandler.disable();
295+
if (networkAgentId_) {
296+
networkHandler.disableAgent(*networkAgentId_);
297+
networkAgentId_ = std::nullopt;
298+
}
290299
// NOTE: Domain enable/disable responses are sent by HostAgent.
291300
return false;
292301
}

packages/react-native/ReactCommon/jsinspector-modern/NetworkIOAgent.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include <folly/dynamic.h>
1414
#include <jsinspector-modern/cdp/CdpJson.h>
15+
#include <jsinspector-modern/network/NetworkHandler.h>
1516

1617
#include <string>
1718
#include <unordered_map>
@@ -211,6 +212,13 @@ class NetworkIOAgent {
211212
{
212213
}
213214

215+
~NetworkIOAgent();
216+
217+
NetworkIOAgent(const NetworkIOAgent &) = delete;
218+
NetworkIOAgent &operator=(const NetworkIOAgent &) = delete;
219+
NetworkIOAgent(NetworkIOAgent &&) = delete;
220+
NetworkIOAgent &operator=(NetworkIOAgent &&) = delete;
221+
214222
/**
215223
* Handle a CDP request. The response will be sent over the provided
216224
* \c FrontendChannel synchronously or asynchronously.
@@ -247,6 +255,12 @@ class NetworkIOAgent {
247255
*/
248256
unsigned long nextStreamId_{0};
249257

258+
/**
259+
* If non-nullopt, indicates that this agent has enabled the Network domain
260+
* via NetworkHandler, storing the agent ID for cleanup.
261+
*/
262+
std::optional<NetworkHandler::AgentId> networkAgentId_;
263+
250264
/**
251265
* Begin loading an HTTP resource, delegating platform-specific
252266
* implementation, responding to the frontend on headers received or on error.

packages/react-native/ReactCommon/jsinspector-modern/network/NetworkHandler.cpp

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -37,28 +37,32 @@ NetworkHandler& NetworkHandler::getInstance() {
3737
return instance;
3838
}
3939

40-
void NetworkHandler::setFrontendChannel(FrontendChannel frontendChannel) {
41-
frontendChannel_ = std::move(frontendChannel);
40+
NetworkHandler::AgentId NetworkHandler::enableAgent(
41+
FrontendChannel frontendChannel) {
42+
std::lock_guard<std::mutex> lock(agentsMutex_);
43+
AgentId id = nextAgentId_++;
44+
agents_.push_back({id, std::move(frontendChannel)});
45+
enabled_.store(true, std::memory_order_release);
46+
return id;
4247
}
4348

44-
bool NetworkHandler::enable() {
45-
if (enabled_.load(std::memory_order_acquire)) {
46-
return false;
47-
}
49+
void NetworkHandler::disableAgent(AgentId agentId) {
50+
std::lock_guard<std::mutex> lock(agentsMutex_);
51+
agents_.remove_if(
52+
[agentId](const AgentRecord& r) { return r.id == agentId; });
53+
if (agents_.empty()) {
54+
enabled_.store(false, std::memory_order_release);
4855

49-
enabled_.store(true, std::memory_order_release);
50-
return true;
56+
std::lock_guard<std::mutex> lock2(requestBodyMutex_);
57+
responseBodyBuffer_.clear();
58+
}
5159
}
5260

53-
bool NetworkHandler::disable() {
54-
if (!enabled_.load(std::memory_order_acquire)) {
55-
return false;
61+
void NetworkHandler::sendToAllAgents(std::string_view message) {
62+
std::lock_guard<std::mutex> lock(agentsMutex_);
63+
for (const auto& agent : agents_) {
64+
agent.channel(message);
5665
}
57-
58-
enabled_.store(false, std::memory_order_release);
59-
std::lock_guard<std::mutex> lock(requestBodyMutex_);
60-
responseBodyBuffer_.clear();
61-
return true;
6266
}
6367

6468
void NetworkHandler::onRequestWillBeSent(
@@ -89,7 +93,7 @@ void NetworkHandler::onRequestWillBeSent(
8993
.redirectResponse = redirectResponse,
9094
};
9195

92-
frontendChannel_(
96+
sendToAllAgents(
9397
cdp::jsonNotification("Network.requestWillBeSent", params.toDynamic()));
9498
}
9599

@@ -106,7 +110,7 @@ void NetworkHandler::onRequestWillBeSentExtraInfo(
106110
.connectTiming = {.requestTime = getCurrentUnixTimestampSeconds()},
107111
};
108112

109-
frontendChannel_(
113+
sendToAllAgents(
110114
cdp::jsonNotification(
111115
"Network.requestWillBeSentExtraInfo", params.toDynamic()));
112116
}
@@ -133,7 +137,7 @@ void NetworkHandler::onResponseReceived(
133137
.hasExtraInfo = false,
134138
};
135139

136-
frontendChannel_(
140+
sendToAllAgents(
137141
cdp::jsonNotification("Network.responseReceived", params.toDynamic()));
138142
}
139143

@@ -152,7 +156,7 @@ void NetworkHandler::onDataReceived(
152156
.encodedDataLength = encodedDataLength,
153157
};
154158

155-
frontendChannel_(
159+
sendToAllAgents(
156160
cdp::jsonNotification("Network.dataReceived", params.toDynamic()));
157161
}
158162

@@ -169,7 +173,7 @@ void NetworkHandler::onLoadingFinished(
169173
.encodedDataLength = encodedDataLength,
170174
};
171175

172-
frontendChannel_(
176+
sendToAllAgents(
173177
cdp::jsonNotification("Network.loadingFinished", params.toDynamic()));
174178
}
175179

@@ -192,7 +196,7 @@ void NetworkHandler::onLoadingFailed(
192196
.canceled = cancelled,
193197
};
194198

195-
frontendChannel_(
199+
sendToAllAgents(
196200
cdp::jsonNotification("Network.loadingFailed", params.toDynamic()));
197201
}
198202
}

packages/react-native/ReactCommon/jsinspector-modern/network/NetworkHandler.h

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <folly/dynamic.h>
1414

1515
#include <atomic>
16+
#include <list>
1617
#include <mutex>
1718
#include <string>
1819
#include <tuple>
@@ -33,27 +34,25 @@ using Headers = std::map<std::string, std::string>;
3334
*/
3435
class NetworkHandler {
3536
public:
36-
static NetworkHandler &getInstance();
37-
3837
/**
39-
* Set the channel used to send CDP events to the frontend. This should be
40-
* supplied before calling `enable`.
38+
* Ephemeral identifier for a registered agent, used to unregister.
4139
*/
42-
void setFrontendChannel(FrontendChannel frontendChannel);
40+
using AgentId = uint32_t;
41+
42+
static NetworkHandler &getInstance();
4343

4444
/**
45-
* Enable network debugging. Returns `false` if already enabled.
46-
*
47-
* @cdp Network.enable
45+
* Register a frontend channel for receiving Network domain events.
46+
* Implicitly enables the domain if this is the first agent.
47+
* \returns An AgentId to be passed to disableAgent() on cleanup.
4848
*/
49-
bool enable();
49+
AgentId enableAgent(FrontendChannel frontendChannel);
5050

5151
/**
52-
* Disable network debugging. Returns `false` if not initially enabled.
53-
*
54-
* @cdp Network.disable
52+
* Unregister a frontend channel by its AgentId.
53+
* Implicitly disables the domain if this was the last agent.
5554
*/
56-
bool disable();
55+
void disableAgent(AgentId agentId);
5756

5857
/**
5958
* Returns whether network debugging is currently enabled.
@@ -134,7 +133,19 @@ class NetworkHandler {
134133

135134
std::optional<folly::dynamic> consumeStoredRequestInitiator(const std::string &requestId);
136135

137-
FrontendChannel frontendChannel_;
136+
/**
137+
* Send a message to all registered frontend channels.
138+
*/
139+
void sendToAllAgents(std::string_view message);
140+
141+
struct AgentRecord {
142+
AgentId id;
143+
FrontendChannel channel;
144+
};
145+
146+
std::list<AgentRecord> agents_;
147+
AgentId nextAgentId_{1};
148+
std::mutex agentsMutex_;
138149

139150
std::map<std::string, std::string> resourceTypeMap_{};
140151
std::map<std::string, folly::dynamic> requestInitiatorById_{};

packages/react-native/ReactCommon/jsinspector-modern/tests/NetworkReporterTest.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,40 @@ TEST_P(NetworkReporterTest, testCreateRequestIdWithoutNetworkDomain) {
588588
EXPECT_NE(id1, id2);
589589
}
590590

591+
TEST_P(NetworkReporterTest, testTwoSessionsReceiveNetworkEvents) {
592+
auto secondary = this->connectSecondary();
593+
594+
this->expectMessageFromPage(JsonEq(R"({"id": 1, "result": {}})"));
595+
this->toPage_->sendMessage(R"({"id": 1, "method": "Network.enable"})");
596+
597+
EXPECT_CALL(
598+
secondary.fromPage(), onMessage(JsonEq(R"({"id": 2, "result": {}})")));
599+
secondary.toPage().sendMessage(R"({"id": 2, "method": "Network.enable"})");
600+
601+
// Both sessions should receive the network event
602+
this->expectMessageFromPage(JsonParsed(AllOf(
603+
AtJsonPtr("/method", "Network.requestWillBeSent"),
604+
AtJsonPtr("/params/requestId", "multi-session-request"))));
605+
EXPECT_CALL(
606+
secondary.fromPage(),
607+
onMessage(JsonParsed(AllOf(
608+
AtJsonPtr("/method", "Network.requestWillBeSent"),
609+
AtJsonPtr("/params/requestId", "multi-session-request")))));
610+
611+
RequestInfo requestInfo;
612+
requestInfo.url = "https://example.com/test";
613+
requestInfo.httpMethod = "GET";
614+
NetworkReporter::getInstance().reportRequestStart(
615+
"multi-session-request", requestInfo, 0, std::nullopt);
616+
617+
this->expectMessageFromPage(JsonEq(R"({"id": 3, "result": {}})"));
618+
this->toPage_->sendMessage(R"({"id": 3, "method": "Network.disable"})");
619+
620+
EXPECT_CALL(
621+
secondary.fromPage(), onMessage(JsonEq(R"({"id": 4, "result": {}})")));
622+
secondary.toPage().sendMessage(R"({"id": 4, "method": "Network.disable"})");
623+
}
624+
591625
struct NetworkReporterTracingTestParams {
592626
bool enableNetworkEventReporting;
593627
bool enableNetworkDomain;

0 commit comments

Comments
 (0)