From b54d24b44db72183ecb088769cffe5dd1d090632 Mon Sep 17 00:00:00 2001 From: Aras Abbasi Date: Thu, 12 Sep 2024 09:07:43 +0200 Subject: [PATCH] util: rename validateHandler to assertRequestHandler, minor changes in util.js (#3583) * util: rename validateHandler to assertRequestHandler, minor changes in jsdoc * util: rename validateHandler to assertRequestHandler, minor changes in jsdoc --- lib/core/request.js | 4 +- lib/core/util.js | 85 ++++++++++++++++++++++++++------- lib/handler/redirect-handler.js | 2 +- test/node-test/util.js | 20 ++++---- 4 files changed, 80 insertions(+), 31 deletions(-) diff --git a/lib/core/request.js b/lib/core/request.js index 376b360dfdb..c9bf388c316 100644 --- a/lib/core/request.js +++ b/lib/core/request.js @@ -15,7 +15,7 @@ const { isIterable, isBlobLike, serializePathWithQuery, - validateHandler, + assertRequestHandler, getServerName, normalizedMethodRecords } = require('./util') @@ -183,7 +183,7 @@ class Request { throw new InvalidArgumentError('headers must be an object or an array') } - validateHandler(handler, method, upgrade) + assertRequestHandler(handler, method, upgrade) this.servername = servername || getServerName(this.host) || null diff --git a/lib/core/util.js b/lib/core/util.js index cdc73195714..05dd11867d7 100644 --- a/lib/core/util.js +++ b/lib/core/util.js @@ -345,7 +345,7 @@ function isDestroyed (body) { /** * @param {import ('stream').Stream} stream * @param {Error} [err] - * @returns + * @returns {void} */ function destroy (stream, err) { if (stream == null || !isStream(stream) || isDestroyed(stream)) { @@ -478,12 +478,24 @@ function parseRawHeaders (headers) { return ret } +/** + * @param {*} buffer + * @returns {buffer is Buffer} + */ function isBuffer (buffer) { // See, https://github.com/mcollina/undici/pull/319 return buffer instanceof Uint8Array || Buffer.isBuffer(buffer) } -function validateHandler (handler, method, upgrade) { +/** + * Asserts that the handler object is a request handler. + * + * @param {object} handler + * @param {string} method + * @param {string} [upgrade] + * @returns {asserts handler is import('../api/api-request').RequestHandler} + */ +function assertRequestHandler (handler, method, upgrade) { if (!handler || typeof handler !== 'object') { throw new InvalidArgumentError('handler must be an object') } @@ -560,6 +572,7 @@ function getSocketInfo (socket) { } /** + * @param {Iterable} iterable * @returns {ReadableStream} */ function ReadableStreamFrom (iterable) { @@ -623,23 +636,47 @@ function addAbortListener (signal, listener) { return () => signal.removeListener('abort', listener) } -const hasToWellFormed = typeof String.prototype.toWellFormed === 'function' -const hasIsWellFormed = typeof String.prototype.isWellFormed === 'function' - /** - * @param {string} val + * @function + * @param {string} value + * @returns {string} */ -function toUSVString (val) { - return hasToWellFormed ? `${val}`.toWellFormed() : nodeUtil.toUSVString(val) -} +const toUSVString = (() => { + if (typeof String.prototype.toWellFormed === 'function') { + /** + * @param {string} value + * @returns {string} + */ + return (value) => `${value}`.toWellFormed() + } else { + /** + * @param {string} value + * @returns {string} + */ + return nodeUtil.toUSVString + } +})() /** - * @param {string} val + * @param {*} value + * @returns {boolean} */ // TODO: move this to webidl -function isUSVString (val) { - return hasIsWellFormed ? `${val}`.isWellFormed() : toUSVString(val) === `${val}` -} +const isUSVString = (() => { + if (typeof String.prototype.isWellFormed === 'function') { + /** + * @param {*} value + * @returns {boolean} + */ + return (value) => `${value}`.isWellFormed() + } else { + /** + * @param {*} value + * @returns {boolean} + */ + return (value) => toUSVString(value) === `${value}` + } +})() /** * @see https://tools.ietf.org/html/rfc7230#section-3.2.6 @@ -710,11 +747,18 @@ function isValidHeaderValue (characters) { const rangeHeaderRegex = /^bytes (\d+)-(\d+)\/(\d+)?$/ +/** + * @typedef {object} RangeHeader + * @property {number} start + * @property {number | null} end + * @property {number | null} size + */ + /** * Parse accordingly to RFC 9110 * @see https://www.rfc-editor.org/rfc/rfc9110#field.content-range * @param {string} [range] - * @returns + * @returns {RangeHeader|null} */ function parseRangeHeader (range) { if (range == null || range === '') return { start: 0, end: null, size: null } @@ -730,9 +774,11 @@ function parseRangeHeader (range) { } /** - * @param {Record} obj + * @template {import("events").EventEmitter} T + * @param {T} obj * @param {string} name - * @param {Function} listener + * @param {(...args: any[]) => void} listener + * @returns {T} */ function addListener (obj, name, listener) { const listeners = (obj[kListeners] ??= []) @@ -742,7 +788,9 @@ function addListener (obj, name, listener) { } /** - * @param {Record} obj + * @template {import("events").EventEmitter} T + * @param {T} obj + * @returns {T} */ function removeAllListeners (obj) { if (obj[kListeners] != null) { @@ -751,6 +799,7 @@ function removeAllListeners (obj) { } obj[kListeners] = null } + return obj } /** @@ -821,7 +870,7 @@ module.exports = { deepClone, ReadableStreamFrom, isBuffer, - validateHandler, + assertRequestHandler, getSocketInfo, isFormDataLike, serializePathWithQuery, diff --git a/lib/handler/redirect-handler.js b/lib/handler/redirect-handler.js index 3db7a476d45..7db5eaf385e 100644 --- a/lib/handler/redirect-handler.js +++ b/lib/handler/redirect-handler.js @@ -38,7 +38,7 @@ class RedirectHandler { throw new InvalidArgumentError('maxRedirections must be a positive number') } - util.validateHandler(handler, opts.method, opts.upgrade) + util.assertRequestHandler(handler, opts.method, opts.upgrade) this.dispatch = dispatch this.location = null diff --git a/test/node-test/util.js b/test/node-test/util.js index 0e5f6e3bdee..f488f866c45 100644 --- a/test/node-test/util.js +++ b/test/node-test/util.js @@ -29,34 +29,34 @@ test('getServerName', () => { assert.equal(util.getServerName('[2606:4700:4700::1111]:443'), '') }) -test('validateHandler', () => { - assert.throws(() => util.validateHandler(null), InvalidArgumentError, 'handler must be an object') - assert.throws(() => util.validateHandler({ +test('assertRequestHandler', () => { + assert.throws(() => util.assertRequestHandler(null), InvalidArgumentError, 'handler must be an object') + assert.throws(() => util.assertRequestHandler({ onConnect: null }), InvalidArgumentError, 'invalid onConnect method') - assert.throws(() => util.validateHandler({ + assert.throws(() => util.assertRequestHandler({ onConnect: () => {}, onError: null }), InvalidArgumentError, 'invalid onError method') - assert.throws(() => util.validateHandler({ + assert.throws(() => util.assertRequestHandler({ onConnect: () => {}, onError: () => {}, onBodySent: null }), InvalidArgumentError, 'invalid onBodySent method') - assert.throws(() => util.validateHandler({ + assert.throws(() => util.assertRequestHandler({ onConnect: () => {}, onError: () => {}, onBodySent: () => {}, onHeaders: null }), InvalidArgumentError, 'invalid onHeaders method') - assert.throws(() => util.validateHandler({ + assert.throws(() => util.assertRequestHandler({ onConnect: () => {}, onError: () => {}, onBodySent: () => {}, onHeaders: () => {}, onData: null }), InvalidArgumentError, 'invalid onData method') - assert.throws(() => util.validateHandler({ + assert.throws(() => util.assertRequestHandler({ onConnect: () => {}, onError: () => {}, onBodySent: () => {}, @@ -64,13 +64,13 @@ test('validateHandler', () => { onData: () => {}, onComplete: null }), InvalidArgumentError, 'invalid onComplete method') - assert.throws(() => util.validateHandler({ + assert.throws(() => util.assertRequestHandler({ onConnect: () => {}, onError: () => {}, onBodySent: () => {}, onUpgrade: 'null' }, 'CONNECT'), InvalidArgumentError, 'invalid onUpgrade method') - assert.throws(() => util.validateHandler({ + assert.throws(() => util.assertRequestHandler({ onConnect: () => {}, onError: () => {}, onBodySent: () => {},