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 26, 2024
1 parent 4c730ae commit 6a9a7cf
Show file tree
Hide file tree
Showing 11 changed files with 484 additions and 2 deletions.
36 changes: 35 additions & 1 deletion lib/_http_client.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
const {
ArrayIsArray,
Boolean,
DateNow,
Error,
FunctionPrototypeCall,
NumberIsFinite,
Expand Down Expand Up @@ -70,6 +71,7 @@ const {
isTraceHTTPEnabled,
traceBegin,
traceEnd,
getNextInspectorEventId,
getNextTraceEventId,
} = require('internal/http');
const {
Expand All @@ -93,6 +95,14 @@ const {
stopPerf,
} = require('internal/perf/observe');

const {
isEnabled: isInspectorEnabled,
requestWillBeSent,
responseReceived,
dataReceived,
loadingFinished,
} = internalBinding('inspector');

const kClientRequestStatistics = Symbol('ClientRequestStatistics');

const dc = require('diagnostics_channel');
Expand Down Expand Up @@ -375,14 +385,15 @@ ObjectSetPrototypeOf(ClientRequest, OutgoingMessage);

ClientRequest.prototype._finish = function _finish() {
FunctionPrototypeCall(OutgoingMessage.prototype._finish, this);
const url = `${this.protocol}//${this.host}${this.path}`;
if (hasObserver('http')) {
startPerf(this, kClientRequestStatistics, {
type: 'http',
name: 'HttpClient',
detail: {
req: {
method: this.method,
url: `${this.protocol}//${this.host}${this.path}`,
url,
headers: typeof this.getHeaders === 'function' ? this.getHeaders() : {},
},
},
Expand All @@ -393,6 +404,14 @@ ClientRequest.prototype._finish = function _finish() {
request: this,
});
}

if (isInspectorEnabled()) {
this._inspectorEventId = getNextInspectorEventId();
const wallTime = DateNow();
const timestamp = wallTime / 1000;
requestWillBeSent(this._inspectorEventId, url, this.method, timestamp, wallTime);
}

if (isTraceHTTPEnabled()) {
this._traceEventId = getNextTraceEventId();
traceBegin(HTTP_CLIENT_TRACE_EVENT_NAME, this._traceEventId);
Expand Down Expand Up @@ -680,6 +699,21 @@ function parserOnIncomingClient(res, shouldKeepAlive) {
response: res,
});
}

if (isInspectorEnabled() && typeof req._inspectorEventId === 'string') {
responseReceived(req._inspectorEventId, DateNow() / 1000);
let response = '';
const onData = (chunk) => {
dataReceived(req._inspectorEventId, DateNow() / 1000, chunk.length);
response += chunk.toString();
};
res.on('data', onData);
res.on('end', () => {
loadingFinished(req._inspectorEventId, response, DateNow() / 1000, response.length);
res.removeListener('data', onData);
});
}

if (isTraceHTTPEnabled() && typeof req._traceEventId === 'number') {
traceEnd(HTTP_CLIENT_TRACE_EVENT_NAME, req._traceEventId, {
path: req.path,
Expand Down
8 changes: 8 additions & 0 deletions lib/internal/http.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ function resetCache() {
utcCache = undefined;
}

let inspectorEventId = 0;

function getNextInspectorEventId() {
const id = ++inspectorEventId;
return `node-network-inspect-event-${id}`;
}

let traceEventId = 0;

function getNextTraceEventId() {
Expand All @@ -57,6 +64,7 @@ module.exports = {
utcDate,
traceBegin,
traceEnd,
getNextInspectorEventId,
getNextTraceEventId,
isTraceHTTPEnabled,
};
60 changes: 60 additions & 0 deletions src/inspector/network_agent.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#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;
}
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 6a9a7cf

Please sign in to comment.