inspector: add undici http tracking support
Add basic undici http tracking support via inspector protocol. This allows tracking `fetch` calls with an inspector. PR-URL: https://github.com/nodejs/node/pull/56488 Refs: https://github.com/nodejs/node/issues/53946 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Ethan Arrowood <ethan@arrowood.dev> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
This commit is contained in:
parent
7b472fdfe7
commit
4f45acef19
@ -8,6 +8,28 @@ const {
|
|||||||
const { now } = require('internal/perf/utils');
|
const { now } = require('internal/perf/utils');
|
||||||
const kInspectorRequestId = Symbol('kInspectorRequestId');
|
const kInspectorRequestId = Symbol('kInspectorRequestId');
|
||||||
|
|
||||||
|
// https://chromedevtools.github.io/devtools-protocol/1-3/Network/#type-ResourceType
|
||||||
|
const kResourceType = {
|
||||||
|
Document: 'Document',
|
||||||
|
Stylesheet: 'Stylesheet',
|
||||||
|
Image: 'Image',
|
||||||
|
Media: 'Media',
|
||||||
|
Font: 'Font',
|
||||||
|
Script: 'Script',
|
||||||
|
TextTrack: 'TextTrack',
|
||||||
|
XHR: 'XHR',
|
||||||
|
Fetch: 'Fetch',
|
||||||
|
Prefetch: 'Prefetch',
|
||||||
|
EventSource: 'EventSource',
|
||||||
|
WebSocket: 'WebSocket',
|
||||||
|
Manifest: 'Manifest',
|
||||||
|
SignedExchange: 'SignedExchange',
|
||||||
|
Ping: 'Ping',
|
||||||
|
CSPViolationReport: 'CSPViolationReport',
|
||||||
|
Preflight: 'Preflight',
|
||||||
|
Other: 'Other',
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a monotonically increasing time in seconds since an arbitrary point in the past.
|
* Return a monotonically increasing time in seconds since an arbitrary point in the past.
|
||||||
* @returns {number}
|
* @returns {number}
|
||||||
@ -26,6 +48,7 @@ function getNextRequestId() {
|
|||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
kInspectorRequestId,
|
kInspectorRequestId,
|
||||||
|
kResourceType,
|
||||||
getMonotonicTime,
|
getMonotonicTime,
|
||||||
getNextRequestId,
|
getNextRequestId,
|
||||||
};
|
};
|
||||||
|
@ -10,13 +10,13 @@ const {
|
|||||||
|
|
||||||
const {
|
const {
|
||||||
kInspectorRequestId,
|
kInspectorRequestId,
|
||||||
|
kResourceType,
|
||||||
getMonotonicTime,
|
getMonotonicTime,
|
||||||
getNextRequestId,
|
getNextRequestId,
|
||||||
} = require('internal/inspector/network');
|
} = require('internal/inspector/network');
|
||||||
const dc = require('diagnostics_channel');
|
const dc = require('diagnostics_channel');
|
||||||
const { Network } = require('inspector');
|
const { Network } = require('inspector');
|
||||||
|
|
||||||
const kResourceType = 'Other';
|
|
||||||
const kRequestUrl = Symbol('kRequestUrl');
|
const kRequestUrl = Symbol('kRequestUrl');
|
||||||
|
|
||||||
// Convert a Headers object (Map<string, number | string | string[]>) to a plain object (Map<string, string>)
|
// Convert a Headers object (Map<string, number | string | string[]>) to a plain object (Map<string, string>)
|
||||||
@ -79,7 +79,7 @@ function onClientRequestError({ request, error }) {
|
|||||||
Network.loadingFailed({
|
Network.loadingFailed({
|
||||||
requestId: request[kInspectorRequestId],
|
requestId: request[kInspectorRequestId],
|
||||||
timestamp: getMonotonicTime(),
|
timestamp: getMonotonicTime(),
|
||||||
type: kResourceType,
|
type: kResourceType.Other,
|
||||||
errorText: error.message,
|
errorText: error.message,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -96,7 +96,7 @@ function onClientResponseFinish({ request, response }) {
|
|||||||
Network.responseReceived({
|
Network.responseReceived({
|
||||||
requestId: request[kInspectorRequestId],
|
requestId: request[kInspectorRequestId],
|
||||||
timestamp: getMonotonicTime(),
|
timestamp: getMonotonicTime(),
|
||||||
type: kResourceType,
|
type: kResourceType.Other,
|
||||||
response: {
|
response: {
|
||||||
url: request[kRequestUrl],
|
url: request[kRequestUrl],
|
||||||
status: response.statusCode,
|
status: response.statusCode,
|
||||||
|
141
lib/internal/inspector/network_undici.js
Normal file
141
lib/internal/inspector/network_undici.js
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const {
|
||||||
|
DateNow,
|
||||||
|
} = primordials;
|
||||||
|
|
||||||
|
const {
|
||||||
|
kInspectorRequestId,
|
||||||
|
kResourceType,
|
||||||
|
getMonotonicTime,
|
||||||
|
getNextRequestId,
|
||||||
|
} = require('internal/inspector/network');
|
||||||
|
const dc = require('diagnostics_channel');
|
||||||
|
const { Network } = require('inspector');
|
||||||
|
|
||||||
|
// Convert an undici request headers array to a plain object (Map<string, string>)
|
||||||
|
function requestHeadersArrayToDictionary(headers) {
|
||||||
|
const dict = {};
|
||||||
|
for (let idx = 0; idx < headers.length; idx += 2) {
|
||||||
|
const key = `${headers[idx]}`;
|
||||||
|
const value = `${headers[idx + 1]}`;
|
||||||
|
dict[key] = value;
|
||||||
|
}
|
||||||
|
return dict;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Convert an undici response headers array to a plain object (Map<string, string>)
|
||||||
|
function responseHeadersArrayToDictionary(headers) {
|
||||||
|
const dict = {};
|
||||||
|
for (let idx = 0; idx < headers.length; idx += 2) {
|
||||||
|
const key = `${headers[idx]}`;
|
||||||
|
const value = `${headers[idx + 1]}`;
|
||||||
|
const prevValue = dict[key];
|
||||||
|
|
||||||
|
if (typeof prevValue === 'string') {
|
||||||
|
// ChromeDevTools frontend treats 'set-cookie' as a special case
|
||||||
|
// https://github.com/ChromeDevTools/devtools-frontend/blob/4275917f84266ef40613db3c1784a25f902ea74e/front_end/core/sdk/NetworkRequest.ts#L1368
|
||||||
|
if (key.toLowerCase() === 'set-cookie') dict[key] = `${prevValue}\n${value}`;
|
||||||
|
else dict[key] = `${prevValue}, ${value}`;
|
||||||
|
} else {
|
||||||
|
dict[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dict;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When a client request starts, emit Network.requestWillBeSent event.
|
||||||
|
* https://chromedevtools.github.io/devtools-protocol/1-3/Network/#event-requestWillBeSent
|
||||||
|
* @param {{ request: undici.Request }} event
|
||||||
|
*/
|
||||||
|
function onClientRequestStart({ request }) {
|
||||||
|
const url = `${request.origin}${request.path}`;
|
||||||
|
request[kInspectorRequestId] = getNextRequestId();
|
||||||
|
Network.requestWillBeSent({
|
||||||
|
requestId: request[kInspectorRequestId],
|
||||||
|
timestamp: getMonotonicTime(),
|
||||||
|
wallTime: DateNow(),
|
||||||
|
request: {
|
||||||
|
url,
|
||||||
|
method: request.method,
|
||||||
|
headers: requestHeadersArrayToDictionary(request.headers),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When a client request errors, emit Network.loadingFailed event.
|
||||||
|
* https://chromedevtools.github.io/devtools-protocol/1-3/Network/#event-loadingFailed
|
||||||
|
* @param {{ request: undici.Request, error: any }} event
|
||||||
|
*/
|
||||||
|
function onClientRequestError({ request, error }) {
|
||||||
|
if (typeof request[kInspectorRequestId] !== 'string') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Network.loadingFailed({
|
||||||
|
requestId: request[kInspectorRequestId],
|
||||||
|
timestamp: getMonotonicTime(),
|
||||||
|
// TODO(legendecas): distinguish between `undici.request` and `undici.fetch`.
|
||||||
|
type: kResourceType.Fetch,
|
||||||
|
errorText: error.message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When response headers are received, emit Network.responseReceived event.
|
||||||
|
* https://chromedevtools.github.io/devtools-protocol/1-3/Network/#event-responseReceived
|
||||||
|
* @param {{ request: undici.Request, response: undici.Response }} event
|
||||||
|
*/
|
||||||
|
function onClientResponseHeaders({ request, response }) {
|
||||||
|
if (typeof request[kInspectorRequestId] !== 'string') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const url = `${request.origin}${request.path}`;
|
||||||
|
Network.responseReceived({
|
||||||
|
requestId: request[kInspectorRequestId],
|
||||||
|
timestamp: getMonotonicTime(),
|
||||||
|
// TODO(legendecas): distinguish between `undici.request` and `undici.fetch`.
|
||||||
|
type: kResourceType.Fetch,
|
||||||
|
response: {
|
||||||
|
url,
|
||||||
|
status: response.statusCode,
|
||||||
|
statusText: response.statusText,
|
||||||
|
headers: responseHeadersArrayToDictionary(response.headers),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When a response is completed, emit Network.loadingFinished event.
|
||||||
|
* https://chromedevtools.github.io/devtools-protocol/1-3/Network/#event-loadingFinished
|
||||||
|
* @param {{ request: undici.Request, response: undici.Response }} event
|
||||||
|
*/
|
||||||
|
function onClientResponseFinish({ request }) {
|
||||||
|
if (typeof request[kInspectorRequestId] !== 'string') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Network.loadingFinished({
|
||||||
|
requestId: request[kInspectorRequestId],
|
||||||
|
timestamp: getMonotonicTime(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function enable() {
|
||||||
|
dc.subscribe('undici:request:create', onClientRequestStart);
|
||||||
|
dc.subscribe('undici:request:error', onClientRequestError);
|
||||||
|
dc.subscribe('undici:request:headers', onClientResponseHeaders);
|
||||||
|
dc.subscribe('undici:request:trailers', onClientResponseFinish);
|
||||||
|
}
|
||||||
|
|
||||||
|
function disable() {
|
||||||
|
dc.subscribe('undici:request:create', onClientRequestStart);
|
||||||
|
dc.subscribe('undici:request:error', onClientRequestError);
|
||||||
|
dc.subscribe('undici:request:headers', onClientResponseHeaders);
|
||||||
|
dc.subscribe('undici:request:trailers', onClientResponseFinish);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
enable,
|
||||||
|
disable,
|
||||||
|
};
|
@ -2,14 +2,12 @@
|
|||||||
|
|
||||||
function enable() {
|
function enable() {
|
||||||
require('internal/inspector/network_http').enable();
|
require('internal/inspector/network_http').enable();
|
||||||
// TODO: add undici request/websocket tracking.
|
require('internal/inspector/network_undici').enable();
|
||||||
// https://github.com/nodejs/node/issues/53946
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function disable() {
|
function disable() {
|
||||||
require('internal/inspector/network_http').disable();
|
require('internal/inspector/network_http').disable();
|
||||||
// TODO: add undici request/websocket tracking.
|
require('internal/inspector/network_undici').disable();
|
||||||
// https://github.com/nodejs/node/issues/53946
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
@ -120,7 +120,8 @@ BuiltinLoader::BuiltinCategories BuiltinLoader::GetBuiltinCategories() const {
|
|||||||
#if !HAVE_INSPECTOR
|
#if !HAVE_INSPECTOR
|
||||||
"inspector", "inspector/promises", "internal/util/inspector",
|
"inspector", "inspector/promises", "internal/util/inspector",
|
||||||
"internal/inspector/network", "internal/inspector/network_http",
|
"internal/inspector/network", "internal/inspector/network_http",
|
||||||
"internal/inspector_async_hook", "internal/inspector_network_tracking",
|
"internal/inspector/network_undici", "internal/inspector_async_hook",
|
||||||
|
"internal/inspector_network_tracking",
|
||||||
#endif // !HAVE_INSPECTOR
|
#endif // !HAVE_INSPECTOR
|
||||||
|
|
||||||
#if !NODE_USE_V8_PLATFORM || !defined(NODE_HAVE_I18N_SUPPORT)
|
#if !NODE_USE_V8_PLATFORM || !defined(NODE_HAVE_I18N_SUPPORT)
|
||||||
|
196
test/parallel/test-inspector-network-fetch.js
Normal file
196
test/parallel/test-inspector-network-fetch.js
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
// Flags: --inspect=0 --experimental-network-inspection
|
||||||
|
'use strict';
|
||||||
|
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');
|
||||||
|
const inspector = require('node:inspector/promises');
|
||||||
|
|
||||||
|
// Disable certificate validation for the global fetch.
|
||||||
|
const undici = require('../../deps/undici/src/index.js');
|
||||||
|
undici.setGlobalDispatcher(new undici.Agent({
|
||||||
|
connect: {
|
||||||
|
rejectUnauthorized: false,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const session = new inspector.Session();
|
||||||
|
session.connect();
|
||||||
|
|
||||||
|
const requestHeaders = [
|
||||||
|
['accept-language', 'en-US'],
|
||||||
|
['cookie', 'k1=v1'],
|
||||||
|
['cookie', 'k2=v2'],
|
||||||
|
['age', 1000],
|
||||||
|
['x-header1', 'value1'],
|
||||||
|
['x-header1', 'value2'],
|
||||||
|
];
|
||||||
|
|
||||||
|
const setResponseHeaders = (res) => {
|
||||||
|
res.setHeader('server', 'node');
|
||||||
|
res.setHeader('etag', 12345);
|
||||||
|
res.setHeader('Set-Cookie', ['key1=value1', 'key2=value2']);
|
||||||
|
res.setHeader('x-header2', ['value1', 'value2']);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRequest = (req, res) => {
|
||||||
|
const path = req.url;
|
||||||
|
switch (path) {
|
||||||
|
case '/hello-world':
|
||||||
|
setResponseHeaders(res);
|
||||||
|
res.writeHead(200);
|
||||||
|
res.end('hello world\n');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(false, `Unexpected path: ${path}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const httpServer = http.createServer(handleRequest);
|
||||||
|
|
||||||
|
const httpsServer = https.createServer({
|
||||||
|
key: fixtures.readKey('agent1-key.pem'),
|
||||||
|
cert: fixtures.readKey('agent1-cert.pem')
|
||||||
|
}, handleRequest);
|
||||||
|
|
||||||
|
const terminate = () => {
|
||||||
|
session.disconnect();
|
||||||
|
httpServer.close();
|
||||||
|
httpsServer.close();
|
||||||
|
inspector.close();
|
||||||
|
};
|
||||||
|
|
||||||
|
const testHttpGet = () => new Promise((resolve, reject) => {
|
||||||
|
session.on('Network.requestWillBeSent', common.mustCall(({ params }) => {
|
||||||
|
assert.ok(params.requestId.startsWith('node-network-event-'));
|
||||||
|
assert.strictEqual(params.request.url, `http://127.0.0.1:${httpServer.address().port}/hello-world`);
|
||||||
|
assert.strictEqual(params.request.method, 'GET');
|
||||||
|
assert.strictEqual(typeof params.request.headers, 'object');
|
||||||
|
assert.strictEqual(params.request.headers['accept-language'], 'en-US');
|
||||||
|
assert.strictEqual(params.request.headers.cookie, 'k1=v1; k2=v2');
|
||||||
|
assert.strictEqual(params.request.headers.age, '1000');
|
||||||
|
assert.strictEqual(params.request.headers['x-header1'], 'value1, value2');
|
||||||
|
assert.strictEqual(typeof params.timestamp, 'number');
|
||||||
|
assert.strictEqual(typeof params.wallTime, 'number');
|
||||||
|
}));
|
||||||
|
session.on('Network.responseReceived', common.mustCall(({ params }) => {
|
||||||
|
assert.ok(params.requestId.startsWith('node-network-event-'));
|
||||||
|
assert.strictEqual(typeof params.timestamp, 'number');
|
||||||
|
assert.strictEqual(params.type, 'Fetch');
|
||||||
|
assert.strictEqual(params.response.status, 200);
|
||||||
|
assert.strictEqual(params.response.statusText, 'OK');
|
||||||
|
assert.strictEqual(params.response.url, `http://127.0.0.1:${httpServer.address().port}/hello-world`);
|
||||||
|
assert.strictEqual(typeof params.response.headers, 'object');
|
||||||
|
assert.strictEqual(params.response.headers.server, 'node');
|
||||||
|
assert.strictEqual(params.response.headers.etag, '12345');
|
||||||
|
assert.strictEqual(params.response.headers['Set-Cookie'], 'key1=value1\nkey2=value2');
|
||||||
|
assert.strictEqual(params.response.headers['x-header2'], 'value1, value2');
|
||||||
|
}));
|
||||||
|
session.on('Network.loadingFinished', common.mustCall(({ params }) => {
|
||||||
|
assert.ok(params.requestId.startsWith('node-network-event-'));
|
||||||
|
assert.strictEqual(typeof params.timestamp, 'number');
|
||||||
|
resolve();
|
||||||
|
}));
|
||||||
|
|
||||||
|
fetch(`http://127.0.0.1:${httpServer.address().port}/hello-world`, {
|
||||||
|
headers: requestHeaders,
|
||||||
|
}).then(common.mustCall());
|
||||||
|
});
|
||||||
|
|
||||||
|
const testHttpsGet = () => new Promise((resolve, reject) => {
|
||||||
|
session.on('Network.requestWillBeSent', common.mustCall(({ params }) => {
|
||||||
|
assert.ok(params.requestId.startsWith('node-network-event-'));
|
||||||
|
assert.strictEqual(params.request.url, `https://127.0.0.1:${httpsServer.address().port}/hello-world`);
|
||||||
|
assert.strictEqual(params.request.method, 'GET');
|
||||||
|
assert.strictEqual(typeof params.request.headers, 'object');
|
||||||
|
assert.strictEqual(params.request.headers['accept-language'], 'en-US');
|
||||||
|
assert.strictEqual(params.request.headers.cookie, 'k1=v1; k2=v2');
|
||||||
|
assert.strictEqual(params.request.headers.age, '1000');
|
||||||
|
assert.strictEqual(params.request.headers['x-header1'], 'value1, value2');
|
||||||
|
assert.strictEqual(typeof params.timestamp, 'number');
|
||||||
|
assert.strictEqual(typeof params.wallTime, 'number');
|
||||||
|
}));
|
||||||
|
session.on('Network.responseReceived', common.mustCall(({ params }) => {
|
||||||
|
assert.ok(params.requestId.startsWith('node-network-event-'));
|
||||||
|
assert.strictEqual(typeof params.timestamp, 'number');
|
||||||
|
assert.strictEqual(params.type, 'Fetch');
|
||||||
|
assert.strictEqual(params.response.status, 200);
|
||||||
|
assert.strictEqual(params.response.statusText, 'OK');
|
||||||
|
assert.strictEqual(params.response.url, `https://127.0.0.1:${httpsServer.address().port}/hello-world`);
|
||||||
|
assert.strictEqual(typeof params.response.headers, 'object');
|
||||||
|
assert.strictEqual(params.response.headers.server, 'node');
|
||||||
|
assert.strictEqual(params.response.headers.etag, '12345');
|
||||||
|
assert.strictEqual(params.response.headers['Set-Cookie'], 'key1=value1\nkey2=value2');
|
||||||
|
assert.strictEqual(params.response.headers['x-header2'], 'value1, value2');
|
||||||
|
}));
|
||||||
|
session.on('Network.loadingFinished', common.mustCall(({ params }) => {
|
||||||
|
assert.ok(params.requestId.startsWith('node-network-event-'));
|
||||||
|
assert.strictEqual(typeof params.timestamp, 'number');
|
||||||
|
resolve();
|
||||||
|
}));
|
||||||
|
|
||||||
|
fetch(`https://127.0.0.1:${httpsServer.address().port}/hello-world`, {
|
||||||
|
headers: requestHeaders,
|
||||||
|
}).then(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, 'Fetch');
|
||||||
|
assert.strictEqual(typeof params.errorText, 'string');
|
||||||
|
resolve();
|
||||||
|
}));
|
||||||
|
session.on('Network.responseReceived', common.mustNotCall());
|
||||||
|
session.on('Network.loadingFinished', common.mustNotCall());
|
||||||
|
|
||||||
|
fetch(`http://${addresses.INVALID_HOST}`).catch(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, 'Fetch');
|
||||||
|
assert.strictEqual(typeof params.errorText, 'string');
|
||||||
|
resolve();
|
||||||
|
}));
|
||||||
|
session.on('Network.responseReceived', common.mustNotCall());
|
||||||
|
session.on('Network.loadingFinished', common.mustNotCall());
|
||||||
|
|
||||||
|
fetch(`https://${addresses.INVALID_HOST}`).catch(common.mustCall());
|
||||||
|
});
|
||||||
|
|
||||||
|
const testNetworkInspection = async () => {
|
||||||
|
await testHttpGet();
|
||||||
|
session.removeAllListeners();
|
||||||
|
await testHttpsGet();
|
||||||
|
session.removeAllListeners();
|
||||||
|
await testHttpError();
|
||||||
|
session.removeAllListeners();
|
||||||
|
await testHttpsError();
|
||||||
|
session.removeAllListeners();
|
||||||
|
};
|
||||||
|
|
||||||
|
httpServer.listen(0, () => {
|
||||||
|
httpsServer.listen(0, async () => {
|
||||||
|
try {
|
||||||
|
await session.post('Network.enable');
|
||||||
|
await testNetworkInspection();
|
||||||
|
await session.post('Network.disable');
|
||||||
|
} catch (e) {
|
||||||
|
assert.fail(e);
|
||||||
|
} finally {
|
||||||
|
terminate();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user