| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 931ff43 commit 3b93507
20 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -972,6 +972,17 @@ added: | |||
| 972 | 972 | ||
| 973 | 973 | Enable experimental support for the `https:` protocol in `import` specifiers. | |
| 974 | 974 | ||
| 975 | + ### `--experimental-network-inspection` | ||
| 976 | + | ||
| 977 | + <!-- YAML | ||
| 978 | + added: | ||
| 979 | + - REPLACEME | ||
| 980 | + --> | ||
| 981 | + | ||
| 982 | + > Stability: 1 - Experimental | ||
| 983 | + | ||
| 984 | + Enable experimental support for the network inspection with Chrome DevTools. | ||
| 985 | + | ||
| 975 | 986 | ### `--experimental-permission` | |
| 976 | 987 | ||
| 977 | 988 | <!-- YAML | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -488,6 +488,75 @@ Blocks until a client (existing or connected later) has sent | |||
| 488 | 488 | ||
| 489 | 489 | An exception will be thrown if there is no active inspector. | |
| 490 | 490 | ||
| 491 | + ## Integration with DevTools | ||
| 492 | + | ||
| 493 | + The `node:inspector` module provides an API for integrating with devtools that support Chrome DevTools Protocol. | ||
| 494 | + DevTools frontends connected to a running Node.js instance can capture protocol events emitted from the instance | ||
| 495 | + and display them accordingly to facilitate debugging. | ||
| 496 | + The following methods broadcast a protocol event to all connected frontends. | ||
| 497 | + The `params` passed to the methods can be optional, depending on the protocol. | ||
| 498 | + | ||
| 499 | + ```js | ||
| 500 | + // The `Network.requestWillBeSent` event will be fired. | ||
| 501 | + inspector.Network.requestWillBeSent({ | ||
| 502 | + requestId: 'request-id-1', | ||
| 503 | + timestamp: Date.now() / 1000, | ||
| 504 | + wallTime: Date.now(), | ||
| 505 | + request: { | ||
| 506 | + url: 'https://nodejs.org/en', | ||
| 507 | + method: 'GET', | ||
| 508 | + }, | ||
| 509 | + }); | ||
| 510 | + ``` | ||
| 511 | + | ||
| 512 | + ### `inspector.Network.requestWillBeSent([params])` | ||
| 513 | + | ||
| 514 | + <!-- YAML | ||
| 515 | + added: | ||
| 516 | + - REPLACEME | ||
| 517 | + --> | ||
| 518 | + | ||
| 519 | + > Stability: 1 - Experimental | ||
| 520 | + | ||
| 521 | + * `params` {Object} | ||
| 522 | + | ||
| 523 | + This feature is only available with the `--experimental-network-inspection` flag enabled. | ||
| 524 | + | ||
| 525 | + Broadcasts the `Network.requestWillBeSent` event to connected frontends. This event indicates that | ||
| 526 | + the application is about to send an HTTP request. | ||
| 527 | + | ||
| 528 | + ### `inspector.Network.responseReceived([params])` | ||
| 529 | + | ||
| 530 | + <!-- YAML | ||
| 531 | + added: | ||
| 532 | + - REPLACEME | ||
| 533 | + --> | ||
| 534 | + | ||
| 535 | + > Stability: 1 - Experimental | ||
| 536 | + | ||
| 537 | + * `params` {Object} | ||
| 538 | + | ||
| 539 | + This feature is only available with the `--experimental-network-inspection` flag enabled. | ||
| 540 | + | ||
| 541 | + Broadcasts the `Network.responseReceived` event to connected frontends. This event indicates that | ||
| 542 | + HTTP response is available. | ||
| 543 | + | ||
| 544 | + ### `inspector.Network.loadingFinished([params])` | ||
| 545 | + | ||
| 546 | + <!-- YAML | ||
| 547 | + added: | ||
| 548 | + - REPLACEME | ||
| 549 | + --> | ||
| 550 | + | ||
| 551 | + > Stability: 1 - Experimental | ||
| 552 | + | ||
| 553 | + * `params` {Object} | ||
| 554 | + | ||
| 555 | + This feature is only available with the `--experimental-network-inspection` flag enabled. | ||
| 556 | + | ||
| 557 | + Broadcasts the `Network.loadingFinished` event to connected frontends. This event indicates that | ||
| 558 | + HTTP request has finished loading. | ||
| 559 | + | ||
| 491 | 560 | ## Support of breakpoints | |
| 492 | 561 | ||
| 493 | 562 | The Chrome DevTools Protocol [`Debugger` domain][] allows an | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -42,6 +42,7 @@ const { | |||
| 42 | 42 | isEnabled, | |
| 43 | 43 | waitForDebugger, | |
| 44 | 44 | console, | |
| 45 | + emitProtocolEvent, | ||
| 45 | 46 | } = internalBinding('inspector'); | |
| 46 | 47 | ||
| 47 | 48 | class Session extends EventEmitter { | |
@@ -188,11 +189,26 @@ function inspectorWaitForDebugger() { | |||
| 188 | 189 | throw new ERR_INSPECTOR_NOT_ACTIVE(); | |
| 189 | 190 | } | |
| 190 | 191 | ||
| 192 | + function broadcastToFrontend(eventName, params) { | ||
| 193 | + validateString(eventName, 'eventName'); | ||
| 194 | + if (params) { | ||
| 195 | + validateObject(params, 'params'); | ||
| 196 | + } | ||
| 197 | + emitProtocolEvent(eventName, JSONStringify(params ?? {})); | ||
| 198 | + } | ||
| 199 | + | ||
| 200 | + const Network = { | ||
| 201 | + requestWillBeSent: (params) => broadcastToFrontend('Network.requestWillBeSent', params), | ||
| 202 | + responseReceived: (params) => broadcastToFrontend('Network.responseReceived', params), | ||
| 203 | + loadingFinished: (params) => broadcastToFrontend('Network.loadingFinished', params), | ||
| 204 | + }; | ||
| 205 | + | ||
| 191 | 206 | module.exports = { | |
| 192 | 207 | open: inspectorOpen, | |
| 193 | 208 | close: _debugEnd, | |
| 194 | 209 | url, | |
| 195 | 210 | waitForDebugger: inspectorWaitForDebugger, | |
| 196 | 211 | console, | |
| 197 | 212 | Session, | |
| 213 | + Network, | ||
| 198 | 214 | }; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,63 @@ | |||
| 1 | + 'use strict'; | ||
| 2 | + | ||
| 3 | + const { | ||
| 4 | + DateNow, | ||
| 5 | + } = primordials; | ||
| 6 | + | ||
| 7 | + let dc; | ||
| 8 | + let Network; | ||
| 9 | + | ||
| 10 | + let requestId = 0; | ||
| 11 | + const getNextRequestId = () => `node-network-event-${++requestId}`; | ||
| 12 | + | ||
| 13 | + function onClientRequestStart({ request }) { | ||
| 14 | + const url = `${request.protocol}//${request.host}${request.path}`; | ||
| 15 | + const wallTime = DateNow(); | ||
| 16 | + const timestamp = wallTime / 1000; | ||
| 17 | + request._inspectorRequestId = getNextRequestId(); | ||
| 18 | + Network.requestWillBeSent({ | ||
| 19 | + requestId: request._inspectorRequestId, | ||
| 20 | + timestamp, | ||
| 21 | + wallTime, | ||
| 22 | + request: { | ||
| 23 | + url, | ||
| 24 | + method: request.method, | ||
| 25 | + }, | ||
| 26 | + }); | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | + function onClientResponseFinish({ request }) { | ||
| 30 | + if (typeof request._inspectorRequestId !== 'string') { | ||
| 31 | + return; | ||
| 32 | + } | ||
| 33 | + const timestamp = DateNow() / 1000; | ||
| 34 | + Network.responseReceived({ | ||
| 35 | + requestId: request._inspectorRequestId, | ||
| 36 | + timestamp, | ||
| 37 | + }); | ||
| 38 | + Network.loadingFinished({ | ||
| 39 | + requestId: request._inspectorRequestId, | ||
| 40 | + timestamp, | ||
| 41 | + }); | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + function enable() { | ||
| 45 | + if (!dc) { | ||
| 46 | + dc = require('diagnostics_channel'); | ||
| 47 | + } | ||
| 48 | + if (!Network) { | ||
| 49 | + Network = require('inspector').Network; | ||
| 50 | + } | ||
| 51 | + dc.subscribe('http.client.request.start', onClientRequestStart); | ||
| 52 | + dc.subscribe('http.client.response.finish', onClientResponseFinish); | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + function disable() { | ||
| 56 | + dc.unsubscribe('http.client.request.start', onClientRequestStart); | ||
| 57 | + dc.unsubscribe('http.client.response.finish', onClientResponseFinish); | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + module.exports = { | ||
| 61 | + enable, | ||
| 62 | + disable, | ||
| 63 | + }; | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -105,6 +105,7 @@ function prepareExecution(options) { | |||
| 105 | 105 | const mainEntry = patchProcessObject(expandArgv1); | |
| 106 | 106 | setupTraceCategoryState(); | |
| 107 | 107 | setupInspectorHooks(); | |
| 108 | + setupNetworkInspection(); | ||
| 108 | 109 | setupWarningHandler(); | |
| 109 | 110 | setupUndici(); | |
| 110 | 111 | setupWebCrypto(); | |
@@ -478,6 +479,16 @@ function setupInspectorHooks() { | |||
| 478 | 479 | } | |
| 479 | 480 | } | |
| 480 | 481 | ||
| 482 | + function setupNetworkInspection() { | ||
| 483 | + if (internalBinding('config').hasInspector && getOptionValue('--experimental-network-inspection')) { | ||
| 484 | + const { | ||
| 485 | + enable, | ||
| 486 | + disable, | ||
| 487 | + } = require('internal/inspector_network_tracking'); | ||
| 488 | + internalBinding('inspector').setupNetworkTracking(enable, disable); | ||
| 489 | + } | ||
| 490 | + } | ||
| 491 | + | ||
| 481 | 492 | // In general deprecations are initialized wherever the APIs are implemented, | |
| 482 | 493 | // this is used to deprecate APIs implemented in C++ where the deprecation | |
| 483 | 494 | // utilities are not easily accessible. | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -426,7 +426,9 @@ | |||
| 426 | 426 | V(immediate_callback_function, v8::Function) \ | |
| 427 | 427 | V(inspector_console_extension_installer, v8::Function) \ | |
| 428 | 428 | V(inspector_disable_async_hooks, v8::Function) \ | |
| 429 | + V(inspector_disable_network_tracking, v8::Function) \ | ||
| 429 | 430 | V(inspector_enable_async_hooks, v8::Function) \ | |
| 431 | + V(inspector_enable_network_tracking, v8::Function) \ | ||
| 430 | 432 | V(maybe_cache_generated_source_map, v8::Function) \ | |
| 431 | 433 | V(messaging_deserialize_create_object, v8::Function) \ | |
| 432 | 434 | V(message_port, v8::Object) \ | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,84 @@ | |||
| 1 | + #include "network_agent.h" | ||
| 2 | + #include "network_inspector.h" | ||
| 3 | + | ||
| 4 | + namespace node { | ||
| 5 | + namespace inspector { | ||
| 6 | + namespace protocol { | ||
| 7 | + | ||
| 8 | + std::unique_ptr<Network::Request> Request(const String& url, | ||
| 9 | + const String& method) { | ||
| 10 | + return Network::Request::create().setUrl(url).setMethod(method).build(); | ||
| 11 | + } | ||
| 12 | + | ||
| 13 | + NetworkAgent::NetworkAgent(NetworkInspector* inspector) | ||
| 14 | + : inspector_(inspector) { | ||
| 15 | + event_notifier_map_["requestWillBeSent"] = &NetworkAgent::requestWillBeSent; | ||
| 16 | + event_notifier_map_["responseReceived"] = &NetworkAgent::responseReceived; | ||
| 17 | + event_notifier_map_["loadingFinished"] = &NetworkAgent::loadingFinished; | ||
| 18 | + } | ||
| 19 | + | ||
| 20 | + void NetworkAgent::emitNotification( | ||
| 21 | + const String& event, std::unique_ptr<protocol::DictionaryValue> params) { | ||
| 22 | + if (!inspector_->IsEnabled()) return; | ||
| 23 | + auto it = event_notifier_map_.find(event); | ||
| 24 | + if (it != event_notifier_map_.end()) { | ||
| 25 | + (this->*(it->second))(std::move(params)); | ||
| 26 | + } | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | + void NetworkAgent::Wire(UberDispatcher* dispatcher) { | ||
| 30 | + frontend_ = std::make_unique<Network::Frontend>(dispatcher->channel()); | ||
| 31 | + Network::Dispatcher::wire(dispatcher, this); | ||
| 32 | + } | ||
| 33 | + | ||
| 34 | + DispatchResponse NetworkAgent::enable() { | ||
| 35 | + inspector_->Enable(); | ||
| 36 | + return DispatchResponse::OK(); | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + DispatchResponse NetworkAgent::disable() { | ||
| 40 | + inspector_->Disable(); | ||
| 41 | + return DispatchResponse::OK(); | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + void NetworkAgent::requestWillBeSent( | ||
| 45 | + std::unique_ptr<protocol::DictionaryValue> params) { | ||
| 46 | + String request_id; | ||
| 47 | + params->getString("requestId", &request_id); | ||
| 48 | + double timestamp; | ||
| 49 | + params->getDouble("timestamp", ×tamp); | ||
| 50 | + double wall_time; | ||
| 51 | + params->getDouble("wallTime", &wall_time); | ||
| 52 | + auto request = params->getObject("request"); | ||
| 53 | + String url; | ||
| 54 | + request->getString("url", &url); | ||
| 55 | + String method; | ||
| 56 | + request->getString("method", &method); | ||
| 57 | + | ||
| 58 | + frontend_->requestWillBeSent( | ||
| 59 | + request_id, Request(url, method), timestamp, wall_time); | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | + void NetworkAgent::responseReceived( | ||
| 63 | + std::unique_ptr<protocol::DictionaryValue> params) { | ||
| 64 | + String request_id; | ||
| 65 | + params->getString("requestId", &request_id); | ||
| 66 | + double timestamp; | ||
| 67 | + params->getDouble("timestamp", ×tamp); | ||
| 68 | + | ||
| 69 | + frontend_->responseReceived(request_id, timestamp); | ||
| 70 | + } | ||
| 71 | + | ||
| 72 | + void NetworkAgent::loadingFinished( | ||
| 73 | + std::unique_ptr<protocol::DictionaryValue> params) { | ||
| 74 | + String request_id; | ||
| 75 | + params->getString("requestId", &request_id); | ||
| 76 | + double timestamp; | ||
| 77 | + params->getDouble("timestamp", ×tamp); | ||
| 78 | + | ||
| 79 | + frontend_->loadingFinished(request_id, timestamp); | ||
| 80 | + } | ||
| 81 | + | ||
| 82 | + } // namespace protocol | ||
| 83 | + } // namespace inspector | ||
| 84 | + } // namespace node | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,49 @@ | |||
| 1 | + #ifndef SRC_INSPECTOR_NETWORK_AGENT_H_ | ||
| 2 | + #define SRC_INSPECTOR_NETWORK_AGENT_H_ | ||
| 3 | + | ||
| 4 | + #include "node/inspector/protocol/Network.h" | ||
| 5 | + | ||
| 6 | + #include <unordered_map> | ||
| 7 | + | ||
| 8 | + namespace node { | ||
| 9 | + | ||
| 10 | + namespace inspector { | ||
| 11 | + class NetworkInspector; | ||
| 12 | + | ||
| 13 | + namespace protocol { | ||
| 14 | + | ||
| 15 | + std::unique_ptr<Network::Request> Request(const String& url, | ||
| 16 | + const String& method); | ||
| 17 | + | ||
| 18 | + class NetworkAgent : public Network::Backend { | ||
| 19 | + public: | ||
| 20 | + explicit NetworkAgent(NetworkInspector* inspector); | ||
| 21 | + | ||
| 22 | + void Wire(UberDispatcher* dispatcher); | ||
| 23 | + | ||
| 24 | + DispatchResponse enable() override; | ||
| 25 | + | ||
| 26 | + DispatchResponse disable() override; | ||
| 27 | + | ||
| 28 | + void emitNotification(const String& event, | ||
| 29 | + std::unique_ptr<protocol::DictionaryValue> params); | ||
| 30 | + | ||
| 31 | + void requestWillBeSent(std::unique_ptr<protocol::DictionaryValue> params); | ||
| 32 | + | ||
| 33 | + void responseReceived(std::unique_ptr<protocol::DictionaryValue> params); | ||
| 34 | + | ||
| 35 | + void loadingFinished(std::unique_ptr<protocol::DictionaryValue> params); | ||
| 36 | + | ||
| 37 | + private: | ||
| 38 | + NetworkInspector* inspector_; | ||
| 39 | + std::shared_ptr<Network::Frontend> frontend_; | ||
| 40 | + using EventNotifier = | ||
| 41 | + void (NetworkAgent::*)(std::unique_ptr<protocol::DictionaryValue>); | ||
| 42 | + std::unordered_map<String, EventNotifier> event_notifier_map_; | ||
| 43 | + }; | ||
| 44 | + | ||
| 45 | + } // namespace protocol | ||
| 46 | + } // namespace inspector | ||
| 47 | + } // namespace node | ||
| 48 | + | ||
| 49 | + #endif // SRC_INSPECTOR_NETWORK_AGENT_H_ | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments