mirror of
https://github.com/zebrajr/node.git
synced 2025-12-06 00:20:08 +01:00
inspector: add mimeType and charset support to Network.Response
Refs: https://github.com/nodejs/node/issues/53946 PR-URL: https://github.com/nodejs/node/pull/58192 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
This commit is contained in:
parent
3877800ffb
commit
a4c7c9f6d7
|
|
@ -16,6 +16,7 @@ const {
|
|||
} = require('internal/inspector/network');
|
||||
const dc = require('diagnostics_channel');
|
||||
const { Network } = require('inspector');
|
||||
const { MIMEType } = require('internal/mime');
|
||||
|
||||
const kRequestUrl = Symbol('kRequestUrl');
|
||||
|
||||
|
|
@ -93,6 +94,18 @@ function onClientResponseFinish({ request, response }) {
|
|||
if (typeof request[kInspectorRequestId] !== 'string') {
|
||||
return;
|
||||
}
|
||||
|
||||
let mimeType;
|
||||
let charset;
|
||||
try {
|
||||
const mimeTypeObj = new MIMEType(response.headers['content-type']);
|
||||
mimeType = mimeTypeObj.essence || '';
|
||||
charset = mimeTypeObj.params.get('charset') || '';
|
||||
} catch {
|
||||
mimeType = '';
|
||||
charset = '';
|
||||
}
|
||||
|
||||
Network.responseReceived({
|
||||
requestId: request[kInspectorRequestId],
|
||||
timestamp: getMonotonicTime(),
|
||||
|
|
@ -102,6 +115,8 @@ function onClientResponseFinish({ request, response }) {
|
|||
status: response.statusCode,
|
||||
statusText: response.statusMessage ?? '',
|
||||
headers: convertHeaderObject(response.headers)[1],
|
||||
mimeType,
|
||||
charset,
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
const {
|
||||
ArrayPrototypeFindIndex,
|
||||
DateNow,
|
||||
} = primordials;
|
||||
|
||||
|
|
@ -12,6 +13,7 @@ const {
|
|||
} = require('internal/inspector/network');
|
||||
const dc = require('diagnostics_channel');
|
||||
const { Network } = require('inspector');
|
||||
const { MIMEType } = require('internal/mime');
|
||||
|
||||
// Convert an undici request headers array to a plain object (Map<string, string>)
|
||||
function requestHeadersArrayToDictionary(headers) {
|
||||
|
|
@ -91,6 +93,21 @@ function onClientResponseHeaders({ request, response }) {
|
|||
if (typeof request[kInspectorRequestId] !== 'string') {
|
||||
return;
|
||||
}
|
||||
|
||||
let mimeType;
|
||||
let charset;
|
||||
try {
|
||||
const contentTypeKeyIndex =
|
||||
ArrayPrototypeFindIndex(response.headers, (header) => header.toString().toLowerCase() === 'content-type');
|
||||
const contentType = contentTypeKeyIndex !== -1 ? response.headers[contentTypeKeyIndex + 1].toString() : '';
|
||||
const mimeTypeObj = new MIMEType(contentType);
|
||||
mimeType = mimeTypeObj.essence || '';
|
||||
charset = mimeTypeObj.params.get('charset') || '';
|
||||
} catch {
|
||||
mimeType = '';
|
||||
charset = '';
|
||||
}
|
||||
|
||||
const url = `${request.origin}${request.path}`;
|
||||
Network.responseReceived({
|
||||
requestId: request[kInspectorRequestId],
|
||||
|
|
@ -102,6 +119,8 @@ function onClientResponseHeaders({ request, response }) {
|
|||
status: response.statusCode,
|
||||
statusText: response.statusText,
|
||||
headers: responseHeadersArrayToDictionary(response.headers),
|
||||
mimeType,
|
||||
charset,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -169,11 +169,23 @@ std::unique_ptr<protocol::Network::Response> createResponseFromObject(
|
|||
return {};
|
||||
}
|
||||
|
||||
protocol::String mimeType;
|
||||
if (!ObjectGetProtocolString(context, response, "mimeType").To(&mimeType)) {
|
||||
mimeType = protocol::String("");
|
||||
}
|
||||
|
||||
protocol::String charset = protocol::String();
|
||||
if (!ObjectGetProtocolString(context, response, "charset").To(&charset)) {
|
||||
charset = protocol::String("");
|
||||
}
|
||||
|
||||
return protocol::Network::Response::create()
|
||||
.setUrl(url)
|
||||
.setStatus(status)
|
||||
.setStatusText(statusText)
|
||||
.setHeaders(std::move(headers))
|
||||
.setMimeType(mimeType)
|
||||
.setCharset(charset)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -173,6 +173,8 @@ experimental domain Network
|
|||
integer status
|
||||
string statusText
|
||||
Headers headers
|
||||
string mimeType
|
||||
string charset
|
||||
|
||||
# Request / response headers as keys / values of JSON object.
|
||||
type Headers extends object
|
||||
|
|
|
|||
|
|
@ -42,7 +42,9 @@ const EXPECTED_EVENTS = {
|
|||
url: 'https://nodejs.org/en',
|
||||
status: 200,
|
||||
statusText: '',
|
||||
headers: { host: 'nodejs.org' }
|
||||
headers: { host: 'nodejs.org' },
|
||||
mimeType: 'text/html',
|
||||
charset: 'utf-8'
|
||||
}
|
||||
},
|
||||
expected: {
|
||||
|
|
@ -53,7 +55,9 @@ const EXPECTED_EVENTS = {
|
|||
url: 'https://nodejs.org/en',
|
||||
status: 200,
|
||||
statusText: '',
|
||||
headers: { host: 'nodejs.org' }
|
||||
headers: { host: 'nodejs.org' },
|
||||
mimeType: 'text/html',
|
||||
charset: 'utf-8'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
|||
170
test/parallel/test-inspector-network-content-type.js
Normal file
170
test/parallel/test-inspector-network-content-type.js
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
// Flags: --inspect=0 --experimental-network-inspection
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
|
||||
common.skipIfInspectorDisabled();
|
||||
|
||||
const assert = require('node:assert');
|
||||
const http = require('node:http');
|
||||
const inspector = require('node:inspector/promises');
|
||||
|
||||
const testNetworkInspection = async (session, port, assert) => {
|
||||
let assertPromise = assert(session);
|
||||
fetch(`http://127.0.0.1:${port}/hello-world`).then(common.mustCall());
|
||||
await assertPromise;
|
||||
session.removeAllListeners();
|
||||
assertPromise = assert(session);
|
||||
new Promise((resolve, reject) => {
|
||||
const req = http.get(
|
||||
{
|
||||
host: '127.0.0.1',
|
||||
port,
|
||||
path: '/hello-world',
|
||||
},
|
||||
common.mustCall((res) => {
|
||||
res.on('data', () => {});
|
||||
res.on('end', () => {});
|
||||
resolve(res);
|
||||
})
|
||||
);
|
||||
req.on('error', reject);
|
||||
});
|
||||
await assertPromise;
|
||||
session.removeAllListeners();
|
||||
};
|
||||
|
||||
const test = (handleRequest, testSessionFunc) => new Promise((resolve) => {
|
||||
const session = new inspector.Session();
|
||||
session.connect();
|
||||
const httpServer = http.createServer(handleRequest);
|
||||
httpServer.listen(0, async () => {
|
||||
try {
|
||||
await session.post('Network.enable');
|
||||
await testNetworkInspection(
|
||||
session,
|
||||
httpServer.address().port,
|
||||
testSessionFunc
|
||||
);
|
||||
await session.post('Network.disable');
|
||||
} catch (err) {
|
||||
assert.fail(err);
|
||||
} finally {
|
||||
await session.disconnect();
|
||||
await httpServer.close();
|
||||
await inspector.close();
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
(async () => {
|
||||
await test(
|
||||
(req, res) => {
|
||||
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
|
||||
res.writeHead(200);
|
||||
res.end('hello world\n');
|
||||
},
|
||||
common.mustCall(
|
||||
(session) =>
|
||||
new Promise((resolve) => {
|
||||
session.on(
|
||||
'Network.responseReceived',
|
||||
common.mustCall(({ params }) => {
|
||||
assert.strictEqual(params.response.mimeType, 'text/plain');
|
||||
assert.strictEqual(params.response.charset, 'utf-8');
|
||||
})
|
||||
);
|
||||
session.on(
|
||||
'Network.loadingFinished',
|
||||
common.mustCall(({ params }) => {
|
||||
assert.ok(params.requestId.startsWith('node-network-event-'));
|
||||
assert.strictEqual(typeof params.timestamp, 'number');
|
||||
resolve();
|
||||
})
|
||||
);
|
||||
}),
|
||||
2
|
||||
)
|
||||
);
|
||||
|
||||
await test(
|
||||
(req, res) => {
|
||||
res.writeHead(200, {});
|
||||
res.end('hello world\n');
|
||||
},
|
||||
common.mustCall((session) =>
|
||||
new Promise((resolve) => {
|
||||
session.on(
|
||||
'Network.responseReceived',
|
||||
common.mustCall(({ params }) => {
|
||||
assert.strictEqual(params.response.mimeType, '');
|
||||
assert.strictEqual(params.response.charset, '');
|
||||
})
|
||||
);
|
||||
session.on(
|
||||
'Network.loadingFinished',
|
||||
common.mustCall(({ params }) => {
|
||||
assert.ok(params.requestId.startsWith('node-network-event-'));
|
||||
assert.strictEqual(typeof params.timestamp, 'number');
|
||||
resolve();
|
||||
})
|
||||
);
|
||||
}), 2
|
||||
)
|
||||
);
|
||||
|
||||
await test(
|
||||
(req, res) => {
|
||||
res.setHeader('Content-Type', 'invalid content-type');
|
||||
res.writeHead(200);
|
||||
res.end('hello world\n');
|
||||
},
|
||||
common.mustCall((session) =>
|
||||
new Promise((resolve) => {
|
||||
session.on(
|
||||
'Network.responseReceived',
|
||||
common.mustCall(({ params }) => {
|
||||
assert.strictEqual(params.response.mimeType, '');
|
||||
assert.strictEqual(params.response.charset, '');
|
||||
})
|
||||
);
|
||||
session.on(
|
||||
'Network.loadingFinished',
|
||||
common.mustCall(({ params }) => {
|
||||
assert.ok(params.requestId.startsWith('node-network-event-'));
|
||||
assert.strictEqual(typeof params.timestamp, 'number');
|
||||
resolve();
|
||||
})
|
||||
);
|
||||
}), 2
|
||||
)
|
||||
);
|
||||
|
||||
await test(
|
||||
(req, res) => {
|
||||
res.setHeader('Content-Type', 'text/plain');
|
||||
res.writeHead(200);
|
||||
res.end('hello world\n');
|
||||
},
|
||||
common.mustCall((session) =>
|
||||
new Promise((resolve) => {
|
||||
session.on(
|
||||
'Network.responseReceived',
|
||||
common.mustCall(({ params }) => {
|
||||
assert.strictEqual(params.response.mimeType, 'text/plain');
|
||||
assert.strictEqual(params.response.charset, '');
|
||||
})
|
||||
);
|
||||
session.on(
|
||||
'Network.loadingFinished',
|
||||
common.mustCall(({ params }) => {
|
||||
assert.ok(params.requestId.startsWith('node-network-event-'));
|
||||
assert.strictEqual(typeof params.timestamp, 'number');
|
||||
resolve();
|
||||
})
|
||||
);
|
||||
}), 2
|
||||
)
|
||||
);
|
||||
|
||||
})().then(common.mustCall());
|
||||
|
|
@ -36,6 +36,7 @@ const setResponseHeaders = (res) => {
|
|||
res.setHeader('etag', 12345);
|
||||
res.setHeader('Set-Cookie', ['key1=value1', 'key2=value2']);
|
||||
res.setHeader('x-header2', ['value1', 'value2']);
|
||||
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
|
||||
};
|
||||
|
||||
const handleRequest = (req, res) => {
|
||||
|
|
@ -101,6 +102,8 @@ const testHttpGet = () => new Promise((resolve, reject) => {
|
|||
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');
|
||||
assert.strictEqual(params.response.mimeType, 'text/plain');
|
||||
assert.strictEqual(params.response.charset, 'utf-8');
|
||||
}));
|
||||
session.on('Network.loadingFinished', common.mustCall(({ params }) => {
|
||||
assert.ok(params.requestId.startsWith('node-network-event-'));
|
||||
|
|
@ -138,6 +141,8 @@ const testHttpsGet = () => new Promise((resolve, reject) => {
|
|||
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');
|
||||
assert.strictEqual(params.response.mimeType, 'text/plain');
|
||||
assert.strictEqual(params.response.charset, 'utf-8');
|
||||
}));
|
||||
session.on('Network.loadingFinished', common.mustCall(({ params }) => {
|
||||
assert.ok(params.requestId.startsWith('node-network-event-'));
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ const setResponseHeaders = (res) => {
|
|||
res.setHeader('etag', 12345);
|
||||
res.setHeader('Set-Cookie', ['key1=value1', 'key2=value2']);
|
||||
res.setHeader('x-header2', ['value1', 'value2']);
|
||||
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
|
||||
};
|
||||
|
||||
const kTimeout = 1000;
|
||||
|
|
@ -106,6 +107,8 @@ function verifyResponseReceived({ method, params }, expect) {
|
|||
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');
|
||||
assert.strictEqual(params.response.mimeType, 'text/plain');
|
||||
assert.strictEqual(params.response.charset, 'utf-8');
|
||||
|
||||
return params;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user