Skip to content

Commit

Permalink
inspector: add initial support for network inspection
Browse files Browse the repository at this point in the history
  • Loading branch information
cola119 committed Jun 27, 2024
1 parent 4c730ae commit 6e727ee
Show file tree
Hide file tree
Showing 10 changed files with 554 additions and 1 deletion.
50 changes: 50 additions & 0 deletions lib/internal/process/pre_execution.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
const {
ArrayPrototypeForEach,
Date,
DateNow,
DatePrototypeGetDate,
DatePrototypeGetFullYear,
DatePrototypeGetHours,
Expand Down Expand Up @@ -98,6 +99,7 @@ function prepareExecution(options) {
const mainEntry = patchProcessObject(expandArgv1);
setupTraceCategoryState();
setupInspectorHooks();
setupNetworkInspection();
setupNavigator();
setupWarningHandler();
setupWebStorage();
Expand Down Expand Up @@ -438,6 +440,54 @@ function setupInspectorHooks() {
}
}

function setupNetworkInspection() {
if (!internalBinding('config').hasInspector) {
return;
}
const dc = require('diagnostics_channel');
const {
dataReceived,
loadingFinished,
requestWillBeSent,
responseReceived,
} = internalBinding('inspector');

let requestId = 0;
const getNextRequestId = () => `node-network-event-${++requestId}`;

dc.subscribe('http.client.request.start', ({ request }) => {
const url = `${request.protocol}//${request.host}${request.path}`;
const wallTime = DateNow();
const timestamp = wallTime / 1000;
request._inspectorRequestId = getNextRequestId();
requestWillBeSent(request._inspectorRequestId, url, request.method, timestamp, wallTime);
});
dc.subscribe('http.client.response.finish', ({ request, response }) => {
if (typeof request._inspectorRequestId !== 'string') {
return;
}
responseReceived(request._inspectorRequestId, DateNow() / 1000);
let responseString = '';
const onData = (chunk) => {
dataReceived(request._inspectorRequestId, DateNow() / 1000, chunk.length);
responseString += chunk.toString();
};
response.on('data', onData);
response.on('end', () => {
loadingFinished(request._inspectorRequestId, responseString, DateNow() / 1000, responseString.length);
response.removeListener('data', onData);
});
});

dc.subscribe('undici:request:create', ({ request }) => {
const url = `${request.origin}${request.path}`;
const wallTime = DateNow();
const timestamp = wallTime / 1000;
request._inspectorRequestId = getNextRequestId();
requestWillBeSent(request._inspectorRequestId, url, request.method, timestamp, wallTime);
});
}

// In general deprecations are initialized wherever the APIs are implemented,
// this is used to deprecate APIs implemented in C++ where the deprecation
// utilities are not easily accessible.
Expand Down
61 changes: 61 additions & 0 deletions src/inspector/network_agent.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#include "network_agent.h"

#include "inspector_agent.h"

namespace node {
namespace inspector {
namespace protocol {

std::unique_ptr<Network::Request> Request(const String& url,
const String& method) {
return Network::Request::create().setUrl(url).setMethod(method).build();
}

NetworkAgent::NetworkAgent() {}

void NetworkAgent::Wire(UberDispatcher* dispatcher) {
frontend_ = std::make_unique<Network::Frontend>(dispatcher->channel());
Network::Dispatcher::wire(dispatcher, this);
}

DispatchResponse NetworkAgent::getResponseBody(const String& in_requestId,
String* out_body) {
auto it = request_id_to_response_.find(in_requestId);
if (it != request_id_to_response_.end()) {
*out_body = it->second;
request_id_to_response_.erase(it);
}
return DispatchResponse::OK();
}

void NetworkAgent::requestWillBeSent(const String& request_id,
const String& url,
const String& method,
double timestamp,
double wall_time) {
frontend_->requestWillBeSent(
request_id, Request(url, method), timestamp, wall_time);
}

void NetworkAgent::responseReceived(const String& request_id,
double timestamp) {
frontend_->responseReceived(request_id, timestamp);
}

void NetworkAgent::dataReceived(const String& request_id,
double timestamp,
int data_length) {
frontend_->dataReceived(request_id, timestamp, data_length);
}

void NetworkAgent::loadingFinished(const String& request_id,
const String& response,
double timestamp,
int encoded_data_length) {
request_id_to_response_[request_id] = response;
frontend_->loadingFinished(request_id, timestamp, encoded_data_length);
}

} // namespace protocol
} // namespace inspector
} // namespace node
49 changes: 49 additions & 0 deletions src/inspector/network_agent.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#ifndef SRC_INSPECTOR_NETWORK_AGENT_H_
#define SRC_INSPECTOR_NETWORK_AGENT_H_

#include "node/inspector/protocol/Network.h"
#include "v8.h"

#include <unordered_map>

namespace node {

namespace inspector {
namespace protocol {

class NetworkAgent : public Network::Backend {
public:
NetworkAgent();

void Wire(UberDispatcher* dispatcher);

DispatchResponse getResponseBody(const String& in_requestId,
String* out_body) override;

void requestWillBeSent(const String& request_id,
const String& url,
const String& method,
double timestamp,
double wall_time);

void responseReceived(const String& request_id, double timestamp);

void dataReceived(const String& request_id,
double timestamp,
int data_length);

void loadingFinished(const String& request_id,
const String& response,
double timestamp,
int encoded_data_length);

private:
std::shared_ptr<Network::Frontend> frontend_;
std::unordered_map<String, String> request_id_to_response_;
};

} // namespace protocol
} // namespace inspector
} // namespace node

#endif // SRC_INSPECTOR_NETWORK_AGENT_H_
4 changes: 4 additions & 0 deletions src/inspector/node_inspector.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
'src/inspector/tracing_agent.h',
'src/inspector/worker_agent.cc',
'src/inspector/worker_agent.h',
'src/inspector/network_agent.cc',
'src/inspector/network_agent.h',
'src/inspector/worker_inspector.cc',
'src/inspector/worker_inspector.h',
],
Expand All @@ -36,6 +38,8 @@
'<(SHARED_INTERMEDIATE_DIR)/src/node/inspector/protocol/NodeTracing.h',
'<(SHARED_INTERMEDIATE_DIR)/src/node/inspector/protocol/NodeRuntime.cpp',
'<(SHARED_INTERMEDIATE_DIR)/src/node/inspector/protocol/NodeRuntime.h',
'<(SHARED_INTERMEDIATE_DIR)/src/node/inspector/protocol/Network.cpp',
'<(SHARED_INTERMEDIATE_DIR)/src/node/inspector/protocol/Network.h',
],
'node_protocol_files': [
'<(protocol_tool_path)/lib/Allocator_h.template',
Expand Down
65 changes: 65 additions & 0 deletions src/inspector/node_protocol.pdl
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,71 @@ experimental domain NodeWorker
SessionID sessionId
string message

# Partial support for Network domain of ChromeDevTools Protocol.
# https://chromedevtools.github.io/devtools-protocol/tot/Network
experimental domain Network
# Unique request identifier.
type RequestId extends string

# UTC time in seconds, counted from January 1, 1970.
type TimeSinceEpoch extends number

# Monotonically increasing time in seconds since an arbitrary point in the past.
type MonotonicTime extends number

# HTTP request data.
type Request extends object
properties
string url
string method

# Returns content served for the given request.
command getResponseBody
parameters
# Identifier of the network request to get content for.
RequestId requestId
returns
# Response body.
string body

# Fired when page is about to send HTTP request.
event requestWillBeSent
parameters
# Request identifier.
RequestId requestId
# Request data.
Request request
# Timestamp.
MonotonicTime timestamp
# Timestamp.
TimeSinceEpoch wallTime

# Fired when HTTP response is available.
event responseReceived
parameters
# Request identifier.
RequestId requestId
# Timestamp.
MonotonicTime timestamp

event dataReceived
parameters
# Request identifier.
RequestId requestId
# Timestamp.
MonotonicTime timestamp
# Data chunk length.
integer dataLength

event loadingFinished
parameters
# Request identifier.
RequestId requestId
# Timestamp.
MonotonicTime timestamp
# Total number of bytes received for this request.
number encodedDataLength

# Support for inspecting node process state.
experimental domain NodeRuntime
# Enable the NodeRuntime events except by `NodeRuntime.waitingForDisconnect`.
Expand Down
2 changes: 1 addition & 1 deletion src/inspector/node_string.cc
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ String StringViewToUtf8(v8_inspector::StringView view) {
String fromDouble(double d) {
std::ostringstream stream;
stream.imbue(std::locale::classic()); // Ignore current locale
stream << d;
stream << std::fixed << d;
return stream.str();
}

Expand Down
Loading

0 comments on commit 6e727ee

Please sign in to comment.