From 008ae8f7f22bd2565de3f8def42e141697f19208 Mon Sep 17 00:00:00 2001 From: theanarkh Date: Sun, 26 Jun 2022 21:23:03 +0800 Subject: [PATCH] http: export diagnostics channel for http --- doc/api/http.md | 58 +++++++++++++++++++ lib/_http_client.js | 19 +++++- lib/_http_server.js | 4 +- lib/http.js | 18 +++++- .../parallel/test-diagnostics-channel-http.js | 51 ++++++++++++++++ 5 files changed, 145 insertions(+), 5 deletions(-) create mode 100644 test/parallel/test-diagnostics-channel-http.js diff --git a/doc/api/http.md b/doc/api/http.md index 88f2378421998e..d6dd2c0bd16218 100644 --- a/doc/api/http.md +++ b/doc/api/http.md @@ -3605,6 +3605,64 @@ try { } ``` +## `http.diagnosticsChannel` + + + +* `onClientRequestStart` +* `onClientResponseFinish` +* `onHTTPRequestStart` +* `onHTTPResponseFinish` + +Examples: + +```js +'use strict'; + +const http = require('http'); + +http.diagnosticsChannel.onClientRequestStart.subscribe(({ request }) => { +}); + +http.diagnosticsChannel.onClientResponseFinish.subscribe(({ request, response }) => { + +}); + +http.diagnosticsChannel.onHTTPRequestStart.subscribe(({ + request, + response, + socket, + server, +}) => { + +}); + +http.diagnosticsChannel.onHTTPResponseFinish.subscribe(({ + request, + response, + socket, + server, +}) => { + +}); + +const server = http.createServer((req, res) => { + res.end('done'); +}); + +server.listen(() => { + const { port } = server.address(); + http.get(`http://localhost:${port}`, (res) => { + res.resume(); + res.on('end', () => { + server.close(); + }); + }); +}); +``` + [RFC 8187]: https://www.rfc-editor.org/rfc/rfc8187.txt [`'checkContinue'`]: #event-checkcontinue [`'finish'`]: #event-finish diff --git a/lib/_http_client.js b/lib/_http_client.js index a06b3904247d73..41f5be7ae2526e 100644 --- a/lib/_http_client.js +++ b/lib/_http_client.js @@ -90,6 +90,10 @@ const { const kClientRequestStatistics = Symbol('ClientRequestStatistics'); +const dc = require('diagnostics_channel'); +const onClientRequestStartChannel = dc.channel('http.client.request.start'); +const onClientResponseFinishChannel = dc.channel('http.client.response.finish'); + const { addAbortSignal, finished } = require('stream'); let debug = require('internal/util/debuglog').debuglog('http', (fn) => { @@ -367,6 +371,11 @@ ClientRequest.prototype._finish = function _finish() { }, }); } + if (onClientRequestStartChannel.hasSubscribers) { + onClientRequestStartChannel.publish({ + request: this, + }); + } }; ClientRequest.prototype._implicitHeader = function _implicitHeader() { @@ -645,6 +654,12 @@ function parserOnIncomingClient(res, shouldKeepAlive) { }, }); } + if (onClientResponseFinishChannel.hasSubscribers) { + onClientResponseFinishChannel.publish({ + request: req, + response: res, + }); + } req.res = res; res.req = req; @@ -927,5 +942,7 @@ ClientRequest.prototype.clearTimeout = function clearTimeout(cb) { }; module.exports = { - ClientRequest + ClientRequest, + onClientRequestStartChannel, + onClientResponseFinishChannel, }; diff --git a/lib/_http_server.js b/lib/_http_server.js index 938dd7aad75cee..7151a36393b22e 100644 --- a/lib/_http_server.js +++ b/lib/_http_server.js @@ -1080,5 +1080,7 @@ module.exports = { setupConnectionsTracking, storeHTTPOptions, _connectionListener: connectionListener, - kServerResponse + kServerResponse, + onRequestStartChannel, + onResponseFinishChannel, }; diff --git a/lib/http.js b/lib/http.js index 1366656e42eb94..53698928c043ec 100644 --- a/lib/http.js +++ b/lib/http.js @@ -28,7 +28,11 @@ const { } = primordials; const httpAgent = require('_http_agent'); -const { ClientRequest } = require('_http_client'); +const { + ClientRequest, + onClientRequestStartChannel, + onClientResponseFinishChannel, +} = require('_http_client'); const { methods } = require('_http_common'); const { IncomingMessage } = require('_http_incoming'); const { @@ -40,7 +44,9 @@ const { _connectionListener, STATUS_CODES, Server, - ServerResponse + ServerResponse, + onRequestStartChannel, + onResponseFinishChannel, } = require('_http_server'); let maxHeaderSize; @@ -123,7 +129,13 @@ module.exports = { validateHeaderName, validateHeaderValue, get, - request + request, + diagnosticsChannel: { + onClientRequestStart: onClientRequestStartChannel, + onClientResponseFinish: onClientResponseFinishChannel, + onHTTPRequestStart: onRequestStartChannel, + onHTTPResponseFinish: onResponseFinishChannel, + }, }; ObjectDefineProperty(module.exports, 'maxHeaderSize', { diff --git a/test/parallel/test-diagnostics-channel-http.js b/test/parallel/test-diagnostics-channel-http.js new file mode 100644 index 00000000000000..0ae6e973a4a9d4 --- /dev/null +++ b/test/parallel/test-diagnostics-channel-http.js @@ -0,0 +1,51 @@ +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const http = require('http'); + +http.diagnosticsChannel.onClientRequestStart.subscribe(common.mustCall(({ request }) => { + assert.strictEqual(typeof request, 'object'); +})); + +http.diagnosticsChannel.onClientResponseFinish.subscribe(common.mustCall(({ request, response }) => { + assert.strictEqual(typeof request, 'object'); + assert.strictEqual(typeof response, 'object'); +})); + +http.diagnosticsChannel.onHTTPRequestStart.subscribe(common.mustCall(({ + request, + response, + socket, + server, +}) => { + assert.strictEqual(typeof request, 'object'); + assert.strictEqual(typeof response, 'object'); + assert.strictEqual(typeof socket, 'object'); + assert.strictEqual(typeof server, 'object'); +})); + +http.diagnosticsChannel.onHTTPResponseFinish.subscribe(common.mustCall(({ + request, + response, + socket, + server, +}) => { + assert.strictEqual(typeof request, 'object'); + assert.strictEqual(typeof response, 'object'); + assert.strictEqual(typeof socket, 'object'); + assert.strictEqual(typeof server, 'object'); +})); + +const server = http.createServer(common.mustCall((req, res) => { + res.end('done'); +})); + +server.listen(() => { + const { port } = server.address(); + http.get(`http://localhost:${port}`, (res) => { + res.resume(); + res.on('end', () => { + server.close(); + }); + }); +});