inspector: convert event params to protocol without json

Event params object can be converted to inspector protocol directly.
This also enables binary data, like `Network.dataReceived`, to be sent
in the inspector protocol from JavaScript since JSON representation
does not support plain binary data.

PR-URL: https://github.com/nodejs/node/pull/57027
Reviewed-By: Kohei Ueno <kohei.ueno119@gmail.com>
This commit is contained in:
Chengzhong Wu 2025-02-24 12:36:23 +00:00 committed by GitHub
parent 044d69a0af
commit b7beb3334e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 339 additions and 155 deletions

View File

@ -24,6 +24,7 @@ if (!hasInspector)
const EventEmitter = require('events');
const { queueMicrotask } = require('internal/process/task_queues');
const { kEmptyObject } = require('internal/util');
const {
isUint32,
validateFunction,
@ -189,12 +190,10 @@ function inspectorWaitForDebugger() {
throw new ERR_INSPECTOR_NOT_ACTIVE();
}
function broadcastToFrontend(eventName, params) {
function broadcastToFrontend(eventName, params = kEmptyObject) {
validateString(eventName, 'eventName');
if (params) {
validateObject(params, 'params');
}
emitProtocolEvent(eventName, JSONStringify(params ?? {}));
validateObject(params, 'params');
emitProtocolEvent(eventName, params);
}
const Network = {

View File

@ -1,27 +1,174 @@
#include "network_agent.h"
#include "inspector/protocol_helper.h"
#include "network_inspector.h"
#include "util-inl.h"
#include "v8.h"
namespace node {
namespace inspector {
namespace protocol {
std::unique_ptr<Network::Request> createRequest(
const String& url,
const String& method,
std::unique_ptr<Network::Headers> headers) {
return Network::Request::create()
using v8::EscapableHandleScope;
using v8::HandleScope;
using v8::Just;
using v8::Local;
using v8::Maybe;
using v8::MaybeLocal;
using v8::Nothing;
using v8::Object;
using v8::Value;
// Get a protocol string property from the object.
Maybe<protocol::String> ObjectGetProtocolString(v8::Local<v8::Context> context,
Local<Object> object,
Local<v8::String> property) {
HandleScope handle_scope(context->GetIsolate());
Local<Value> value;
if (!object->Get(context, property).ToLocal(&value) || !value->IsString()) {
return Nothing<protocol::String>();
}
Local<v8::String> str = value.As<v8::String>();
return Just(ToProtocolString(context->GetIsolate(), str));
}
// Get a protocol string property from the object.
Maybe<protocol::String> ObjectGetProtocolString(v8::Local<v8::Context> context,
Local<Object> object,
const char* property) {
HandleScope handle_scope(context->GetIsolate());
return ObjectGetProtocolString(
context, object, OneByteString(context->GetIsolate(), property));
}
// Get a protocol double property from the object.
Maybe<double> ObjectGetDouble(v8::Local<v8::Context> context,
Local<Object> object,
const char* property) {
HandleScope handle_scope(context->GetIsolate());
Local<Value> value;
if (!object->Get(context, OneByteString(context->GetIsolate(), property))
.ToLocal(&value) ||
!value->IsNumber()) {
return Nothing<double>();
}
return Just(value.As<v8::Number>()->Value());
}
// Get a protocol int property from the object.
Maybe<int> ObjectGetInt(v8::Local<v8::Context> context,
Local<Object> object,
const char* property) {
HandleScope handle_scope(context->GetIsolate());
Local<Value> value;
if (!object->Get(context, OneByteString(context->GetIsolate(), property))
.ToLocal(&value) ||
!value->IsInt32()) {
return Nothing<int>();
}
return Just(value.As<v8::Int32>()->Value());
}
// Get an object property from the object.
MaybeLocal<v8::Object> ObjectGetObject(v8::Local<v8::Context> context,
Local<Object> object,
const char* property) {
EscapableHandleScope handle_scope(context->GetIsolate());
Local<Value> value;
if (!object->Get(context, OneByteString(context->GetIsolate(), property))
.ToLocal(&value) ||
!value->IsObject()) {
return {};
}
return handle_scope.Escape(value.As<v8::Object>());
}
// Create a protocol::Network::Headers from the v8 object.
std::unique_ptr<protocol::Network::Headers> createHeadersFromObject(
v8::Local<v8::Context> context, Local<Object> headers_obj) {
HandleScope handle_scope(context->GetIsolate());
std::unique_ptr<protocol::DictionaryValue> dict =
protocol::DictionaryValue::create();
Local<v8::Array> property_names;
if (!headers_obj->GetOwnPropertyNames(context).ToLocal(&property_names)) {
return {};
}
for (size_t idx = 0; idx < property_names->Length(); idx++) {
Local<v8::Value> property_name_val;
if (!property_names->Get(context, idx).ToLocal(&property_name_val) ||
!property_name_val->IsString()) {
return {};
}
Local<v8::String> property_name = property_name_val.As<v8::String>();
protocol::String property_value;
if (!ObjectGetProtocolString(context, headers_obj, property_name)
.To(&property_value)) {
return {};
}
dict->setString(ToProtocolString(context->GetIsolate(), property_name),
property_value);
}
return std::make_unique<protocol::Network::Headers>(std::move(dict));
}
// Create a protocol::Network::Request from the v8 object.
std::unique_ptr<protocol::Network::Request> createRequestFromObject(
v8::Local<v8::Context> context, Local<Object> request) {
HandleScope handle_scope(context->GetIsolate());
protocol::String url;
if (!ObjectGetProtocolString(context, request, "url").To(&url)) {
return {};
}
protocol::String method;
if (!ObjectGetProtocolString(context, request, "method").To(&method)) {
return {};
}
Local<Object> headers_obj;
if (!ObjectGetObject(context, request, "headers").ToLocal(&headers_obj)) {
return {};
}
std::unique_ptr<protocol::Network::Headers> headers =
createHeadersFromObject(context, headers_obj);
if (!headers) {
return {};
}
return protocol::Network::Request::create()
.setUrl(url)
.setMethod(method)
.setHeaders(std::move(headers))
.build();
}
std::unique_ptr<Network::Response> createResponse(
const String& url,
int status,
const String& statusText,
std::unique_ptr<Network::Headers> headers) {
return Network::Response::create()
// Create a protocol::Network::Response from the v8 object.
std::unique_ptr<protocol::Network::Response> createResponseFromObject(
v8::Local<v8::Context> context, Local<Object> response) {
HandleScope handle_scope(context->GetIsolate());
protocol::String url;
if (!ObjectGetProtocolString(context, response, "url").To(&url)) {
return {};
}
int status;
if (!ObjectGetInt(context, response, "status").To(&status)) {
return {};
}
protocol::String statusText;
if (!ObjectGetProtocolString(context, response, "statusText")
.To(&statusText)) {
return {};
}
Local<Object> headers_obj;
if (!ObjectGetObject(context, response, "headers").ToLocal(&headers_obj)) {
return {};
}
std::unique_ptr<protocol::Network::Headers> headers =
createHeadersFromObject(context, headers_obj);
if (!headers) {
return {};
}
return protocol::Network::Response::create()
.setUrl(url)
.setStatus(status)
.setStatusText(statusText)
@ -38,123 +185,131 @@ NetworkAgent::NetworkAgent(NetworkInspector* inspector,
event_notifier_map_["loadingFinished"] = &NetworkAgent::loadingFinished;
}
void NetworkAgent::emitNotification(
const String& event, std::unique_ptr<protocol::DictionaryValue> params) {
void NetworkAgent::emitNotification(v8::Local<v8::Context> context,
const protocol::String& event,
v8::Local<v8::Object> params) {
if (!inspector_->IsEnabled()) return;
auto it = event_notifier_map_.find(event);
if (it != event_notifier_map_.end()) {
(this->*(it->second))(std::move(params));
(this->*(it->second))(context, params);
}
}
void NetworkAgent::Wire(UberDispatcher* dispatcher) {
frontend_ = std::make_unique<Network::Frontend>(dispatcher->channel());
Network::Dispatcher::wire(dispatcher, this);
void NetworkAgent::Wire(protocol::UberDispatcher* dispatcher) {
frontend_ =
std::make_unique<protocol::Network::Frontend>(dispatcher->channel());
protocol::Network::Dispatcher::wire(dispatcher, this);
}
DispatchResponse NetworkAgent::enable() {
protocol::DispatchResponse NetworkAgent::enable() {
inspector_->Enable();
return DispatchResponse::Success();
return protocol::DispatchResponse::Success();
}
DispatchResponse NetworkAgent::disable() {
protocol::DispatchResponse NetworkAgent::disable() {
inspector_->Disable();
return DispatchResponse::Success();
return protocol::DispatchResponse::Success();
}
void NetworkAgent::requestWillBeSent(
std::unique_ptr<protocol::DictionaryValue> params) {
String request_id;
params->getString("requestId", &request_id);
void NetworkAgent::requestWillBeSent(v8::Local<v8::Context> context,
v8::Local<v8::Object> params) {
protocol::String request_id;
if (!ObjectGetProtocolString(context, params, "requestId").To(&request_id)) {
return;
}
double timestamp;
params->getDouble("timestamp", &timestamp);
if (!ObjectGetDouble(context, params, "timestamp").To(&timestamp)) {
return;
}
double wall_time;
params->getDouble("wallTime", &wall_time);
auto request = params->getObject("request");
String url;
request->getString("url", &url);
String method;
request->getString("method", &method);
if (!ObjectGetDouble(context, params, "wallTime").To(&wall_time)) {
return;
}
Local<v8::Object> request_obj;
if (!ObjectGetObject(context, params, "request").ToLocal(&request_obj)) {
return;
}
std::unique_ptr<protocol::Network::Request> request =
createRequestFromObject(context, request_obj);
if (!request) {
return;
}
std::unique_ptr<Network::Initiator> initiator =
Network::Initiator::create()
.setType(Network::Initiator::TypeEnum::Script)
std::unique_ptr<protocol::Network::Initiator> initiator =
protocol::Network::Initiator::create()
.setType(protocol::Network::Initiator::TypeEnum::Script)
.setStack(
v8_inspector_->captureStackTrace(true)->buildInspectorObject(0))
.build();
ErrorSupport errors;
errors.Push();
errors.SetName("headers");
auto headers =
Network::Headers::fromValue(request->getObject("headers"), &errors);
if (!errors.Errors().empty()) {
headers = std::make_unique<Network::Headers>(DictionaryValue::create());
}
frontend_->requestWillBeSent(request_id,
createRequest(url, method, std::move(headers)),
std::move(request),
std::move(initiator),
timestamp,
wall_time);
}
void NetworkAgent::responseReceived(
std::unique_ptr<protocol::DictionaryValue> params) {
String request_id;
params->getString("requestId", &request_id);
void NetworkAgent::responseReceived(v8::Local<v8::Context> context,
v8::Local<v8::Object> params) {
protocol::String request_id;
if (!ObjectGetProtocolString(context, params, "requestId").To(&request_id)) {
return;
}
double timestamp;
params->getDouble("timestamp", &timestamp);
String type;
params->getString("type", &type);
auto response = params->getObject("response");
String url;
response->getString("url", &url);
int status;
response->getInteger("status", &status);
String statusText;
response->getString("statusText", &statusText);
ErrorSupport errors;
errors.Push();
errors.SetName("headers");
auto headers =
Network::Headers::fromValue(response->getObject("headers"), &errors);
if (!errors.Errors().empty()) {
headers = std::make_unique<Network::Headers>(DictionaryValue::create());
if (!ObjectGetDouble(context, params, "timestamp").To(&timestamp)) {
return;
}
protocol::String type;
if (!ObjectGetProtocolString(context, params, "type").To(&type)) {
return;
}
Local<Object> response_obj;
if (!ObjectGetObject(context, params, "response").ToLocal(&response_obj)) {
return;
}
auto response = createResponseFromObject(context, response_obj);
if (!response) {
return;
}
frontend_->responseReceived(
request_id,
timestamp,
type,
createResponse(url, status, statusText, std::move(headers)));
frontend_->responseReceived(request_id, timestamp, type, std::move(response));
}
void NetworkAgent::loadingFailed(
std::unique_ptr<protocol::DictionaryValue> params) {
String request_id;
params->getString("requestId", &request_id);
void NetworkAgent::loadingFailed(v8::Local<v8::Context> context,
v8::Local<v8::Object> params) {
protocol::String request_id;
if (!ObjectGetProtocolString(context, params, "requestId").To(&request_id)) {
return;
}
double timestamp;
params->getDouble("timestamp", &timestamp);
String type;
params->getString("type", &type);
String error_text;
params->getString("errorText", &error_text);
if (!ObjectGetDouble(context, params, "timestamp").To(&timestamp)) {
return;
}
protocol::String type;
if (!ObjectGetProtocolString(context, params, "type").To(&type)) {
return;
}
protocol::String error_text;
if (!ObjectGetProtocolString(context, params, "errorText").To(&error_text)) {
return;
}
frontend_->loadingFailed(request_id, timestamp, type, error_text);
}
void NetworkAgent::loadingFinished(
std::unique_ptr<protocol::DictionaryValue> params) {
String request_id;
params->getString("requestId", &request_id);
void NetworkAgent::loadingFinished(v8::Local<v8::Context> context,
Local<v8::Object> params) {
protocol::String request_id;
if (!ObjectGetProtocolString(context, params, "requestId").To(&request_id)) {
return;
}
double timestamp;
params->getDouble("timestamp", &timestamp);
if (!ObjectGetDouble(context, params, "timestamp").To(&timestamp)) {
return;
}
frontend_->loadingFinished(request_id, timestamp);
}
} // namespace protocol
} // namespace inspector
} // namespace node

View File

@ -6,44 +6,46 @@
#include <unordered_map>
namespace node {
namespace inspector {
class NetworkInspector;
namespace protocol {
class NetworkAgent : public Network::Backend {
class NetworkAgent : public protocol::Network::Backend {
public:
explicit NetworkAgent(NetworkInspector* inspector,
v8_inspector::V8Inspector* v8_inspector);
void Wire(UberDispatcher* dispatcher);
void Wire(protocol::UberDispatcher* dispatcher);
DispatchResponse enable() override;
protocol::DispatchResponse enable() override;
DispatchResponse disable() override;
protocol::DispatchResponse disable() override;
void emitNotification(const String& event,
std::unique_ptr<protocol::DictionaryValue> params);
void emitNotification(v8::Local<v8::Context> context,
const protocol::String& event,
v8::Local<v8::Object> params);
void requestWillBeSent(std::unique_ptr<protocol::DictionaryValue> params);
void requestWillBeSent(v8::Local<v8::Context> context,
v8::Local<v8::Object> params);
void responseReceived(std::unique_ptr<protocol::DictionaryValue> params);
void responseReceived(v8::Local<v8::Context> context,
v8::Local<v8::Object> params);
void loadingFailed(std::unique_ptr<protocol::DictionaryValue> params);
void loadingFailed(v8::Local<v8::Context> context,
v8::Local<v8::Object> params);
void loadingFinished(std::unique_ptr<protocol::DictionaryValue> params);
void loadingFinished(v8::Local<v8::Context> context,
v8::Local<v8::Object> params);
private:
NetworkInspector* inspector_;
v8_inspector::V8Inspector* v8_inspector_;
std::shared_ptr<Network::Frontend> frontend_;
using EventNotifier =
void (NetworkAgent::*)(std::unique_ptr<protocol::DictionaryValue>);
std::unordered_map<String, EventNotifier> event_notifier_map_;
std::shared_ptr<protocol::Network::Frontend> frontend_;
using EventNotifier = void (NetworkAgent::*)(v8::Local<v8::Context> context,
v8::Local<v8::Object>);
std::unordered_map<protocol::String, EventNotifier> event_notifier_map_;
};
} // namespace protocol
} // namespace inspector
} // namespace node

View File

@ -6,7 +6,7 @@ namespace inspector {
NetworkInspector::NetworkInspector(Environment* env,
v8_inspector::V8Inspector* v8_inspector)
: enabled_(false), env_(env) {
network_agent_ = std::make_unique<protocol::NetworkAgent>(this, v8_inspector);
network_agent_ = std::make_unique<NetworkAgent>(this, v8_inspector);
}
NetworkInspector::~NetworkInspector() {
network_agent_.reset();
@ -20,12 +20,12 @@ bool NetworkInspector::canEmit(const std::string& domain) {
return domain == "Network";
}
void NetworkInspector::emitNotification(
const std::string& domain,
const std::string& method,
std::unique_ptr<protocol::DictionaryValue> params) {
void NetworkInspector::emitNotification(v8::Local<v8::Context> context,
const std::string& domain,
const std::string& method,
v8::Local<v8::Object> params) {
if (domain == "Network") {
network_agent_->emitNotification(method, std::move(params));
network_agent_->emitNotification(context, method, params);
} else {
UNREACHABLE("Unknown domain");
}

View File

@ -19,9 +19,10 @@ class NetworkInspector {
bool canEmit(const std::string& domain);
void emitNotification(const std::string& domain,
void emitNotification(v8::Local<v8::Context> context,
const std::string& domain,
const std::string& method,
std::unique_ptr<protocol::DictionaryValue> params);
v8::Local<v8::Object> params);
void Enable();
void Disable();
@ -30,7 +31,7 @@ class NetworkInspector {
private:
bool enabled_;
Environment* env_;
std::unique_ptr<protocol::NetworkAgent> network_agent_;
std::unique_ptr<NetworkAgent> network_agent_;
};
} // namespace inspector

View File

@ -21,6 +21,7 @@
'src/inspector/node_json.h',
'src/inspector/node_string.cc',
'src/inspector/node_string.h',
'src/inspector/protocol_helper.h',
'src/inspector/runtime_agent.cc',
'src/inspector/runtime_agent.h',
'src/inspector/tracing_agent.cc',

View File

@ -0,0 +1,27 @@
#ifndef SRC_INSPECTOR_PROTOCOL_HELPER_H_
#define SRC_INSPECTOR_PROTOCOL_HELPER_H_
#include "node/inspector/protocol/Protocol.h"
#include "util.h"
#include "v8-inspector.h"
namespace node::inspector {
// Convert a V8 string to v8_inspector StringBuffer, encoded in UTF16.
inline std::unique_ptr<v8_inspector::StringBuffer> ToInspectorString(
v8::Isolate* isolate, v8::Local<v8::Value> value) {
TwoByteValue buffer(isolate, value);
return v8_inspector::StringBuffer::create(
v8_inspector::StringView(*buffer, buffer.length()));
}
// Convert a V8 string to node::inspector::protocol::String, encoded in UTF8.
inline protocol::String ToProtocolString(v8::Isolate* isolate,
v8::Local<v8::Value> value) {
Utf8Value buffer(isolate, value);
return *buffer;
}
} // namespace node::inspector
#endif // SRC_INSPECTOR_PROTOCOL_HELPER_H_

View File

@ -6,6 +6,7 @@
#include "inspector/network_inspector.h"
#include "inspector/node_json.h"
#include "inspector/node_string.h"
#include "inspector/protocol_helper.h"
#include "inspector/runtime_agent.h"
#include "inspector/tracing_agent.h"
#include "inspector/worker_agent.h"
@ -69,12 +70,6 @@ static std::atomic_bool start_io_thread_async_initialized { false };
// Protects the Agent* stored in start_io_thread_async.data.
static Mutex start_io_thread_async_mutex;
std::unique_ptr<StringBuffer> ToProtocolString(Isolate* isolate,
Local<Value> value) {
TwoByteValue buffer(isolate, value);
return StringBuffer::create(StringView(*buffer, buffer.length()));
}
// Called on the main thread.
void StartIoThreadAsyncCallback(uv_async_t* handle) {
static_cast<Agent*>(handle->data)->StartIoThread();
@ -259,16 +254,15 @@ class ChannelImpl final : public v8_inspector::V8Inspector::Channel,
network_inspector_.reset(); // Dispose before the dispatchers
}
void emitNotificationFromBackend(const StringView& event,
const StringView& params) {
std::unique_ptr<protocol::DictionaryValue> value =
protocol::DictionaryValue::cast(JsonUtil::parseJSON(params));
void emitNotificationFromBackend(v8::Local<v8::Context> context,
const StringView& event,
Local<Object> params) {
std::string raw_event = protocol::StringUtil::StringViewToUtf8(event);
std::string domain_name = raw_event.substr(0, raw_event.find('.'));
std::string event_name = raw_event.substr(raw_event.find('.') + 1);
if (network_inspector_->canEmit(domain_name)) {
network_inspector_->emitNotification(
domain_name, event_name, std::move(value));
context, domain_name, event_name, params);
} else {
UNREACHABLE("Unknown domain for emitNotificationFromBackend");
}
@ -619,8 +613,8 @@ class NodeInspectorClient : public V8InspectorClient {
context,
StringView(DETAILS, sizeof(DETAILS) - 1),
error,
ToProtocolString(isolate, message->Get())->string(),
ToProtocolString(isolate, message->GetScriptResourceName())->string(),
ToInspectorString(isolate, message->Get())->string(),
ToInspectorString(isolate, message->GetScriptResourceName())->string(),
message->GetLineNumber(context).FromMaybe(0),
message->GetStartColumn(context).FromMaybe(0),
client_->createStackTrace(stack_trace),
@ -688,9 +682,11 @@ class NodeInspectorClient : public V8InspectorClient {
return retaining_context;
}
void emitNotification(const StringView& event, const StringView& params) {
void emitNotification(v8::Local<v8::Context> context,
const StringView& event,
Local<Object> params) {
for (const auto& id_channel : channels_) {
id_channel.second->emitNotificationFromBackend(event, params);
id_channel.second->emitNotificationFromBackend(context, event, params);
}
}
@ -907,10 +903,11 @@ std::unique_ptr<InspectorSession> Agent::ConnectToMainThread(
prevent_shutdown);
}
void Agent::EmitProtocolEvent(const StringView& event,
const StringView& params) {
void Agent::EmitProtocolEvent(v8::Local<v8::Context> context,
const StringView& event,
Local<Object> params) {
if (!env()->options()->experimental_network_inspection) return;
client_->emitNotification(event, params);
client_->emitNotification(context, event, params);
}
void Agent::SetupNetworkTracking(Local<Function> enable_function,

View File

@ -69,8 +69,9 @@ class Agent {
void ReportUncaughtException(v8::Local<v8::Value> error,
v8::Local<v8::Message> message);
void EmitProtocolEvent(const v8_inspector::StringView& event,
const v8_inspector::StringView& params);
void EmitProtocolEvent(v8::Local<v8::Context> context,
const v8_inspector::StringView& event,
v8::Local<v8::Object> params);
void SetupNetworkTracking(v8::Local<v8::Function> enable_function,
v8::Local<v8::Function> disable_function);

View File

@ -1,4 +1,5 @@
#include "base_object-inl.h"
#include "inspector/protocol_helper.h"
#include "inspector_agent.h"
#include "inspector_io.h"
#include "memory_tracker-inl.h"
@ -27,16 +28,8 @@ using v8::Object;
using v8::String;
using v8::Uint32;
using v8::Value;
using v8_inspector::StringBuffer;
using v8_inspector::StringView;
std::unique_ptr<StringBuffer> ToProtocolString(Isolate* isolate,
Local<Value> value) {
TwoByteValue buffer(isolate, value);
return StringBuffer::create(StringView(*buffer, buffer.length()));
}
struct LocalConnection {
static std::unique_ptr<InspectorSession> Connect(
Agent* inspector, std::unique_ptr<InspectorSessionDelegate> delegate) {
@ -143,7 +136,7 @@ class JSBindingsConnection : public BaseObject {
if (session->session_) {
session->session_->Dispatch(
ToProtocolString(env->isolate(), info[0])->string());
ToInspectorString(env->isolate(), info[0])->string());
}
}
@ -275,12 +268,13 @@ void EmitProtocolEvent(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
CHECK(args[0]->IsString());
Local<String> eventName = args[0].As<String>();
CHECK(args[1]->IsString());
Local<String> params = args[1].As<String>();
CHECK(args[1]->IsObject());
Local<Object> params = args[1].As<Object>();
env->inspector_agent()->EmitProtocolEvent(
ToProtocolString(env->isolate(), eventName)->string(),
ToProtocolString(env->isolate(), params)->string());
args.GetIsolate()->GetCurrentContext(),
ToInspectorString(env->isolate(), eventName)->string(),
params);
}
void SetupNetworkTracking(const FunctionCallbackInfo<Value>& args) {

View File

@ -16,6 +16,7 @@ const EXPECTED_EVENTS = {
request: {
url: 'https://nodejs.org/en',
method: 'GET',
headers: {},
},
timestamp: 1000,
wallTime: 1000,
@ -25,7 +26,7 @@ const EXPECTED_EVENTS = {
request: {
url: 'https://nodejs.org/en',
method: 'GET',
headers: {} // Headers should be an empty object if not provided.
headers: {},
},
timestamp: 1000,
wallTime: 1000,
@ -40,6 +41,7 @@ const EXPECTED_EVENTS = {
response: {
url: 'https://nodejs.org/en',
status: 200,
statusText: '',
headers: { host: 'nodejs.org' }
}
},
@ -50,7 +52,7 @@ const EXPECTED_EVENTS = {
response: {
url: 'https://nodejs.org/en',
status: 200,
statusText: '', // Status text should be an empty string if not provided.
statusText: '',
headers: { host: 'nodejs.org' }
}
}
@ -104,6 +106,11 @@ const runAsyncTest = async () => {
for (const [domain, events] of Object.entries(EXPECTED_EVENTS)) {
for (const event of events) {
session.on(`${domain}.${event.name}`, common.mustCall(({ params }) => {
if (event.name === 'requestWillBeSent') {
// Initiator is automatically captured and contains caller info.
// No need to validate it.
delete params.initiator;
}
assert.deepStrictEqual(params, event.expected ?? event.params);
}));
inspector[domain][event.name](event.params);