Skip to content

Commit daf0a44

Browse files
authored
inspector: add network payload buffer size limits
By default, the total buffered payloads are limited to 100MB, and 5MB for each single request. The oldest unused requests will be evicted first when the buffer size limit has been exceeded. PR-URL: #60236 Refs: https://chromedevtools.github.io/devtools-protocol/tot/Network/#method-enable Reviewed-By: Ryuhei Shima <[email protected]> Reviewed-By: Darshan Sen <[email protected]>
1 parent 170848b commit daf0a44

File tree

6 files changed

+434
-53
lines changed

6 files changed

+434
-53
lines changed

node.gyp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,7 @@
425425
'test/cctest/test_quic_tokens.cc',
426426
],
427427
'node_cctest_inspector_sources': [
428+
'test/cctest/inspector/test_network_requests_buffer.cc',
428429
'test/cctest/inspector/test_node_protocol.cc',
429430
'test/cctest/test_inspector_socket.cc',
430431
'test/cctest/test_inspector_socket_server.cc',

src/inspector/network_agent.cc

Lines changed: 42 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ using v8::Object;
2626
using v8::Uint8Array;
2727
using v8::Value;
2828

29+
constexpr size_t kDefaultMaxTotalBufferSize = 100 * 1024 * 1024; // 100MB
30+
2931
// Get a protocol string property from the object.
3032
Maybe<protocol::String> ObjectGetProtocolString(v8::Local<v8::Context> context,
3133
Local<Object> object,
@@ -246,7 +248,8 @@ NetworkAgent::NetworkAgent(
246248
: inspector_(inspector),
247249
v8_inspector_(v8_inspector),
248250
env_(env),
249-
network_resource_manager_(std::move(network_resource_manager)) {
251+
network_resource_manager_(std::move(network_resource_manager)),
252+
requests_(kDefaultMaxTotalBufferSize) {
250253
event_notifier_map_["requestWillBeSent"] = &NetworkAgent::requestWillBeSent;
251254
event_notifier_map_["responseReceived"] = &NetworkAgent::responseReceived;
252255
event_notifier_map_["loadingFailed"] = &NetworkAgent::loadingFailed;
@@ -329,8 +332,15 @@ void NetworkAgent::Wire(protocol::UberDispatcher* dispatcher) {
329332
protocol::Network::Dispatcher::wire(dispatcher, this);
330333
}
331334

332-
protocol::DispatchResponse NetworkAgent::enable() {
335+
protocol::DispatchResponse NetworkAgent::enable(
336+
std::optional<int> in_maxTotalBufferSize,
337+
std::optional<int> in_maxResourceBufferSize) {
333338
inspector_->Enable();
339+
requests_ = RequestsBuffer(
340+
in_maxTotalBufferSize.value_or(kDefaultMaxTotalBufferSize));
341+
if (in_maxResourceBufferSize) {
342+
max_resource_buffer_size_ = *in_maxResourceBufferSize;
343+
}
334344
return protocol::DispatchResponse::Success();
335345
}
336346

@@ -341,7 +351,7 @@ protocol::DispatchResponse NetworkAgent::disable() {
341351

342352
protocol::DispatchResponse NetworkAgent::getRequestPostData(
343353
const protocol::String& in_requestId, protocol::String* out_postData) {
344-
auto request_entry = requests_.find(in_requestId);
354+
auto request_entry = requests_.cfind(in_requestId);
345355
if (request_entry == requests_.end()) {
346356
// Request not found, ignore it.
347357
return protocol::DispatchResponse::InvalidParams("Request not found");
@@ -362,7 +372,7 @@ protocol::DispatchResponse NetworkAgent::getRequestPostData(
362372

363373
// Concat response bodies.
364374
protocol::Binary buf =
365-
protocol::Binary::concat(request_entry->second.request_data_blobs);
375+
protocol::Binary::concat(request_entry->second.request_data_blobs());
366376
*out_postData = protocol::StringUtil::fromUTF8(buf.data(), buf.size());
367377
return protocol::DispatchResponse::Success();
368378
}
@@ -371,7 +381,7 @@ protocol::DispatchResponse NetworkAgent::getResponseBody(
371381
const protocol::String& in_requestId,
372382
protocol::String* out_body,
373383
bool* out_base64Encoded) {
374-
auto request_entry = requests_.find(in_requestId);
384+
auto request_entry = requests_.cfind(in_requestId);
375385
if (request_entry == requests_.end()) {
376386
// Request not found, ignore it.
377387
return protocol::DispatchResponse::InvalidParams("Request not found");
@@ -391,7 +401,7 @@ protocol::DispatchResponse NetworkAgent::getResponseBody(
391401

392402
// Concat response bodies.
393403
protocol::Binary buf =
394-
protocol::Binary::concat(request_entry->second.response_data_blobs);
404+
protocol::Binary::concat(request_entry->second.response_data_blobs());
395405
if (request_entry->second.response_charset == Charset::kBinary) {
396406
// If the response is binary, we return base64 encoded data.
397407
*out_body = buf.toBase64();
@@ -410,22 +420,26 @@ protocol::DispatchResponse NetworkAgent::getResponseBody(
410420

411421
protocol::DispatchResponse NetworkAgent::streamResourceContent(
412422
const protocol::String& in_requestId, protocol::Binary* out_bufferedData) {
413-
auto it = requests_.find(in_requestId);
414-
if (it == requests_.end()) {
415-
// Request not found, ignore it.
416-
return protocol::DispatchResponse::InvalidParams("Request not found");
417-
}
418-
auto& request_entry = it->second;
423+
bool is_response_finished = false;
424+
{
425+
auto it = requests_.find(in_requestId);
426+
if (it == requests_.end()) {
427+
// Request not found, ignore it.
428+
return protocol::DispatchResponse::InvalidParams("Request not found");
429+
}
430+
auto& request_entry = it->second;
419431

420-
request_entry.is_streaming = true;
432+
request_entry.is_streaming = true;
421433

422-
// Concat response bodies.
423-
*out_bufferedData =
424-
protocol::Binary::concat(request_entry.response_data_blobs);
425-
// Clear buffered data.
426-
request_entry.response_data_blobs.clear();
434+
// Concat response bodies.
435+
*out_bufferedData =
436+
protocol::Binary::concat(request_entry.response_data_blobs());
437+
// Clear buffered data.
438+
request_entry.clear_response_data_blobs();
439+
is_response_finished = request_entry.is_response_finished;
440+
}
427441

428-
if (request_entry.is_response_finished) {
442+
if (is_response_finished) {
429443
// If the request is finished, remove the entry.
430444
requests_.erase(in_requestId);
431445
}
@@ -500,9 +514,11 @@ void NetworkAgent::requestWillBeSent(v8::Local<v8::Context> context,
500514
}
501515

502516
auto request_charset = charset == "utf-8" ? Charset::kUTF8 : Charset::kBinary;
503-
requests_.emplace(
504-
request_id,
505-
RequestEntry(timestamp, request_charset, request->getHasPostData()));
517+
requests_.emplace(request_id,
518+
RequestEntry(timestamp,
519+
request_charset,
520+
request->getHasPostData(),
521+
max_resource_buffer_size_));
506522
frontend_->requestWillBeSent(request_id,
507523
std::move(request),
508524
std::move(initiator),
@@ -580,7 +596,7 @@ void NetworkAgent::loadingFinished(v8::Local<v8::Context> context,
580596

581597
frontend_->loadingFinished(request_id, timestamp);
582598

583-
auto request_entry = requests_.find(request_id);
599+
auto request_entry = requests_.cfind(request_id);
584600
if (request_entry == requests_.end()) {
585601
// No entry found. Ignore it.
586602
return;
@@ -590,7 +606,7 @@ void NetworkAgent::loadingFinished(v8::Local<v8::Context> context,
590606
// Streaming finished, remove the entry.
591607
requests_.erase(request_id);
592608
} else {
593-
request_entry->second.is_response_finished = true;
609+
requests_.find(request_id)->second.is_response_finished = true;
594610
}
595611
}
596612

@@ -631,7 +647,7 @@ void NetworkAgent::dataSent(v8::Local<v8::Context> context,
631647
}
632648
Local<Uint8Array> data = data_obj.As<Uint8Array>();
633649
auto data_bin = protocol::Binary::fromUint8Array(data);
634-
request_entry->second.request_data_blobs.push_back(data_bin);
650+
request_entry->second.push_request_data_blob(data_bin);
635651
}
636652

637653
void NetworkAgent::dataReceived(v8::Local<v8::Context> context,
@@ -673,7 +689,7 @@ void NetworkAgent::dataReceived(v8::Local<v8::Context> context,
673689
frontend_->dataReceived(
674690
request_id, timestamp, data_length, encoded_data_length, data_bin);
675691
} else {
676-
request_entry.response_data_blobs.push_back(data_bin);
692+
request_entry.push_response_data_blob(data_bin);
677693
}
678694
}
679695

src/inspector/network_agent.h

Lines changed: 10 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#include "env.h"
55
#include "io_agent.h"
6+
#include "network_requests_buffer.h"
67
#include "network_resource_manager.h"
78
#include "node/inspector/protocol/Network.h"
89

@@ -15,31 +16,6 @@ namespace inspector {
1516

1617
class NetworkInspector;
1718

18-
// Supported charsets for devtools frontend on request/response data.
19-
// If the charset is kUTF8, the data is expected to be text and can be
20-
// formatted on the frontend.
21-
enum class Charset {
22-
kUTF8,
23-
kBinary,
24-
};
25-
26-
struct RequestEntry {
27-
double timestamp;
28-
bool is_request_finished = false;
29-
bool is_response_finished = false;
30-
bool is_streaming = false;
31-
Charset request_charset;
32-
std::vector<protocol::Binary> request_data_blobs;
33-
Charset response_charset;
34-
std::vector<protocol::Binary> response_data_blobs;
35-
36-
RequestEntry(double timestamp, Charset request_charset, bool has_request_body)
37-
: timestamp(timestamp),
38-
is_request_finished(!has_request_body),
39-
request_charset(request_charset),
40-
response_charset(Charset::kBinary) {}
41-
};
42-
4319
class NetworkAgent : public protocol::Network::Backend {
4420
public:
4521
explicit NetworkAgent(
@@ -50,7 +26,9 @@ class NetworkAgent : public protocol::Network::Backend {
5026

5127
void Wire(protocol::UberDispatcher* dispatcher);
5228

53-
protocol::DispatchResponse enable() override;
29+
protocol::DispatchResponse enable(
30+
std::optional<int> in_maxTotalBufferSize,
31+
std::optional<int> in_maxResourceBufferSize) override;
5432

5533
protocol::DispatchResponse disable() override;
5634

@@ -104,12 +82,17 @@ class NetworkAgent : public protocol::Network::Backend {
10482
NetworkInspector* inspector_;
10583
v8_inspector::V8Inspector* v8_inspector_;
10684
std::shared_ptr<protocol::Network::Frontend> frontend_;
85+
10786
using EventNotifier = void (NetworkAgent::*)(v8::Local<v8::Context> context,
10887
v8::Local<v8::Object>);
10988
std::unordered_map<protocol::String, EventNotifier> event_notifier_map_;
110-
std::map<protocol::String, RequestEntry> requests_;
11189
Environment* env_;
11290
std::shared_ptr<NetworkResourceManager> network_resource_manager_;
91+
92+
// Per-resource buffer size in bytes to use when preserving network payloads
93+
// (XHRs, etc).
94+
size_t max_resource_buffer_size_ = 5 * 1024 * 1024; // 5MB
95+
RequestsBuffer requests_;
11396
};
11497

11598
} // namespace inspector

0 commit comments

Comments
 (0)