Skip to content

Commit

Permalink
inspector: support Network.loadingFailed event
Browse files Browse the repository at this point in the history
PR-URL: nodejs#54246
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
  • Loading branch information
cola119 committed Aug 11, 2024
1 parent 298ff4f commit 746213e
Show file tree
Hide file tree
Showing 8 changed files with 109 additions and 0 deletions.
16 changes: 16 additions & 0 deletions doc/api/inspector.md
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,22 @@ This feature is only available with the `--experimental-network-inspection` flag
Broadcasts the `Network.loadingFinished` event to connected frontends. This event indicates that
HTTP request has finished loading.

### `inspector.Network.loadingFailed([params])`

<!-- YAML
added:
- REPLACEME
-->

> Stability: 1 - Experimental
* `params` {Object}

This feature is only available with the `--experimental-network-inspection` flag enabled.

Broadcasts the `Network.loadingFailed` event to connected frontends. This event indicates that
HTTP request has failed to load.

## Support of breakpoints

The Chrome DevTools Protocol [`Debugger` domain][] allows an
Expand Down
1 change: 1 addition & 0 deletions lib/inspector.js
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ const Network = {
requestWillBeSent: (params) => broadcastToFrontend('Network.requestWillBeSent', params),
responseReceived: (params) => broadcastToFrontend('Network.responseReceived', params),
loadingFinished: (params) => broadcastToFrontend('Network.loadingFinished', params),
loadingFailed: (params) => broadcastToFrontend('Network.loadingFailed', params),
};

module.exports = {
Expand Down
15 changes: 15 additions & 0 deletions lib/internal/inspector_network_tracking.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,19 @@ function onClientRequestStart({ request }) {
});
}

function onClientRequestError({ request, error }) {
if (typeof request._inspectorRequestId !== 'string') {
return;
}
const timestamp = DateNow() / 1000;
Network.loadingFailed({
requestId: request._inspectorRequestId,
timestamp,
type: 'Other',
errorText: error.message,
});
}

function onClientResponseFinish({ request, response }) {
if (typeof request._inspectorRequestId !== 'string') {
return;
Expand Down Expand Up @@ -80,11 +93,13 @@ function enable() {
Network = require('inspector').Network;
}
dc.subscribe('http.client.request.start', onClientRequestStart);
dc.subscribe('http.client.request.error', onClientRequestError);
dc.subscribe('http.client.response.finish', onClientResponseFinish);
}

function disable() {
dc.unsubscribe('http.client.request.start', onClientRequestStart);
dc.unsubscribe('http.client.request.error', onClientRequestError);
dc.unsubscribe('http.client.response.finish', onClientResponseFinish);
}

Expand Down
15 changes: 15 additions & 0 deletions src/inspector/network_agent.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ NetworkAgent::NetworkAgent(NetworkInspector* inspector)
: inspector_(inspector) {
event_notifier_map_["requestWillBeSent"] = &NetworkAgent::requestWillBeSent;
event_notifier_map_["responseReceived"] = &NetworkAgent::responseReceived;
event_notifier_map_["loadingFailed"] = &NetworkAgent::loadingFailed;
event_notifier_map_["loadingFinished"] = &NetworkAgent::loadingFinished;
}

Expand Down Expand Up @@ -117,6 +118,20 @@ void NetworkAgent::responseReceived(
createResponse(url, status, statusText, std::move(headers)));
}

void NetworkAgent::loadingFailed(
std::unique_ptr<protocol::DictionaryValue> params) {
String request_id;
params->getString("requestId", &request_id);
double timestamp;
params->getDouble("timestamp", &timestamp);
String type;
params->getString("type", &type);
String error_text;
params->getString("errorText", &error_text);

frontend_->loadingFailed(request_id, timestamp, type, error_text);
}

void NetworkAgent::loadingFinished(
std::unique_ptr<protocol::DictionaryValue> params) {
String request_id;
Expand Down
2 changes: 2 additions & 0 deletions src/inspector/network_agent.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ class NetworkAgent : public Network::Backend {

void responseReceived(std::unique_ptr<protocol::DictionaryValue> params);

void loadingFailed(std::unique_ptr<protocol::DictionaryValue> params);

void loadingFinished(std::unique_ptr<protocol::DictionaryValue> params);

private:
Expand Down
11 changes: 11 additions & 0 deletions src/inspector/node_protocol.pdl
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,17 @@ experimental domain Network
# Response data.
Response response

event loadingFailed
parameters
# Request identifier.
RequestId requestId
# Timestamp.
MonotonicTime timestamp
# Resource type.
ResourceType type
# Error message.
string errorText

event loadingFinished
parameters
# Request identifier.
Expand Down
9 changes: 9 additions & 0 deletions test/parallel/test-inspector-emit-protocol-event.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,15 @@ const EXPECTED_EVENTS = {
timestamp: 1000,
}
},
{
name: 'loadingFailed',
params: {
requestId: 'request-id-1',
timestamp: 1000,
type: 'Document',
errorText: 'Failed to load resource'
}
},
]
};

Expand Down
40 changes: 40 additions & 0 deletions test/parallel/test-inspector-network-domain.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const common = require('../common');
common.skipIfInspectorDisabled();

const assert = require('node:assert');
const { addresses } = require('../common/internet');
const fixtures = require('../common/fixtures');
const http = require('node:http');
const https = require('node:https');
Expand Down Expand Up @@ -144,11 +145,50 @@ const testHttpsGet = () => new Promise((resolve, reject) => {
}, common.mustCall());
});

const testHttpError = () => new Promise((resolve, reject) => {
session.on('Network.requestWillBeSent', common.mustCall());
session.on('Network.loadingFailed', common.mustCall(({ params }) => {
assert.ok(params.requestId.startsWith('node-network-event-'));
assert.strictEqual(typeof params.timestamp, 'number');
assert.strictEqual(params.type, 'Other');
assert.strictEqual(typeof params.errorText, 'string');
resolve();
}));
session.on('Network.responseReceived', common.mustNotCall());
session.on('Network.loadingFinished', common.mustNotCall());

http.get({
host: addresses.INVALID_HOST,
}, common.mustNotCall()).on('error', common.mustCall());
});


const testHttpsError = () => new Promise((resolve, reject) => {
session.on('Network.requestWillBeSent', common.mustCall());
session.on('Network.loadingFailed', common.mustCall(({ params }) => {
assert.ok(params.requestId.startsWith('node-network-event-'));
assert.strictEqual(typeof params.timestamp, 'number');
assert.strictEqual(params.type, 'Other');
assert.strictEqual(typeof params.errorText, 'string');
resolve();
}));
session.on('Network.responseReceived', common.mustNotCall());
session.on('Network.loadingFinished', common.mustNotCall());

https.get({
host: addresses.INVALID_HOST,
}, common.mustNotCall()).on('error', common.mustCall());
});

const testNetworkInspection = async () => {
await testHttpGet();
session.removeAllListeners();
await testHttpsGet();
session.removeAllListeners();
await testHttpError();
session.removeAllListeners();
await testHttpsError();
session.removeAllListeners();
};

httpServer.listen(0, () => {
Expand Down

0 comments on commit 746213e

Please sign in to comment.