GeezerVison is showing github.com — inspector: initial support for Network.loadNetworkResource · nodejs/node@d02831e
File treeExpand file treeCollapse file tree Open diff view settings fixtures/inspector-network-resource
Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: doc/api/cli.md +11Lines changed: 11 additions & 0 deletions - Display the source diff
- Display the rich diff
| Original file line number | Diff line number | Diff line change |
|---|
@@ -1046,6 +1046,17 @@ passing a second `parentURL` argument for contextual resolution. | 1046 | 1046 |
| 1047 | 1047 | Previously gated the entire `import.meta.resolve` feature. | 1048 | 1048 |
| | 1049 | +### `--experimental-inspector-network-resource` | | 1050 | + | | 1051 | +<!-- YAML | | 1052 | +added: | | 1053 | + - REPLACEME | | 1054 | +--> | | 1055 | + | | 1056 | +> Stability: 1.1 - Active Development | | 1057 | +
| | 1058 | +Enable experimental support for inspector network resources. | | 1059 | + | 1049 | 1060 | ### `--experimental-loader=module` | 1050 | 1061 |
| 1051 | 1062 | <!-- YAML | |
Collapse file Copy file name to clipboardExpand all lines: doc/api/inspector.md +37Lines changed: 37 additions & 0 deletions - Display the source diff
- Display the rich diff
| Original file line number | Diff line number | Diff line change |
|---|
@@ -594,6 +594,43 @@ This feature is only available with the `--experimental-network-inspection` flag | 594 | 594 | Broadcasts the `Network.loadingFailed` event to connected frontends. This event indicates that | 595 | 595 | HTTP request has failed to load. | 596 | 596 |
| | 597 | +### `inspector.NetworkResources.put` | | 598 | + | | 599 | +<!-- YAML | | 600 | +added: | | 601 | + - REPLACEME | | 602 | +--> | | 603 | + | | 604 | +> Stability: 1.1 - Active Development | | 605 | +
| | 606 | +This feature is only available with the `--experimental-inspector-network-resource` flag enabled. | | 607 | + | | 608 | +The inspector.NetworkResources.put method is used to provide a response for a loadNetworkResource | | 609 | +request issued via the Chrome DevTools Protocol (CDP). | | 610 | +This is typically triggered when a source map is specified by URL, and a DevTools frontend—such as | | 611 | +Chrome—requests the resource to retrieve the source map. | | 612 | + | | 613 | +This method allows developers to predefine the resource content to be served in response to such CDP requests. | | 614 | + | | 615 | +```js | | 616 | +const inspector = require('node:inspector'); | | 617 | +// By preemptively calling put to register the resource, a source map can be resolved when | | 618 | +// a loadNetworkResource request is made from the frontend. | | 619 | +async function setNetworkResources() { | | 620 | + const mapUrl = 'http://localhost:3000/dist/app.js.map'; | | 621 | + const tsUrl = 'http://localhost:3000/src/app.ts'; | | 622 | + const distAppJsMap = await fetch(mapUrl).then((res) => res.text()); | | 623 | + const srcAppTs = await fetch(tsUrl).then((res) => res.text()); | | 624 | + inspector.NetworkResources.put(mapUrl, distAppJsMap); | | 625 | + inspector.NetworkResources.put(tsUrl, srcAppTs); | | 626 | +}; | | 627 | +setNetworkResources().then(() => { | | 628 | + require('./dist/app'); | | 629 | +}); | | 630 | +``` | | 631 | + | | 632 | +For more details, see the official CDP documentation: [Network.loadNetworkResource](https://chromedevtools.github.io/devtools-protocol/tot/Network/#method-loadNetworkResource) | | 633 | + | 597 | 634 | ## Support of breakpoints | 598 | 635 |
| 599 | 636 | The Chrome DevTools Protocol [`Debugger` domain][] allows an | |
Collapse file Copy file name to clipboardExpand all lines: doc/node.1 +3Lines changed: 3 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -237,6 +237,9 @@ flag is no longer required as WASI is enabled by default. | 237 | 237 | .It Fl -experimental-wasm-modules | 238 | 238 | Enable experimental WebAssembly module support. | 239 | 239 | . | | 240 | +.It Fl -experimental-inspector-network-resource | | 241 | +Enable experimental support for inspector network resources. | | 242 | +. | 240 | 243 | .It Fl -force-context-aware | 241 | 244 | Disable loading native addons that are not context-aware. | 242 | 245 | . | |
Collapse file Copy file name to clipboardExpand all lines: lib/inspector.js +8Lines changed: 8 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -39,6 +39,9 @@ const { | 39 | 39 | } = require('internal/validators'); | 40 | 40 | const { isMainThread } = require('worker_threads'); | 41 | 41 | const { _debugEnd } = internalBinding('process_methods'); | | 42 | +const { | | 43 | + put, | | 44 | +} = require('internal/inspector/network_resources'); | 42 | 45 |
| 43 | 46 | const { | 44 | 47 | Connection, | @@ -221,6 +224,10 @@ const Network = { | 221 | 224 | dataReceived: (params) => broadcastToFrontend('Network.dataReceived', params), | 222 | 225 | }; | 223 | 226 |
| | 227 | +const NetworkResources = { | | 228 | + put, | | 229 | +}; | | 230 | + | 224 | 231 | module.exports = { | 225 | 232 | open: inspectorOpen, | 226 | 233 | close: _debugEnd, | @@ -229,4 +236,5 @@ module.exports = { | 229 | 236 | console, | 230 | 237 | Session, | 231 | 238 | Network, | | 239 | + NetworkResources, | 232 | 240 | }; |
Collapse file Copy file name to clipboard +27Lines changed: 27 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| | 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 | +}; |
Collapse file Copy file name to clipboard +57Lines changed: 57 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| | 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 |
Collapse file Copy file name to clipboard +30Lines changed: 30 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| | 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_ |
Collapse file Copy file name to clipboardExpand all lines: src/inspector/network_agent.cc +44-4Lines changed: 44 additions & 4 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 1 | 1 | #include "network_agent.h" | | 2 | +#include <string> | 2 | 3 | #include "debug_utils-inl.h" | | 4 | +#include "env-inl.h" | | 5 | +#include "inspector/network_resource_manager.h" | 3 | 6 | #include "inspector/protocol_helper.h" | 4 | 7 | #include "network_inspector.h" | | 8 | +#include "node_metadata.h" | 5 | 9 | #include "util-inl.h" | | 10 | +#include "uv.h" | | 11 | +#include "v8-context.h" | 6 | 12 | #include "v8.h" | 7 | 13 |
| 8 | 14 | namespace node { | @@ -202,9 +208,15 @@ std::unique_ptr<protocol::Network::Response> createResponseFromObject( | 202 | 208 | .build(); | 203 | 209 | } | 204 | 210 |
| 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)) { | 208 | 220 | event_notifier_map_["requestWillBeSent"] = &NetworkAgent::requestWillBeSent; | 209 | 221 | event_notifier_map_["responseReceived"] = &NetworkAgent::responseReceived; | 210 | 222 | event_notifier_map_["loadingFailed"] = &NetworkAgent::loadingFailed; | @@ -329,10 +341,38 @@ protocol::DispatchResponse NetworkAgent::streamResourceContent( | 329 | 341 | // If the request is finished, remove the entry. | 330 | 342 | requests_.erase(in_requestId); | 331 | 343 | } | 332 | | - | 333 | 344 | return protocol::DispatchResponse::Success(); | 334 | 345 | } | 335 | 346 |
| | 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 | + | 336 | 376 | void NetworkAgent::requestWillBeSent(v8::Local<v8::Context> context, | 337 | 377 | v8::Local<v8::Object> params) { | 338 | 378 | protocol::String request_id; | |
Collapse file Copy file name to clipboardExpand all lines: src/inspector/network_agent.h +16-2Lines changed: 16 additions & 2 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 1 | 1 | #ifndef SRC_INSPECTOR_NETWORK_AGENT_H_ | 2 | 2 | #define SRC_INSPECTOR_NETWORK_AGENT_H_ | 3 | 3 |
| | 4 | +#include "env.h" | | 5 | +#include "io_agent.h" | | 6 | +#include "network_resource_manager.h" | 4 | 7 | #include "node/inspector/protocol/Network.h" | 5 | 8 |
| 6 | 9 | #include <map> | | 10 | +#include <memory> | 7 | 11 | #include <unordered_map> | 8 | 12 |
| 9 | 13 | namespace node { | @@ -38,8 +42,11 @@ struct RequestEntry { | 38 | 42 |
| 39 | 43 | class NetworkAgent : public protocol::Network::Backend { | 40 | 44 | 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); | 43 | 50 |
| 44 | 51 | void Wire(protocol::UberDispatcher* dispatcher); | 45 | 52 |
| @@ -60,6 +67,11 @@ class NetworkAgent : public protocol::Network::Backend { | 60 | 67 | const protocol::String& in_requestId, | 61 | 68 | protocol::Binary* out_bufferedData) override; | 62 | 69 |
| | 70 | + protocol::DispatchResponse loadNetworkResource( | | 71 | + const protocol::String& in_url, | | 72 | + std::unique_ptr<protocol::Network::LoadNetworkResourcePageResult>* | | 73 | + out_resource) override; | | 74 | + | 63 | 75 | void emitNotification(v8::Local<v8::Context> context, | 64 | 76 | const protocol::String& event, | 65 | 77 | v8::Local<v8::Object> params); | @@ -89,6 +101,8 @@ class NetworkAgent : public protocol::Network::Backend { | 89 | 101 | v8::Local<v8::Object>); | 90 | 102 | std::unordered_map<protocol::String, EventNotifier> event_notifier_map_; | 91 | 103 | std::map<protocol::String, RequestEntry> requests_; | | 104 | + Environment* env_; | | 105 | + std::shared_ptr<NetworkResourceManager> network_resource_manager_; | 92 | 106 | }; | 93 | 107 |
| 94 | 108 | } // namespace inspector | |
Collapse file Copy file name to clipboardExpand all lines: src/inspector/network_inspector.cc +9-4Lines changed: 9 additions & 4 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 3 | 3 | namespace node { | 4 | 4 | namespace inspector { | 5 | 5 |
| 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_); | 10 | 15 | } | 11 | 16 | NetworkInspector::~NetworkInspector() { | 12 | 17 | network_agent_.reset(); | |
|