Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

inspector: add initial support for network inspection #53593

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

cola119
Copy link
Member

@cola119 cola119 commented Jun 26, 2024

The idea of supporting network inspection in Node.js was first proposed 7 years age in the nodejs/diagnostics#75. Despite numerous discussions, we have yet to settle on an implementation approach. This PR aims to serve as a starting point to explore and refine how we can achieve this feature.

Overview

This PR introduces basic support for the Network domain of the Chrome DevTools Protocol (CDP) and its corresponding agent implementation in Node.js. Although this is an initial implementation with several pending tasks, it sets a foundation to verify if we are heading in the right direction.

Demo

Currenlty, the Node-specific DevTools Frontend lacks a network tab. Therefore, you'll need to use the Chrome DevTools Frontend, accessible via devtools://devtools/bundled/inspector.html. Below is a simple demonstration:

  1. Start Node.js with the inspector and wait for a connection:
$ ./node --inspect-wait -e "require('https').get('https://nodejs.org/en', (res) => { console.log(res.statusCode); }); fetch('https://nodejs.org/fr');"
Debugger listening on ws://127.0.0.1:9229/<inspector-websocket-id>
For help, see: https://nodejs.org/en/docs/inspector
  1. Open the Chrome DevTools Frontend and connect to the Node.js inspector
devtools://devtools/bundled/inspector.html?ws=127.0.0.1:9229/<inspector-websocket-id>
  1. Navigate to the network tab to observe network activity.

image

Implementation Strategy

Network activity tracking

We considered several ways to track network activities, as discussed in nodejs/diagnostics#75. This PR captures request and response data with the diagnostic_channel module. This approach enables us to monitor activities in both core modules (http, https) and external libraries (undici) without changing the core implementation.

Custom CDP domain (NodeNetwork)

TBD

Future work

To fully support the Network domain of the CDP, several tasks remain:

  • Complete implementation for all network domain events as specified in the https://chromedevtools.github.io/devtools-protocol/tot/Network/
    • CDP is primarily designed for browsers, but we aim to support as many relevant features as possible in Node.js
    • Network.loadingFailed
    • request url
    • request headers
    • request timing
    • response data
    • status code
    • response headers
    • ...
  • Add a network tab on the Node-specific DevTools frontend
    • Collaborate with the Chrome DevTools team to achieve this.

Limitations and Challenges

These APIs can be supported once each diagnostics_channel provides sufficient hook timing and resources.

  • Support WebSocket
  • Support fetch API
  • Support http2 module

The following features may be challenging to fully implement in the initial phase, and we need to evaluate the demand for them.

  • Non-inspection features (e.g., header/request/response modification, network condition emulation, etc.)

cc @nodejs/inspector @eugeneo

@nodejs-github-bot
Copy link
Collaborator

Review requested:

  • @nodejs/gyp
  • @nodejs/http
  • @nodejs/net

@nodejs-github-bot nodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. lib / src Issues and PRs related to general changes in the lib or src directory. needs-ci PRs that need a full CI run. labels Jun 26, 2024
@cola119 cola119 added the inspector Issues and PRs related to the V8 inspector protocol label Jun 26, 2024
@MoLow
Copy link
Member

MoLow commented Jun 26, 2024

CC @nodejs/undici regarding support for fetch and WebSocket

@benjamingr
Copy link
Member

Hey, this is incredibly cool.

@benjamingr
Copy link
Member

Yes, at the very least we should probably integrate with fetch/undici, it's hookable already through the dispatcher so it shouldn't be too hard (before this is stable, not to block this PR)

@GrinZero
Copy link

I think the fetch api is also very important and I hope it can be supported

@cola119
Copy link
Member Author

cola119 commented Jun 26, 2024

@benjamingr I wasn't aware of undici's dispatcher feature, and I've now seen that undici includes diagnostics channels. I'm thinking using diagnostics_channel to monitor network activities could be a more straightforward approach than capturing data within the core implementation.

@GrinZero
Copy link

I received this update before taking a shower, and this piece can finally be pushed forward, which is great.
I have decided to share my experiences and ideas in this area, hoping to be helpful for development.

About two weeks ago, I developed a library for this issue, and some key ideas should be useful:

The 'v8 inspector' lacks a network domain

It is useddevtools://devtools/bundled/inspector.htmlSubstitute (this is consistent with the above)

How to listen for HTTP/HTTPS requests?

Basic ideas

  • Firstly, I attempted to hijack the request method of the HTTP module, which allowed me to obtain Options when the user called it. By analyzing the parameters, I obtained key data such as URL and request headers.(request.ts#L77)
  • Next, we will continue to hijack the parameter callback of request. Through this step, we can obtain the IncomingMessage, so that we can obtain key data such as responseData and reponseHeader when the request returns.(request.ts#L50)
  • The final step is to hijack the instance returned by request with write method, so that the data at the time of the request can be obtained. (request.ts#L20)

Key points

  • It is worth noting that when truly sending responseData to devtool, data decompression processing is also required!(tryDecompression(...))
  • When sending requestWillBeSend, it is necessary to have more judgment on the content-type in order to better utilize devtool.

How to make full use of the initiator

A single network domain cannot support operations such as traceability and click to jump. This involves the Debugger domain and the specific chain ⛓️ :

  • Debugger.scriptParsed(Server to Devtool) -->
  • Debugger. getScriptSource (Devtool to Server) -->
  • Debugger.getScriptSourceResponse(Server response to Devtool).

The core of it is scriptId. Currently, I distinguish scriptId by file name, but the actual processing should be more complex.

How to support fetch

fetch.ts

Although I attempted to implement fetch hijacking, I found that the information provided by the fetch was relatively limited, and only basic request header \ request data \ response header \ response data could be displayed.

Data regarding data length and other aspects could not be fully collected. (This can be seen in the code specifically, the core is clone() & hijacking)

I hope this will be helpful for future development. My mastery of C++ is average, and my assistance with PR is limited.

@eugeneo
Copy link
Contributor

eugeneo commented Jun 26, 2024

One thing I was prototyping years ago was implementing Inspector domains in the user land, in JS. I.e. instead of piping requestWillBeSent/responseReceived through all the layers we could have a generic backend and one method that JS would use to send different messages. This would also allow the ecosystem add more custom domains that would be able to piggiback on existing Inspector infrastructure. E.g. some database vendor may want to add a custom domain for their database and a custom tool that would connect to Inspector server.

Another thing we discussed a lot in the past is that Network domain in Node should be reversed as most users will be interested in debugging server application. There should be requestReceived/responseWillBeSent pair.

Chrome DevTools at the time was very adamant not to reuse Chrome domains for the domains not in V8. Please rename this domain to NodeNetwork and let the tool developers opt in in supporting it. Chances are the domains will diverge (say, to support requestReceived) and it will be really difficult for tools to tell what they are working with, a browser or server.

@ronag
Copy link
Member

ronag commented Jun 26, 2024

Could we implement it in terms of diagnostic channnels that external libs (undici) can just hook into?

@GrinZero
Copy link

One thing I was prototyping years ago was implementing Inspector domains in the user land,...

I completely agree, and I also believe that the network domain in Node should be reversed. Now we can actually extend the v8 inspector launched by the node, but it is more related to remote debugging, and due to domain limitations, network and other domains cannot be implemented.

@eugeneo
Copy link
Contributor

eugeneo commented Jun 26, 2024

Note needs both HTTP server and HTTP client support... It would be invaluable to be able to see request that was received and what was sent to other microservices.

@cola119 cola119 force-pushed the network-inspection-poc branch 2 times, most recently from fc0ed45 to 5656be6 Compare June 27, 2024 07:06
@cola119
Copy link
Member Author

cola119 commented Jun 27, 2024

@nodejs/undici For network inspection on fetch API, we need undici's diagnostics_channel to support a hook when body is received. Has there been any progress on nodejs/undici#1342?

@GrinZero
Copy link

@nodejs/undici For network inspection on fetch API, we need undici's diagnostics_channel to support a hook when body is received. Has there been any progress on nodejs/undici#1342?

I would like to confirm if listening to network requests through the undici library diagnostics.channel is compatible with previous libraries?

@cola119
Copy link
Member Author

cola119 commented Jun 27, 2024

@GrinZero I'm going to add as many features of the Network domain as possible once we confirm that this PR is on the right track. (Currently, I'm trying to figure out how to support both the custom NodeNetwork domain and the Network domain). Any guidance or suggestions you could provide would be very helpful, thank you!

@eugeneo I need your advice on how to properly define and implement the custom NodeNetwork domain. My understanding is that the V8 inspector doesn't support the Network domain, so Node.js needs to support it. Additionally, Node.js should have the custom NodeNetwork domain to handle Node-specific events and commands (e.g., requestReceived) and allow ecosystems to utilize the inspector infrastructure. However, I'm still unsure the best way to proceed and would greatly appreciate your input. Below is a draft architecture overview I have in mind. Thank you for your assistance :)

image

@GrinZero
Copy link

I am wondering if it is possible to be more open and allow the node v8 inspector to directly expose the websocket server. This way, developers can not only operate devtool as a CDP client, but also extend devtool as a CDP server in the future.

dataReceived(request._inspectorRequestId, DateNow() / 1000, chunk.length);
responseString += chunk.toString();
};
response.on('data', onData);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on the test results, consuming response data and entering flowing mode in the diagnostics_channel hook is causing some issues in the core. Any ideas?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Show the issues?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mcollina
Copy link
Member

We could add fetch support via nodejs/undici#2701.

Generically I think we should add some APIs to let devs integrate 3rd party clients.

@benjamingr
Copy link
Member

+1 to this being diagnostics_channel based and +1 for letting userland tools integrate with it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c++ Issues and PRs that require attention from people who are familiar with C++. inspector Issues and PRs related to the V8 inspector protocol lib / src Issues and PRs related to general changes in the lib or src directory. needs-ci PRs that need a full CI run.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants