Skip to content

Commit 85d6a28

Browse files
islandryutargos
authored andcommitted
inspector: initial support for Network.loadNetworkResource
Fixes: #57873 PR-URL: #58077 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
1 parent 2178007 commit 85d6a28

25 files changed

+613
-26
lines changed

doc/api/cli.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1031,6 +1031,17 @@ passing a second `parentURL` argument for contextual resolution.
10311031

10321032
Previously gated the entire `import.meta.resolve` feature.
10331033

1034+
### `--experimental-inspector-network-resource`
1035+
1036+
<!-- YAML
1037+
added:
1038+
- REPLACEME
1039+
-->
1040+
1041+
> Stability: 1.1 - Active Development
1042+
1043+
Enable experimental support for inspector network resources.
1044+
10341045
### `--experimental-loader=module`
10351046

10361047
<!-- YAML

doc/api/inspector.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -598,6 +598,43 @@ This feature is only available with the `--experimental-network-inspection` flag
598598
Broadcasts the `Network.loadingFailed` event to connected frontends. This event indicates that
599599
HTTP request has failed to load.
600600

601+
### `inspector.NetworkResources.put`
602+
603+
<!-- YAML
604+
added:
605+
- REPLACEME
606+
-->
607+
608+
> Stability: 1.1 - Active Development
609+
610+
This feature is only available with the `--experimental-inspector-network-resource` flag enabled.
611+
612+
The inspector.NetworkResources.put method is used to provide a response for a loadNetworkResource
613+
request issued via the Chrome DevTools Protocol (CDP).
614+
This is typically triggered when a source map is specified by URL, and a DevTools frontend—such as
615+
Chrome—requests the resource to retrieve the source map.
616+
617+
This method allows developers to predefine the resource content to be served in response to such CDP requests.
618+
619+
```js
620+
const inspector = require('node:inspector');
621+
// By preemptively calling put to register the resource, a source map can be resolved when
622+
// a loadNetworkResource request is made from the frontend.
623+
async function setNetworkResources() {
624+
const mapUrl = 'http://localhost:3000/dist/app.js.map';
625+
const tsUrl = 'http://localhost:3000/src/app.ts';
626+
const distAppJsMap = await fetch(mapUrl).then((res) => res.text());
627+
const srcAppTs = await fetch(tsUrl).then((res) => res.text());
628+
inspector.NetworkResources.put(mapUrl, distAppJsMap);
629+
inspector.NetworkResources.put(tsUrl, srcAppTs);
630+
};
631+
setNetworkResources().then(() => {
632+
require('./dist/app');
633+
});
634+
```
635+
636+
For more details, see the official CDP documentation: [Network.loadNetworkResource](https://chromedevtools.github.io/devtools-protocol/tot/Network/#method-loadNetworkResource)
637+
601638
## Support of breakpoints
602639

603640
The Chrome DevTools Protocol [`Debugger` domain][] allows an

doc/node.1

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,9 @@ Enable experimental WebAssembly module support.
226226
.It Fl -experimental-quic
227227
Enable the experimental QUIC support.
228228
.
229+
.It Fl -experimental-inspector-network-resource
230+
Enable experimental support for inspector network resources.
231+
.
229232
.It Fl -force-context-aware
230233
Disable loading native addons that are not context-aware.
231234
.

lib/inspector.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ const {
3636
} = require('internal/validators');
3737
const { isMainThread } = require('worker_threads');
3838
const { _debugEnd } = internalBinding('process_methods');
39+
const {
40+
put,
41+
} = require('internal/inspector/network_resources');
3942

4043
const {
4144
Connection,
@@ -218,6 +221,10 @@ const Network = {
218221
dataReceived: (params) => broadcastToFrontend('Network.dataReceived', params),
219222
};
220223

224+
const NetworkResources = {
225+
put,
226+
};
227+
221228
module.exports = {
222229
open: inspectorOpen,
223230
close: _debugEnd,
@@ -226,4 +233,5 @@ module.exports = {
226233
console,
227234
Session,
228235
Network,
236+
NetworkResources,
229237
};
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
'use strict';
2+
3+
const { getOptionValue } = require('internal/options');
4+
const { validateString } = require('internal/validators');
5+
const { putNetworkResource } = internalBinding('inspector');
6+
7+
/**
8+
* Registers a resource for the inspector using the internal 'putNetworkResource' binding.
9+
* @param {string} url - The URL of the resource.
10+
* @param {string} data - The content of the resource to provide.
11+
*/
12+
function put(url, data) {
13+
if (!getOptionValue('--experimental-inspector-network-resource')) {
14+
process.emitWarning(
15+
'The --experimental-inspector-network-resource option is not enabled. ' +
16+
'Please enable it to use the putNetworkResource function');
17+
return;
18+
}
19+
validateString(url, 'url');
20+
validateString(data, 'data');
21+
22+
putNetworkResource(url, data);
23+
}
24+
25+
module.exports = {
26+
put,
27+
};

src/inspector/io_agent.cc

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#include "io_agent.h"
2+
#include <algorithm>
3+
#include <iostream>
4+
#include <string>
5+
#include <string_view>
6+
#include "crdtp/dispatch.h"
7+
#include "inspector/network_resource_manager.h"
8+
9+
namespace node::inspector::protocol {
10+
11+
void IoAgent::Wire(UberDispatcher* dispatcher) {
12+
frontend_ = std::make_shared<IO::Frontend>(dispatcher->channel());
13+
IO::Dispatcher::wire(dispatcher, this);
14+
}
15+
16+
DispatchResponse IoAgent::read(const String& in_handle,
17+
std::optional<int> in_offset,
18+
std::optional<int> in_size,
19+
String* out_data,
20+
bool* out_eof) {
21+
std::string url = in_handle;
22+
std::string txt = network_resource_manager_->Get(url);
23+
std::string_view txt_view(txt);
24+
25+
int offset = 0;
26+
bool offset_was_specified = false;
27+
if (in_offset.has_value()) {
28+
offset = *in_offset;
29+
offset_was_specified = true;
30+
} else if (offset_map_.find(url) != offset_map_.end()) {
31+
offset = offset_map_[url];
32+
}
33+
int size = 1 << 20;
34+
if (in_size.has_value()) {
35+
size = *in_size;
36+
}
37+
if (static_cast<std::size_t>(offset) < txt_view.length()) {
38+
std::string_view out_view = txt_view.substr(offset, size);
39+
out_data->assign(out_view.data(), out_view.size());
40+
*out_eof = false;
41+
if (!offset_was_specified) {
42+
offset_map_[url] = offset + size;
43+
}
44+
} else {
45+
*out_data = "";
46+
*out_eof = true;
47+
}
48+
49+
return DispatchResponse::Success();
50+
}
51+
52+
DispatchResponse IoAgent::close(const String& in_handle) {
53+
std::string url = in_handle;
54+
network_resource_manager_->Erase(url);
55+
return DispatchResponse::Success();
56+
}
57+
} // namespace node::inspector::protocol

src/inspector/io_agent.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#ifndef SRC_INSPECTOR_IO_AGENT_H_
2+
#define SRC_INSPECTOR_IO_AGENT_H_
3+
4+
#include <memory>
5+
#include "inspector/network_resource_manager.h"
6+
#include "node/inspector/protocol/IO.h"
7+
8+
namespace node::inspector::protocol {
9+
10+
class IoAgent : public IO::Backend {
11+
public:
12+
explicit IoAgent(
13+
std::shared_ptr<NetworkResourceManager> network_resource_manager)
14+
: network_resource_manager_(std::move(network_resource_manager)) {}
15+
void Wire(UberDispatcher* dispatcher);
16+
DispatchResponse read(const String& in_handle,
17+
std::optional<int> in_offset,
18+
std::optional<int> in_size,
19+
String* out_data,
20+
bool* out_eof) override;
21+
DispatchResponse close(const String& in_handle) override;
22+
23+
private:
24+
std::shared_ptr<IO::Frontend> frontend_;
25+
std::unordered_map<std::string, int> offset_map_ =
26+
{}; // Maps stream_id to offset
27+
std::shared_ptr<NetworkResourceManager> network_resource_manager_;
28+
};
29+
} // namespace node::inspector::protocol
30+
#endif // SRC_INSPECTOR_IO_AGENT_H_

src/inspector/network_agent.cc

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
#include "network_agent.h"
2+
#include <string>
23
#include "debug_utils-inl.h"
4+
#include "env-inl.h"
5+
#include "inspector/network_resource_manager.h"
36
#include "inspector/protocol_helper.h"
47
#include "network_inspector.h"
8+
#include "node_metadata.h"
59
#include "util-inl.h"
10+
#include "uv.h"
11+
#include "v8-context.h"
612
#include "v8.h"
713

814
namespace node {
@@ -202,9 +208,15 @@ std::unique_ptr<protocol::Network::Response> createResponseFromObject(
202208
.build();
203209
}
204210

205-
NetworkAgent::NetworkAgent(NetworkInspector* inspector,
206-
v8_inspector::V8Inspector* v8_inspector)
207-
: inspector_(inspector), v8_inspector_(v8_inspector) {
211+
NetworkAgent::NetworkAgent(
212+
NetworkInspector* inspector,
213+
v8_inspector::V8Inspector* v8_inspector,
214+
Environment* env,
215+
std::shared_ptr<NetworkResourceManager> network_resource_manager)
216+
: inspector_(inspector),
217+
v8_inspector_(v8_inspector),
218+
env_(env),
219+
network_resource_manager_(std::move(network_resource_manager)) {
208220
event_notifier_map_["requestWillBeSent"] = &NetworkAgent::requestWillBeSent;
209221
event_notifier_map_["responseReceived"] = &NetworkAgent::responseReceived;
210222
event_notifier_map_["loadingFailed"] = &NetworkAgent::loadingFailed;
@@ -329,10 +341,38 @@ protocol::DispatchResponse NetworkAgent::streamResourceContent(
329341
// If the request is finished, remove the entry.
330342
requests_.erase(in_requestId);
331343
}
332-
333344
return protocol::DispatchResponse::Success();
334345
}
335346

347+
protocol::DispatchResponse NetworkAgent::loadNetworkResource(
348+
const protocol::String& in_url,
349+
std::unique_ptr<protocol::Network::LoadNetworkResourcePageResult>*
350+
out_resource) {
351+
if (!env_->options()->experimental_inspector_network_resource) {
352+
return protocol::DispatchResponse::ServerError(
353+
"Network resource loading is not enabled. This feature is "
354+
"experimental and requires --experimental-inspector-network-resource "
355+
"flag to be set.");
356+
}
357+
CHECK_NOT_NULL(network_resource_manager_);
358+
std::string data = network_resource_manager_->Get(in_url);
359+
bool found = !data.empty();
360+
if (found) {
361+
auto result = protocol::Network::LoadNetworkResourcePageResult::create()
362+
.setSuccess(true)
363+
.setStream(in_url)
364+
.build();
365+
*out_resource = std::move(result);
366+
return protocol::DispatchResponse::Success();
367+
} else {
368+
auto result = protocol::Network::LoadNetworkResourcePageResult::create()
369+
.setSuccess(false)
370+
.build();
371+
*out_resource = std::move(result);
372+
return protocol::DispatchResponse::Success();
373+
}
374+
}
375+
336376
void NetworkAgent::requestWillBeSent(v8::Local<v8::Context> context,
337377
v8::Local<v8::Object> params) {
338378
protocol::String request_id;

src/inspector/network_agent.h

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
#ifndef SRC_INSPECTOR_NETWORK_AGENT_H_
22
#define SRC_INSPECTOR_NETWORK_AGENT_H_
33

4+
#include "env.h"
5+
#include "io_agent.h"
6+
#include "network_resource_manager.h"
47
#include "node/inspector/protocol/Network.h"
58

69
#include <map>
10+
#include <memory>
711
#include <unordered_map>
812

913
namespace node {
@@ -38,8 +42,11 @@ struct RequestEntry {
3842

3943
class NetworkAgent : public protocol::Network::Backend {
4044
public:
41-
explicit NetworkAgent(NetworkInspector* inspector,
42-
v8_inspector::V8Inspector* v8_inspector);
45+
explicit NetworkAgent(
46+
NetworkInspector* inspector,
47+
v8_inspector::V8Inspector* v8_inspector,
48+
Environment* env,
49+
std::shared_ptr<NetworkResourceManager> network_resource_manager);
4350

4451
void Wire(protocol::UberDispatcher* dispatcher);
4552

@@ -60,6 +67,11 @@ class NetworkAgent : public protocol::Network::Backend {
6067
const protocol::String& in_requestId,
6168
protocol::Binary* out_bufferedData) override;
6269

70+
protocol::DispatchResponse loadNetworkResource(
71+
const protocol::String& in_url,
72+
std::unique_ptr<protocol::Network::LoadNetworkResourcePageResult>*
73+
out_resource) override;
74+
6375
void emitNotification(v8::Local<v8::Context> context,
6476
const protocol::String& event,
6577
v8::Local<v8::Object> params);
@@ -89,6 +101,8 @@ class NetworkAgent : public protocol::Network::Backend {
89101
v8::Local<v8::Object>);
90102
std::unordered_map<protocol::String, EventNotifier> event_notifier_map_;
91103
std::map<protocol::String, RequestEntry> requests_;
104+
Environment* env_;
105+
std::shared_ptr<NetworkResourceManager> network_resource_manager_;
92106
};
93107

94108
} // namespace inspector

src/inspector/network_inspector.cc

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,15 @@
33
namespace node {
44
namespace inspector {
55

6-
NetworkInspector::NetworkInspector(Environment* env,
7-
v8_inspector::V8Inspector* v8_inspector)
8-
: enabled_(false), env_(env) {
9-
network_agent_ = std::make_unique<NetworkAgent>(this, v8_inspector);
6+
NetworkInspector::NetworkInspector(
7+
Environment* env,
8+
v8_inspector::V8Inspector* v8_inspector,
9+
std::shared_ptr<NetworkResourceManager> network_resource_manager)
10+
: enabled_(false),
11+
env_(env),
12+
network_resource_manager_(std::move(network_resource_manager)) {
13+
network_agent_ = std::make_unique<NetworkAgent>(
14+
this, v8_inspector, env, network_resource_manager_);
1015
}
1116
NetworkInspector::~NetworkInspector() {
1217
network_agent_.reset();

0 commit comments

Comments
 (0)