Skip to content

Commit ce745ca

Browse files
committed
put method api
1 parent 2e503fe commit ce745ca

26 files changed

+371
-592
lines changed

doc/api/cli.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1066,8 +1066,7 @@ added:
10661066

10671067
> Stability: 1.1 - Active Development
10681068
1069-
Enables the Network.loadNetworkResource method in the Chrome DevTools Protocol (CDP) during debugging sessions.
1070-
This feature allows DevTools to fetch additional resources directly through the inspector backend.
1069+
Enable experimental support for inspector network resources.
10711070

10721071
### `--experimental-loader=module`
10731072

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

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
};

lib/internal/inspector/fall_through_handle.js

Lines changed: 0 additions & 29 deletions
This file was deleted.

lib/internal/inspector/load_network_resource_worker.js

Lines changed: 0 additions & 55 deletions
This file was deleted.
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+
};

lib/internal/modules/run_main.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -136,10 +136,6 @@ function runEntryPointWithESMLoader(callback) {
136136
* @param {string} main - First positional CLI argument, such as `'entry.js'` from `node entry.js`
137137
*/
138138
function executeUserEntryPoint(main = process.argv[1]) {
139-
if (getOptionValue('--experimental-inspector-network-resource')) {
140-
require('internal/inspector/fall_through_handle').spawnLoadNetworkResourceWorker();
141-
}
142-
143139
let useESMLoader;
144140
let resolvedMain;
145141
if (getOptionValue('--entry-url')) {

src/inspector/io_agent.cc

Lines changed: 28 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
#include "io_agent.h"
22
#include <algorithm>
3+
#include <iostream>
34
#include <string>
5+
#include <string_view>
46
#include "crdtp/dispatch.h"
5-
#include "node_mutex.h"
7+
#include "inspector/network_resource_manager.h"
68

79
namespace node::inspector::protocol {
810

@@ -11,75 +13,67 @@ void IoAgent::Wire(UberDispatcher* dispatcher) {
1113
IO::Dispatcher::wire(dispatcher, this);
1214
}
1315

14-
std::unordered_map<int, int> IoAgent::offset_map_;
15-
std::unordered_map<int, std::string> IoAgent::data_map_;
16-
std::atomic<int> IoAgent::stream_counter_{1};
17-
Mutex IoAgent::data_mutex_;
18-
19-
int IoAgent::setData(const std::string& value) {
20-
int key = getNextStreamId();
21-
Mutex::ScopedLock lock(data_mutex_);
22-
data_map_[key] = value;
23-
24-
return key;
25-
}
26-
27-
int IoAgent::getNextStreamId() {
28-
return stream_counter_++;
29-
}
30-
3116
DispatchResponse IoAgent::read(const String& in_handle,
3217
Maybe<int> in_offset,
3318
Maybe<int> in_size,
3419
String* out_data,
3520
bool* out_eof) {
36-
Mutex::ScopedReadLock lock(data_mutex_);
3721
std::string in_handle_str = in_handle;
38-
int stream_id = 0;
22+
uint64_t stream_id = 0;
3923
bool is_number =
4024
std::all_of(in_handle_str.begin(), in_handle_str.end(), ::isdigit);
4125
if (!is_number) {
42-
out_data = new String("");
26+
*out_data = "";
4327
*out_eof = true;
4428
return DispatchResponse::Success();
4529
}
46-
stream_id = std::stoi(in_handle_str);
30+
stream_id = std::stoull(in_handle_str);
31+
32+
std::string url = NetworkResourceManager::GetUrlForStreamId(stream_id);
33+
if (url.empty()) {
34+
*out_data = "";
35+
*out_eof = true;
36+
return DispatchResponse::Success();
37+
}
38+
std::string txt = NetworkResourceManager::Get(url);
39+
std::string_view txt_view(txt);
4740

48-
std::string txt = data_map_[stream_id];
4941
int offset = 0;
42+
bool offset_was_specified = false;
5043
if (in_offset.isJust()) {
5144
offset = in_offset.fromJust();
45+
offset_was_specified = true;
5246
} else if (offset_map_.find(stream_id) != offset_map_.end()) {
5347
offset = offset_map_[stream_id];
5448
}
5549
int size = 1 << 20;
5650
if (in_size.isJust()) {
5751
size = in_size.fromJust();
5852
}
59-
60-
if (static_cast<std::size_t>(offset) < txt.length()) {
61-
std::string out_txt = txt.substr(offset, size);
62-
out_data->assign(out_txt);
53+
if (static_cast<std::size_t>(offset) < txt_view.length()) {
54+
std::string_view out_view = txt_view.substr(offset, size);
55+
out_data->assign(out_view.data(), out_view.size());
6356
*out_eof = false;
57+
if (!offset_was_specified) {
58+
offset_map_[stream_id] = offset + size;
59+
}
6460
} else {
61+
*out_data = "";
6562
*out_eof = true;
6663
}
6764

68-
offset_map_[stream_id] = offset + size;
69-
7065
return DispatchResponse::Success();
7166
}
7267

7368
DispatchResponse IoAgent::close(const String& in_handle) {
74-
Mutex::ScopedWriteLock lock(data_mutex_);
7569
std::string in_handle_str = in_handle;
76-
int stream_id = 0;
70+
uint64_t stream_id = 0;
7771
bool is_number =
7872
std::all_of(in_handle_str.begin(), in_handle_str.end(), ::isdigit);
7973
if (is_number) {
80-
stream_id = std::stoi(in_handle_str);
81-
offset_map_.erase(stream_id);
82-
data_map_.erase(stream_id);
74+
stream_id = std::stoull(in_handle_str);
75+
// Use accessor to erase resource and mapping by stream id
76+
NetworkResourceManager::EraseByStreamId(stream_id);
8377
}
8478
return DispatchResponse::Success();
8579
}

src/inspector/io_agent.h

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
#ifndef SRC_INSPECTOR_IO_AGENT_H_
22
#define SRC_INSPECTOR_IO_AGENT_H_
33

4-
#include <unordered_map>
54
#include "node/inspector/protocol/IO.h"
6-
#include "node_mutex.h"
75

86
namespace node::inspector::protocol {
97

@@ -18,16 +16,9 @@ class IoAgent : public IO::Backend {
1816
bool* out_eof) override;
1917
DispatchResponse close(const String& in_handle) override;
2018

21-
static int setData(const std::string& value);
22-
2319
private:
2420
std::shared_ptr<IO::Frontend> frontend_;
25-
static int getNextStreamId();
26-
27-
static std::unordered_map<int, std::string> data_map_;
28-
static std::unordered_map<int, int> offset_map_;
29-
static std::atomic<int> stream_counter_;
30-
static Mutex data_mutex_;
21+
std::unordered_map<int, int> offset_map_ = {}; // Maps stream_id to offset
3122
};
3223
} // namespace node::inspector::protocol
3324
#endif // SRC_INSPECTOR_IO_AGENT_H_

src/inspector/network_agent.cc

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
#include "network_agent.h"
2-
#include "debug_utils-inl.h"
32
#include <string>
3+
#include "debug_utils-inl.h"
44
#include "env-inl.h"
5+
#include "inspector/network_resource_manager.h"
56
#include "inspector/protocol_helper.h"
67
#include "network_inspector.h"
78
#include "node_metadata.h"
@@ -208,8 +209,9 @@ std::unique_ptr<protocol::Network::Response> createResponseFromObject(
208209
}
209210

210211
NetworkAgent::NetworkAgent(NetworkInspector* inspector,
211-
v8_inspector::V8Inspector* v8_inspector)
212-
: inspector_(inspector), v8_inspector_(v8_inspector) {
212+
v8_inspector::V8Inspector* v8_inspector,
213+
Environment* env)
214+
: inspector_(inspector), v8_inspector_(v8_inspector), env_(env) {
213215
event_notifier_map_["requestWillBeSent"] = &NetworkAgent::requestWillBeSent;
214216
event_notifier_map_["responseReceived"] = &NetworkAgent::responseReceived;
215217
event_notifier_map_["loadingFailed"] = &NetworkAgent::loadingFailed;
@@ -341,7 +343,29 @@ protocol::DispatchResponse NetworkAgent::loadNetworkResource(
341343
const protocol::String& in_url,
342344
std::unique_ptr<protocol::Network::LoadNetworkResourcePageResult>*
343345
out_resource) {
344-
return protocol::DispatchResponse::FallThrough();
346+
if (!env_->options()->experimental_inspector_network_resource) {
347+
return protocol::DispatchResponse::ServerError(
348+
"Network resource loading is not enabled. This feature is "
349+
"experimental and requires --experimental-inspector-network-resource "
350+
"flag to be set.");
351+
}
352+
std::string data = NetworkResourceManager::Get(in_url);
353+
bool found = !data.empty();
354+
if (found) {
355+
uint64_t stream_id = NetworkResourceManager::GetStreamId(in_url);
356+
auto result = protocol::Network::LoadNetworkResourcePageResult::create()
357+
.setSuccess(true)
358+
.setStream(std::to_string(stream_id))
359+
.build();
360+
*out_resource = std::move(result);
361+
return protocol::DispatchResponse::Success();
362+
} else {
363+
auto result = protocol::Network::LoadNetworkResourcePageResult::create()
364+
.setSuccess(false)
365+
.build();
366+
*out_resource = std::move(result);
367+
return protocol::DispatchResponse::Success();
368+
}
345369
}
346370

347371
void NetworkAgent::requestWillBeSent(v8::Local<v8::Context> context,

0 commit comments

Comments
 (0)