format: prettify entire project

This commit is contained in:
Rim
2025-04-02 06:50:39 -04:00
parent 86f0782a98
commit 7ccc0be712
1711 changed files with 755867 additions and 235931 deletions

View File

@ -1,104 +1,125 @@
'use strict'
'use strict';
const net = require('node:net')
const assert = require('node:assert')
const util = require('./util')
const { InvalidArgumentError, ConnectTimeoutError } = require('./errors')
const timers = require('../util/timers')
const net = require('node:net');
const assert = require('node:assert');
const util = require('./util');
const { InvalidArgumentError, ConnectTimeoutError } = require('./errors');
const timers = require('../util/timers');
function noop () {}
function noop() {}
let tls // include tls conditionally since it is not always available
let tls; // include tls conditionally since it is not always available
// TODO: session re-use does not wait for the first
// connection to resolve the session and might therefore
// resolve the same servername multiple times even when
// re-use is enabled.
let SessionCache
let SessionCache;
// FIXME: remove workaround when the Node bug is fixed
// https://github.com/nodejs/node/issues/49344#issuecomment-1741776308
if (global.FinalizationRegistry && !(process.env.NODE_V8_COVERAGE || process.env.UNDICI_NO_FG)) {
if (
global.FinalizationRegistry &&
!(process.env.NODE_V8_COVERAGE || process.env.UNDICI_NO_FG)
) {
SessionCache = class WeakSessionCache {
constructor (maxCachedSessions) {
this._maxCachedSessions = maxCachedSessions
this._sessionCache = new Map()
constructor(maxCachedSessions) {
this._maxCachedSessions = maxCachedSessions;
this._sessionCache = new Map();
this._sessionRegistry = new global.FinalizationRegistry((key) => {
if (this._sessionCache.size < this._maxCachedSessions) {
return
return;
}
const ref = this._sessionCache.get(key)
const ref = this._sessionCache.get(key);
if (ref !== undefined && ref.deref() === undefined) {
this._sessionCache.delete(key)
this._sessionCache.delete(key);
}
})
});
}
get (sessionKey) {
const ref = this._sessionCache.get(sessionKey)
return ref ? ref.deref() : null
get(sessionKey) {
const ref = this._sessionCache.get(sessionKey);
return ref ? ref.deref() : null;
}
set (sessionKey, session) {
set(sessionKey, session) {
if (this._maxCachedSessions === 0) {
return
return;
}
this._sessionCache.set(sessionKey, new WeakRef(session))
this._sessionRegistry.register(session, sessionKey)
this._sessionCache.set(sessionKey, new WeakRef(session));
this._sessionRegistry.register(session, sessionKey);
}
}
};
} else {
SessionCache = class SimpleSessionCache {
constructor (maxCachedSessions) {
this._maxCachedSessions = maxCachedSessions
this._sessionCache = new Map()
constructor(maxCachedSessions) {
this._maxCachedSessions = maxCachedSessions;
this._sessionCache = new Map();
}
get (sessionKey) {
return this._sessionCache.get(sessionKey)
get(sessionKey) {
return this._sessionCache.get(sessionKey);
}
set (sessionKey, session) {
set(sessionKey, session) {
if (this._maxCachedSessions === 0) {
return
return;
}
if (this._sessionCache.size >= this._maxCachedSessions) {
// remove the oldest session
const { value: oldestKey } = this._sessionCache.keys().next()
this._sessionCache.delete(oldestKey)
const { value: oldestKey } = this._sessionCache.keys().next();
this._sessionCache.delete(oldestKey);
}
this._sessionCache.set(sessionKey, session)
this._sessionCache.set(sessionKey, session);
}
}
};
}
function buildConnector ({ allowH2, maxCachedSessions, socketPath, timeout, session: customSession, ...opts }) {
if (maxCachedSessions != null && (!Number.isInteger(maxCachedSessions) || maxCachedSessions < 0)) {
throw new InvalidArgumentError('maxCachedSessions must be a positive integer or zero')
function buildConnector({
allowH2,
maxCachedSessions,
socketPath,
timeout,
session: customSession,
...opts
}) {
if (
maxCachedSessions != null &&
(!Number.isInteger(maxCachedSessions) || maxCachedSessions < 0)
) {
throw new InvalidArgumentError(
'maxCachedSessions must be a positive integer or zero'
);
}
const options = { path: socketPath, ...opts }
const sessionCache = new SessionCache(maxCachedSessions == null ? 100 : maxCachedSessions)
timeout = timeout == null ? 10e3 : timeout
allowH2 = allowH2 != null ? allowH2 : false
return function connect ({ hostname, host, protocol, port, servername, localAddress, httpSocket }, callback) {
let socket
const options = { path: socketPath, ...opts };
const sessionCache = new SessionCache(
maxCachedSessions == null ? 100 : maxCachedSessions
);
timeout = timeout == null ? 10e3 : timeout;
allowH2 = allowH2 != null ? allowH2 : false;
return function connect(
{ hostname, host, protocol, port, servername, localAddress, httpSocket },
callback
) {
let socket;
if (protocol === 'https:') {
if (!tls) {
tls = require('node:tls')
tls = require('node:tls');
}
servername = servername || options.servername || util.getServerName(host) || null
servername =
servername || options.servername || util.getServerName(host) || null;
const sessionKey = servername || hostname
assert(sessionKey)
const sessionKey = servername || hostname;
assert(sessionKey);
const session = customSession || sessionCache.get(sessionKey) || null
const session = customSession || sessionCache.get(sessionKey) || null;
port = port || 443
port = port || 443;
socket = tls.connect({
highWaterMark: 16384, // TLS in node can't have bigger HWM anyway...
@ -110,59 +131,65 @@ function buildConnector ({ allowH2, maxCachedSessions, socketPath, timeout, sess
ALPNProtocols: allowH2 ? ['http/1.1', 'h2'] : ['http/1.1'],
socket: httpSocket, // upgrade socket connection
port,
host: hostname
})
host: hostname,
});
socket
.on('session', function (session) {
// TODO (fix): Can a session become invalid once established? Don't think so?
sessionCache.set(sessionKey, session)
})
socket.on('session', function (session) {
// TODO (fix): Can a session become invalid once established? Don't think so?
sessionCache.set(sessionKey, session);
});
} else {
assert(!httpSocket, 'httpSocket can only be sent on TLS update')
assert(!httpSocket, 'httpSocket can only be sent on TLS update');
port = port || 80
port = port || 80;
socket = net.connect({
highWaterMark: 64 * 1024, // Same as nodejs fs streams.
...options,
localAddress,
port,
host: hostname
})
host: hostname,
});
}
// Set TCP keep alive options on the socket here instead of in connect() for the case of assigning the socket
if (options.keepAlive == null || options.keepAlive) {
const keepAliveInitialDelay = options.keepAliveInitialDelay === undefined ? 60e3 : options.keepAliveInitialDelay
socket.setKeepAlive(true, keepAliveInitialDelay)
const keepAliveInitialDelay =
options.keepAliveInitialDelay === undefined ?
60e3
: options.keepAliveInitialDelay;
socket.setKeepAlive(true, keepAliveInitialDelay);
}
const clearConnectTimeout = setupConnectTimeout(new WeakRef(socket), { timeout, hostname, port })
const clearConnectTimeout = setupConnectTimeout(new WeakRef(socket), {
timeout,
hostname,
port,
});
socket
.setNoDelay(true)
.once(protocol === 'https:' ? 'secureConnect' : 'connect', function () {
queueMicrotask(clearConnectTimeout)
queueMicrotask(clearConnectTimeout);
if (callback) {
const cb = callback
callback = null
cb(null, this)
const cb = callback;
callback = null;
cb(null, this);
}
})
.on('error', function (err) {
queueMicrotask(clearConnectTimeout)
queueMicrotask(clearConnectTimeout);
if (callback) {
const cb = callback
callback = null
cb(err)
const cb = callback;
callback = null;
cb(err);
}
})
});
return socket
}
return socket;
};
}
/**
@ -173,44 +200,47 @@ function buildConnector ({ allowH2, maxCachedSessions, socketPath, timeout, sess
* @param {number} opts.port
* @returns {() => void}
*/
const setupConnectTimeout = process.platform === 'win32'
? (socketWeakRef, opts) => {
const setupConnectTimeout =
process.platform === 'win32' ?
(socketWeakRef, opts) => {
if (!opts.timeout) {
return noop
return noop;
}
let s1 = null
let s2 = null
let s1 = null;
let s2 = null;
const fastTimer = timers.setFastTimeout(() => {
// setImmediate is added to make sure that we prioritize socket error events over timeouts
// setImmediate is added to make sure that we prioritize socket error events over timeouts
s1 = setImmediate(() => {
// Windows needs an extra setImmediate probably due to implementation differences in the socket logic
s2 = setImmediate(() => onConnectTimeout(socketWeakRef.deref(), opts))
})
}, opts.timeout)
// Windows needs an extra setImmediate probably due to implementation differences in the socket logic
s2 = setImmediate(() =>
onConnectTimeout(socketWeakRef.deref(), opts)
);
});
}, opts.timeout);
return () => {
timers.clearFastTimeout(fastTimer)
clearImmediate(s1)
clearImmediate(s2)
}
timers.clearFastTimeout(fastTimer);
clearImmediate(s1);
clearImmediate(s2);
};
}
: (socketWeakRef, opts) => {
if (!opts.timeout) {
return noop
return noop;
}
let s1 = null
let s1 = null;
const fastTimer = timers.setFastTimeout(() => {
// setImmediate is added to make sure that we prioritize socket error events over timeouts
// setImmediate is added to make sure that we prioritize socket error events over timeouts
s1 = setImmediate(() => {
onConnectTimeout(socketWeakRef.deref(), opts)
})
}, opts.timeout)
onConnectTimeout(socketWeakRef.deref(), opts);
});
}, opts.timeout);
return () => {
timers.clearFastTimeout(fastTimer)
clearImmediate(s1)
}
}
timers.clearFastTimeout(fastTimer);
clearImmediate(s1);
};
};
/**
* @param {net.Socket} socket
@ -219,22 +249,22 @@ const setupConnectTimeout = process.platform === 'win32'
* @param {string} opts.hostname
* @param {number} opts.port
*/
function onConnectTimeout (socket, opts) {
function onConnectTimeout(socket, opts) {
// The socket could be already garbage collected
if (socket == null) {
return
return;
}
let message = 'Connect Timeout Error'
let message = 'Connect Timeout Error';
if (Array.isArray(socket.autoSelectFamilyAttemptedAddresses)) {
message += ` (attempted addresses: ${socket.autoSelectFamilyAttemptedAddresses.join(', ')},`
message += ` (attempted addresses: ${socket.autoSelectFamilyAttemptedAddresses.join(', ')},`;
} else {
message += ` (attempted address: ${opts.hostname}:${opts.port},`
message += ` (attempted address: ${opts.hostname}:${opts.port},`;
}
message += ` timeout: ${opts.timeout}ms)`
message += ` timeout: ${opts.timeout}ms)`;
util.destroy(socket, new ConnectTimeoutError(message))
util.destroy(socket, new ConnectTimeoutError(message));
}
module.exports = buildConnector
module.exports = buildConnector;

View File

@ -1,4 +1,4 @@
'use strict'
'use strict';
/**
* @see https://developer.mozilla.org/docs/Web/HTTP/Headers
@ -98,46 +98,46 @@ const wellknownHeaderNames = /** @type {const} */ ([
'X-Permitted-Cross-Domain-Policies',
'X-Powered-By',
'X-Requested-With',
'X-XSS-Protection'
])
'X-XSS-Protection',
]);
/** @type {Record<typeof wellknownHeaderNames[number]|Lowercase<typeof wellknownHeaderNames[number]>, string>} */
const headerNameLowerCasedRecord = {}
const headerNameLowerCasedRecord = {};
// Note: object prototypes should not be able to be referenced. e.g. `Object#hasOwnProperty`.
Object.setPrototypeOf(headerNameLowerCasedRecord, null)
Object.setPrototypeOf(headerNameLowerCasedRecord, null);
/**
* @type {Record<Lowercase<typeof wellknownHeaderNames[number]>, Buffer>}
*/
const wellknownHeaderNameBuffers = {}
const wellknownHeaderNameBuffers = {};
// Note: object prototypes should not be able to be referenced. e.g. `Object#hasOwnProperty`.
Object.setPrototypeOf(wellknownHeaderNameBuffers, null)
Object.setPrototypeOf(wellknownHeaderNameBuffers, null);
/**
* @param {string} header Lowercased header
* @returns {Buffer}
*/
function getHeaderNameAsBuffer (header) {
let buffer = wellknownHeaderNameBuffers[header]
function getHeaderNameAsBuffer(header) {
let buffer = wellknownHeaderNameBuffers[header];
if (buffer === undefined) {
buffer = Buffer.from(header)
buffer = Buffer.from(header);
}
return buffer
return buffer;
}
for (let i = 0; i < wellknownHeaderNames.length; ++i) {
const key = wellknownHeaderNames[i]
const lowerCasedKey = key.toLowerCase()
const key = wellknownHeaderNames[i];
const lowerCasedKey = key.toLowerCase();
headerNameLowerCasedRecord[key] = headerNameLowerCasedRecord[lowerCasedKey] =
lowerCasedKey
lowerCasedKey;
}
module.exports = {
wellknownHeaderNames,
headerNameLowerCasedRecord,
getHeaderNameAsBuffer
}
getHeaderNameAsBuffer,
};

View File

@ -1,11 +1,11 @@
'use strict'
'use strict';
const diagnosticsChannel = require('node:diagnostics_channel')
const util = require('node:util')
const diagnosticsChannel = require('node:diagnostics_channel');
const util = require('node:util');
const undiciDebugLog = util.debuglog('undici')
const fetchDebuglog = util.debuglog('fetch')
const websocketDebuglog = util.debuglog('websocket')
const undiciDebugLog = util.debuglog('undici');
const fetchDebuglog = util.debuglog('fetch');
const websocketDebuglog = util.debuglog('websocket');
const channels = {
// Client
@ -24,173 +24,158 @@ const channels = {
close: diagnosticsChannel.channel('undici:websocket:close'),
socketError: diagnosticsChannel.channel('undici:websocket:socket_error'),
ping: diagnosticsChannel.channel('undici:websocket:ping'),
pong: diagnosticsChannel.channel('undici:websocket:pong')
}
pong: diagnosticsChannel.channel('undici:websocket:pong'),
};
let isTrackingClientEvents = false
let isTrackingClientEvents = false;
function trackClientEvents (debugLog = undiciDebugLog) {
function trackClientEvents(debugLog = undiciDebugLog) {
if (isTrackingClientEvents) {
return
return;
}
isTrackingClientEvents = true
isTrackingClientEvents = true;
diagnosticsChannel.subscribe('undici:client:beforeConnect',
evt => {
const {
connectParams: { version, protocol, port, host }
} = evt
debugLog(
'connecting to %s%s using %s%s',
host,
port ? `:${port}` : '',
protocol,
version
)
})
diagnosticsChannel.subscribe('undici:client:beforeConnect', (evt) => {
const {
connectParams: { version, protocol, port, host },
} = evt;
debugLog(
'connecting to %s%s using %s%s',
host,
port ? `:${port}` : '',
protocol,
version
);
});
diagnosticsChannel.subscribe('undici:client:connected',
evt => {
const {
connectParams: { version, protocol, port, host }
} = evt
debugLog(
'connected to %s%s using %s%s',
host,
port ? `:${port}` : '',
protocol,
version
)
})
diagnosticsChannel.subscribe('undici:client:connected', (evt) => {
const {
connectParams: { version, protocol, port, host },
} = evt;
debugLog(
'connected to %s%s using %s%s',
host,
port ? `:${port}` : '',
protocol,
version
);
});
diagnosticsChannel.subscribe('undici:client:connectError',
evt => {
const {
connectParams: { version, protocol, port, host },
error
} = evt
debugLog(
'connection to %s%s using %s%s errored - %s',
host,
port ? `:${port}` : '',
protocol,
version,
error.message
)
})
diagnosticsChannel.subscribe('undici:client:connectError', (evt) => {
const {
connectParams: { version, protocol, port, host },
error,
} = evt;
debugLog(
'connection to %s%s using %s%s errored - %s',
host,
port ? `:${port}` : '',
protocol,
version,
error.message
);
});
diagnosticsChannel.subscribe('undici:client:sendHeaders',
evt => {
const {
request: { method, path, origin }
} = evt
debugLog('sending request to %s %s/%s', method, origin, path)
})
diagnosticsChannel.subscribe('undici:client:sendHeaders', (evt) => {
const {
request: { method, path, origin },
} = evt;
debugLog('sending request to %s %s/%s', method, origin, path);
});
}
let isTrackingRequestEvents = false
let isTrackingRequestEvents = false;
function trackRequestEvents (debugLog = undiciDebugLog) {
function trackRequestEvents(debugLog = undiciDebugLog) {
if (isTrackingRequestEvents) {
return
return;
}
isTrackingRequestEvents = true
isTrackingRequestEvents = true;
diagnosticsChannel.subscribe('undici:request:headers',
evt => {
const {
request: { method, path, origin },
response: { statusCode }
} = evt
debugLog(
'received response to %s %s/%s - HTTP %d',
method,
origin,
path,
statusCode
)
})
diagnosticsChannel.subscribe('undici:request:headers', (evt) => {
const {
request: { method, path, origin },
response: { statusCode },
} = evt;
debugLog(
'received response to %s %s/%s - HTTP %d',
method,
origin,
path,
statusCode
);
});
diagnosticsChannel.subscribe('undici:request:trailers',
evt => {
const {
request: { method, path, origin }
} = evt
debugLog('trailers received from %s %s/%s', method, origin, path)
})
diagnosticsChannel.subscribe('undici:request:trailers', (evt) => {
const {
request: { method, path, origin },
} = evt;
debugLog('trailers received from %s %s/%s', method, origin, path);
});
diagnosticsChannel.subscribe('undici:request:error',
evt => {
const {
request: { method, path, origin },
error
} = evt
debugLog(
'request to %s %s/%s errored - %s',
method,
origin,
path,
error.message
)
})
diagnosticsChannel.subscribe('undici:request:error', (evt) => {
const {
request: { method, path, origin },
error,
} = evt;
debugLog(
'request to %s %s/%s errored - %s',
method,
origin,
path,
error.message
);
});
}
let isTrackingWebSocketEvents = false
let isTrackingWebSocketEvents = false;
function trackWebSocketEvents (debugLog = websocketDebuglog) {
function trackWebSocketEvents(debugLog = websocketDebuglog) {
if (isTrackingWebSocketEvents) {
return
return;
}
isTrackingWebSocketEvents = true
isTrackingWebSocketEvents = true;
diagnosticsChannel.subscribe('undici:websocket:open',
evt => {
const {
address: { address, port }
} = evt
debugLog('connection opened %s%s', address, port ? `:${port}` : '')
})
diagnosticsChannel.subscribe('undici:websocket:open', (evt) => {
const {
address: { address, port },
} = evt;
debugLog('connection opened %s%s', address, port ? `:${port}` : '');
});
diagnosticsChannel.subscribe('undici:websocket:close',
evt => {
const { websocket, code, reason } = evt
debugLog(
'closed connection to %s - %s %s',
websocket.url,
code,
reason
)
})
diagnosticsChannel.subscribe('undici:websocket:close', (evt) => {
const { websocket, code, reason } = evt;
debugLog('closed connection to %s - %s %s', websocket.url, code, reason);
});
diagnosticsChannel.subscribe('undici:websocket:socket_error',
err => {
debugLog('connection errored - %s', err.message)
})
diagnosticsChannel.subscribe('undici:websocket:socket_error', (err) => {
debugLog('connection errored - %s', err.message);
});
diagnosticsChannel.subscribe('undici:websocket:ping',
evt => {
debugLog('ping received')
})
diagnosticsChannel.subscribe('undici:websocket:ping', (evt) => {
debugLog('ping received');
});
diagnosticsChannel.subscribe('undici:websocket:pong',
evt => {
debugLog('pong received')
})
diagnosticsChannel.subscribe('undici:websocket:pong', (evt) => {
debugLog('pong received');
});
}
if (undiciDebugLog.enabled || fetchDebuglog.enabled) {
trackClientEvents(fetchDebuglog.enabled ? fetchDebuglog : undiciDebugLog)
trackRequestEvents(fetchDebuglog.enabled ? fetchDebuglog : undiciDebugLog)
trackClientEvents(fetchDebuglog.enabled ? fetchDebuglog : undiciDebugLog);
trackRequestEvents(fetchDebuglog.enabled ? fetchDebuglog : undiciDebugLog);
}
if (websocketDebuglog.enabled) {
trackClientEvents(undiciDebugLog.enabled ? undiciDebugLog : websocketDebuglog)
trackWebSocketEvents(websocketDebuglog)
trackClientEvents(
undiciDebugLog.enabled ? undiciDebugLog : websocketDebuglog
);
trackWebSocketEvents(websocketDebuglog);
}
module.exports = {
channels
}
channels,
};

View File

@ -1,219 +1,221 @@
'use strict'
'use strict';
class UndiciError extends Error {
constructor (message, options) {
super(message, options)
this.name = 'UndiciError'
this.code = 'UND_ERR'
constructor(message, options) {
super(message, options);
this.name = 'UndiciError';
this.code = 'UND_ERR';
}
}
class ConnectTimeoutError extends UndiciError {
constructor (message) {
super(message)
this.name = 'ConnectTimeoutError'
this.message = message || 'Connect Timeout Error'
this.code = 'UND_ERR_CONNECT_TIMEOUT'
constructor(message) {
super(message);
this.name = 'ConnectTimeoutError';
this.message = message || 'Connect Timeout Error';
this.code = 'UND_ERR_CONNECT_TIMEOUT';
}
}
class HeadersTimeoutError extends UndiciError {
constructor (message) {
super(message)
this.name = 'HeadersTimeoutError'
this.message = message || 'Headers Timeout Error'
this.code = 'UND_ERR_HEADERS_TIMEOUT'
constructor(message) {
super(message);
this.name = 'HeadersTimeoutError';
this.message = message || 'Headers Timeout Error';
this.code = 'UND_ERR_HEADERS_TIMEOUT';
}
}
class HeadersOverflowError extends UndiciError {
constructor (message) {
super(message)
this.name = 'HeadersOverflowError'
this.message = message || 'Headers Overflow Error'
this.code = 'UND_ERR_HEADERS_OVERFLOW'
constructor(message) {
super(message);
this.name = 'HeadersOverflowError';
this.message = message || 'Headers Overflow Error';
this.code = 'UND_ERR_HEADERS_OVERFLOW';
}
}
class BodyTimeoutError extends UndiciError {
constructor (message) {
super(message)
this.name = 'BodyTimeoutError'
this.message = message || 'Body Timeout Error'
this.code = 'UND_ERR_BODY_TIMEOUT'
constructor(message) {
super(message);
this.name = 'BodyTimeoutError';
this.message = message || 'Body Timeout Error';
this.code = 'UND_ERR_BODY_TIMEOUT';
}
}
class ResponseStatusCodeError extends UndiciError {
constructor (message, statusCode, headers, body) {
super(message)
this.name = 'ResponseStatusCodeError'
this.message = message || 'Response Status Code Error'
this.code = 'UND_ERR_RESPONSE_STATUS_CODE'
this.body = body
this.status = statusCode
this.statusCode = statusCode
this.headers = headers
constructor(message, statusCode, headers, body) {
super(message);
this.name = 'ResponseStatusCodeError';
this.message = message || 'Response Status Code Error';
this.code = 'UND_ERR_RESPONSE_STATUS_CODE';
this.body = body;
this.status = statusCode;
this.statusCode = statusCode;
this.headers = headers;
}
}
class InvalidArgumentError extends UndiciError {
constructor (message) {
super(message)
this.name = 'InvalidArgumentError'
this.message = message || 'Invalid Argument Error'
this.code = 'UND_ERR_INVALID_ARG'
constructor(message) {
super(message);
this.name = 'InvalidArgumentError';
this.message = message || 'Invalid Argument Error';
this.code = 'UND_ERR_INVALID_ARG';
}
}
class InvalidReturnValueError extends UndiciError {
constructor (message) {
super(message)
this.name = 'InvalidReturnValueError'
this.message = message || 'Invalid Return Value Error'
this.code = 'UND_ERR_INVALID_RETURN_VALUE'
constructor(message) {
super(message);
this.name = 'InvalidReturnValueError';
this.message = message || 'Invalid Return Value Error';
this.code = 'UND_ERR_INVALID_RETURN_VALUE';
}
}
class AbortError extends UndiciError {
constructor (message) {
super(message)
this.name = 'AbortError'
this.message = message || 'The operation was aborted'
constructor(message) {
super(message);
this.name = 'AbortError';
this.message = message || 'The operation was aborted';
}
}
class RequestAbortedError extends AbortError {
constructor (message) {
super(message)
this.name = 'AbortError'
this.message = message || 'Request aborted'
this.code = 'UND_ERR_ABORTED'
constructor(message) {
super(message);
this.name = 'AbortError';
this.message = message || 'Request aborted';
this.code = 'UND_ERR_ABORTED';
}
}
class InformationalError extends UndiciError {
constructor (message) {
super(message)
this.name = 'InformationalError'
this.message = message || 'Request information'
this.code = 'UND_ERR_INFO'
constructor(message) {
super(message);
this.name = 'InformationalError';
this.message = message || 'Request information';
this.code = 'UND_ERR_INFO';
}
}
class RequestContentLengthMismatchError extends UndiciError {
constructor (message) {
super(message)
this.name = 'RequestContentLengthMismatchError'
this.message = message || 'Request body length does not match content-length header'
this.code = 'UND_ERR_REQ_CONTENT_LENGTH_MISMATCH'
constructor(message) {
super(message);
this.name = 'RequestContentLengthMismatchError';
this.message =
message || 'Request body length does not match content-length header';
this.code = 'UND_ERR_REQ_CONTENT_LENGTH_MISMATCH';
}
}
class ResponseContentLengthMismatchError extends UndiciError {
constructor (message) {
super(message)
this.name = 'ResponseContentLengthMismatchError'
this.message = message || 'Response body length does not match content-length header'
this.code = 'UND_ERR_RES_CONTENT_LENGTH_MISMATCH'
constructor(message) {
super(message);
this.name = 'ResponseContentLengthMismatchError';
this.message =
message || 'Response body length does not match content-length header';
this.code = 'UND_ERR_RES_CONTENT_LENGTH_MISMATCH';
}
}
class ClientDestroyedError extends UndiciError {
constructor (message) {
super(message)
this.name = 'ClientDestroyedError'
this.message = message || 'The client is destroyed'
this.code = 'UND_ERR_DESTROYED'
constructor(message) {
super(message);
this.name = 'ClientDestroyedError';
this.message = message || 'The client is destroyed';
this.code = 'UND_ERR_DESTROYED';
}
}
class ClientClosedError extends UndiciError {
constructor (message) {
super(message)
this.name = 'ClientClosedError'
this.message = message || 'The client is closed'
this.code = 'UND_ERR_CLOSED'
constructor(message) {
super(message);
this.name = 'ClientClosedError';
this.message = message || 'The client is closed';
this.code = 'UND_ERR_CLOSED';
}
}
class SocketError extends UndiciError {
constructor (message, socket) {
super(message)
this.name = 'SocketError'
this.message = message || 'Socket error'
this.code = 'UND_ERR_SOCKET'
this.socket = socket
constructor(message, socket) {
super(message);
this.name = 'SocketError';
this.message = message || 'Socket error';
this.code = 'UND_ERR_SOCKET';
this.socket = socket;
}
}
class NotSupportedError extends UndiciError {
constructor (message) {
super(message)
this.name = 'NotSupportedError'
this.message = message || 'Not supported error'
this.code = 'UND_ERR_NOT_SUPPORTED'
constructor(message) {
super(message);
this.name = 'NotSupportedError';
this.message = message || 'Not supported error';
this.code = 'UND_ERR_NOT_SUPPORTED';
}
}
class BalancedPoolMissingUpstreamError extends UndiciError {
constructor (message) {
super(message)
this.name = 'MissingUpstreamError'
this.message = message || 'No upstream has been added to the BalancedPool'
this.code = 'UND_ERR_BPL_MISSING_UPSTREAM'
constructor(message) {
super(message);
this.name = 'MissingUpstreamError';
this.message = message || 'No upstream has been added to the BalancedPool';
this.code = 'UND_ERR_BPL_MISSING_UPSTREAM';
}
}
class HTTPParserError extends Error {
constructor (message, code, data) {
super(message)
this.name = 'HTTPParserError'
this.code = code ? `HPE_${code}` : undefined
this.data = data ? data.toString() : undefined
constructor(message, code, data) {
super(message);
this.name = 'HTTPParserError';
this.code = code ? `HPE_${code}` : undefined;
this.data = data ? data.toString() : undefined;
}
}
class ResponseExceededMaxSizeError extends UndiciError {
constructor (message) {
super(message)
this.name = 'ResponseExceededMaxSizeError'
this.message = message || 'Response content exceeded max size'
this.code = 'UND_ERR_RES_EXCEEDED_MAX_SIZE'
constructor(message) {
super(message);
this.name = 'ResponseExceededMaxSizeError';
this.message = message || 'Response content exceeded max size';
this.code = 'UND_ERR_RES_EXCEEDED_MAX_SIZE';
}
}
class RequestRetryError extends UndiciError {
constructor (message, code, { headers, data }) {
super(message)
this.name = 'RequestRetryError'
this.message = message || 'Request retry error'
this.code = 'UND_ERR_REQ_RETRY'
this.statusCode = code
this.data = data
this.headers = headers
constructor(message, code, { headers, data }) {
super(message);
this.name = 'RequestRetryError';
this.message = message || 'Request retry error';
this.code = 'UND_ERR_REQ_RETRY';
this.statusCode = code;
this.data = data;
this.headers = headers;
}
}
class ResponseError extends UndiciError {
constructor (message, code, { headers, body }) {
super(message)
this.name = 'ResponseError'
this.message = message || 'Response error'
this.code = 'UND_ERR_RESPONSE'
this.statusCode = code
this.body = body
this.headers = headers
constructor(message, code, { headers, body }) {
super(message);
this.name = 'ResponseError';
this.message = message || 'Response error';
this.code = 'UND_ERR_RESPONSE';
this.statusCode = code;
this.body = body;
this.headers = headers;
}
}
class SecureProxyConnectionError extends UndiciError {
constructor (cause, message, options = {}) {
super(message, { cause, ...options })
this.name = 'SecureProxyConnectionError'
this.message = message || 'Secure Proxy Connection failed'
this.code = 'UND_ERR_PRX_TLS'
this.cause = cause
constructor(cause, message, options = {}) {
super(message, { cause, ...options });
this.name = 'SecureProxyConnectionError';
this.message = message || 'Secure Proxy Connection failed';
this.code = 'UND_ERR_PRX_TLS';
this.cause = cause;
}
}
@ -240,5 +242,5 @@ module.exports = {
ResponseExceededMaxSizeError,
RequestRetryError,
ResponseError,
SecureProxyConnectionError
}
SecureProxyConnectionError,
};

View File

@ -1,10 +1,7 @@
'use strict'
'use strict';
const {
InvalidArgumentError,
NotSupportedError
} = require('./errors')
const assert = require('node:assert')
const { InvalidArgumentError, NotSupportedError } = require('./errors');
const assert = require('node:assert');
const {
isValidHTTPToken,
isValidHeaderValue,
@ -17,381 +14,415 @@ const {
serializePathWithQuery,
assertRequestHandler,
getServerName,
normalizedMethodRecords
} = require('./util')
const { channels } = require('./diagnostics.js')
const { headerNameLowerCasedRecord } = require('./constants')
normalizedMethodRecords,
} = require('./util');
const { channels } = require('./diagnostics.js');
const { headerNameLowerCasedRecord } = require('./constants');
// Verifies that a given path is valid does not contain control chars \x00 to \x20
const invalidPathRegex = /[^\u0021-\u00ff]/
const invalidPathRegex = /[^\u0021-\u00ff]/;
const kHandler = Symbol('handler')
const kHandler = Symbol('handler');
class Request {
constructor (origin, {
path,
method,
body,
headers,
query,
idempotent,
blocking,
upgrade,
headersTimeout,
bodyTimeout,
reset,
expectContinue,
servername,
throwOnError
}, handler) {
constructor(
origin,
{
path,
method,
body,
headers,
query,
idempotent,
blocking,
upgrade,
headersTimeout,
bodyTimeout,
reset,
expectContinue,
servername,
throwOnError,
},
handler
) {
if (typeof path !== 'string') {
throw new InvalidArgumentError('path must be a string')
throw new InvalidArgumentError('path must be a string');
} else if (
path[0] !== '/' &&
!(path.startsWith('http://') || path.startsWith('https://')) &&
method !== 'CONNECT'
) {
throw new InvalidArgumentError('path must be an absolute URL or start with a slash')
throw new InvalidArgumentError(
'path must be an absolute URL or start with a slash'
);
} else if (invalidPathRegex.test(path)) {
throw new InvalidArgumentError('invalid request path')
throw new InvalidArgumentError('invalid request path');
}
if (typeof method !== 'string') {
throw new InvalidArgumentError('method must be a string')
} else if (normalizedMethodRecords[method] === undefined && !isValidHTTPToken(method)) {
throw new InvalidArgumentError('invalid request method')
throw new InvalidArgumentError('method must be a string');
} else if (
normalizedMethodRecords[method] === undefined &&
!isValidHTTPToken(method)
) {
throw new InvalidArgumentError('invalid request method');
}
if (upgrade && typeof upgrade !== 'string') {
throw new InvalidArgumentError('upgrade must be a string')
throw new InvalidArgumentError('upgrade must be a string');
}
if (headersTimeout != null && (!Number.isFinite(headersTimeout) || headersTimeout < 0)) {
throw new InvalidArgumentError('invalid headersTimeout')
if (
headersTimeout != null &&
(!Number.isFinite(headersTimeout) || headersTimeout < 0)
) {
throw new InvalidArgumentError('invalid headersTimeout');
}
if (bodyTimeout != null && (!Number.isFinite(bodyTimeout) || bodyTimeout < 0)) {
throw new InvalidArgumentError('invalid bodyTimeout')
if (
bodyTimeout != null &&
(!Number.isFinite(bodyTimeout) || bodyTimeout < 0)
) {
throw new InvalidArgumentError('invalid bodyTimeout');
}
if (reset != null && typeof reset !== 'boolean') {
throw new InvalidArgumentError('invalid reset')
throw new InvalidArgumentError('invalid reset');
}
if (expectContinue != null && typeof expectContinue !== 'boolean') {
throw new InvalidArgumentError('invalid expectContinue')
throw new InvalidArgumentError('invalid expectContinue');
}
if (throwOnError != null) {
throw new InvalidArgumentError('invalid throwOnError')
throw new InvalidArgumentError('invalid throwOnError');
}
this.headersTimeout = headersTimeout
this.headersTimeout = headersTimeout;
this.bodyTimeout = bodyTimeout
this.bodyTimeout = bodyTimeout;
this.method = method
this.method = method;
this.abort = null
this.abort = null;
if (body == null) {
this.body = null
this.body = null;
} else if (isStream(body)) {
this.body = body
this.body = body;
const rState = this.body._readableState
const rState = this.body._readableState;
if (!rState || !rState.autoDestroy) {
this.endHandler = function autoDestroy () {
destroy(this)
}
this.body.on('end', this.endHandler)
this.endHandler = function autoDestroy() {
destroy(this);
};
this.body.on('end', this.endHandler);
}
this.errorHandler = err => {
this.errorHandler = (err) => {
if (this.abort) {
this.abort(err)
this.abort(err);
} else {
this.error = err
this.error = err;
}
}
this.body.on('error', this.errorHandler)
};
this.body.on('error', this.errorHandler);
} else if (isBuffer(body)) {
this.body = body.byteLength ? body : null
this.body = body.byteLength ? body : null;
} else if (ArrayBuffer.isView(body)) {
this.body = body.buffer.byteLength ? Buffer.from(body.buffer, body.byteOffset, body.byteLength) : null
this.body =
body.buffer.byteLength ?
Buffer.from(body.buffer, body.byteOffset, body.byteLength)
: null;
} else if (body instanceof ArrayBuffer) {
this.body = body.byteLength ? Buffer.from(body) : null
this.body = body.byteLength ? Buffer.from(body) : null;
} else if (typeof body === 'string') {
this.body = body.length ? Buffer.from(body) : null
this.body = body.length ? Buffer.from(body) : null;
} else if (isFormDataLike(body) || isIterable(body) || isBlobLike(body)) {
this.body = body
this.body = body;
} else {
throw new InvalidArgumentError('body must be a string, a Buffer, a Readable stream, an iterable, or an async iterable')
throw new InvalidArgumentError(
'body must be a string, a Buffer, a Readable stream, an iterable, or an async iterable'
);
}
this.completed = false
this.aborted = false
this.completed = false;
this.aborted = false;
this.upgrade = upgrade || null
this.upgrade = upgrade || null;
this.path = query ? serializePathWithQuery(path, query) : path
this.path = query ? serializePathWithQuery(path, query) : path;
this.origin = origin
this.origin = origin;
this.idempotent = idempotent == null
? method === 'HEAD' || method === 'GET'
: idempotent
this.idempotent =
idempotent == null ? method === 'HEAD' || method === 'GET' : idempotent;
this.blocking = blocking ?? this.method !== 'HEAD'
this.blocking = blocking ?? this.method !== 'HEAD';
this.reset = reset == null ? null : reset
this.reset = reset == null ? null : reset;
this.host = null
this.host = null;
this.contentLength = null
this.contentLength = null;
this.contentType = null
this.contentType = null;
this.headers = []
this.headers = [];
// Only for H2
this.expectContinue = expectContinue != null ? expectContinue : false
this.expectContinue = expectContinue != null ? expectContinue : false;
if (Array.isArray(headers)) {
if (headers.length % 2 !== 0) {
throw new InvalidArgumentError('headers array must be even')
throw new InvalidArgumentError('headers array must be even');
}
for (let i = 0; i < headers.length; i += 2) {
processHeader(this, headers[i], headers[i + 1])
processHeader(this, headers[i], headers[i + 1]);
}
} else if (headers && typeof headers === 'object') {
if (headers[Symbol.iterator]) {
for (const header of headers) {
if (!Array.isArray(header) || header.length !== 2) {
throw new InvalidArgumentError('headers must be in key-value pair format')
throw new InvalidArgumentError(
'headers must be in key-value pair format'
);
}
processHeader(this, header[0], header[1])
processHeader(this, header[0], header[1]);
}
} else {
const keys = Object.keys(headers)
const keys = Object.keys(headers);
for (let i = 0; i < keys.length; ++i) {
processHeader(this, keys[i], headers[keys[i]])
processHeader(this, keys[i], headers[keys[i]]);
}
}
} else if (headers != null) {
throw new InvalidArgumentError('headers must be an object or an array')
throw new InvalidArgumentError('headers must be an object or an array');
}
assertRequestHandler(handler, method, upgrade)
assertRequestHandler(handler, method, upgrade);
this.servername = servername || getServerName(this.host) || null
this.servername = servername || getServerName(this.host) || null;
this[kHandler] = handler
this[kHandler] = handler;
if (channels.create.hasSubscribers) {
channels.create.publish({ request: this })
channels.create.publish({ request: this });
}
}
onBodySent (chunk) {
onBodySent(chunk) {
if (this[kHandler].onBodySent) {
try {
return this[kHandler].onBodySent(chunk)
return this[kHandler].onBodySent(chunk);
} catch (err) {
this.abort(err)
this.abort(err);
}
}
}
onRequestSent () {
onRequestSent() {
if (channels.bodySent.hasSubscribers) {
channels.bodySent.publish({ request: this })
channels.bodySent.publish({ request: this });
}
if (this[kHandler].onRequestSent) {
try {
return this[kHandler].onRequestSent()
return this[kHandler].onRequestSent();
} catch (err) {
this.abort(err)
this.abort(err);
}
}
}
onConnect (abort) {
assert(!this.aborted)
assert(!this.completed)
onConnect(abort) {
assert(!this.aborted);
assert(!this.completed);
if (this.error) {
abort(this.error)
abort(this.error);
} else {
this.abort = abort
return this[kHandler].onConnect(abort)
this.abort = abort;
return this[kHandler].onConnect(abort);
}
}
onResponseStarted () {
return this[kHandler].onResponseStarted?.()
onResponseStarted() {
return this[kHandler].onResponseStarted?.();
}
onHeaders (statusCode, headers, resume, statusText) {
assert(!this.aborted)
assert(!this.completed)
onHeaders(statusCode, headers, resume, statusText) {
assert(!this.aborted);
assert(!this.completed);
if (channels.headers.hasSubscribers) {
channels.headers.publish({ request: this, response: { statusCode, headers, statusText } })
channels.headers.publish({
request: this,
response: { statusCode, headers, statusText },
});
}
try {
return this[kHandler].onHeaders(statusCode, headers, resume, statusText)
return this[kHandler].onHeaders(statusCode, headers, resume, statusText);
} catch (err) {
this.abort(err)
this.abort(err);
}
}
onData (chunk) {
assert(!this.aborted)
assert(!this.completed)
onData(chunk) {
assert(!this.aborted);
assert(!this.completed);
try {
return this[kHandler].onData(chunk)
return this[kHandler].onData(chunk);
} catch (err) {
this.abort(err)
return false
this.abort(err);
return false;
}
}
onUpgrade (statusCode, headers, socket) {
assert(!this.aborted)
assert(!this.completed)
onUpgrade(statusCode, headers, socket) {
assert(!this.aborted);
assert(!this.completed);
return this[kHandler].onUpgrade(statusCode, headers, socket)
return this[kHandler].onUpgrade(statusCode, headers, socket);
}
onComplete (trailers) {
this.onFinally()
onComplete(trailers) {
this.onFinally();
assert(!this.aborted)
assert(!this.completed)
assert(!this.aborted);
assert(!this.completed);
this.completed = true
this.completed = true;
if (channels.trailers.hasSubscribers) {
channels.trailers.publish({ request: this, trailers })
channels.trailers.publish({ request: this, trailers });
}
try {
return this[kHandler].onComplete(trailers)
return this[kHandler].onComplete(trailers);
} catch (err) {
// TODO (fix): This might be a bad idea?
this.onError(err)
this.onError(err);
}
}
onError (error) {
this.onFinally()
onError(error) {
this.onFinally();
if (channels.error.hasSubscribers) {
channels.error.publish({ request: this, error })
channels.error.publish({ request: this, error });
}
if (this.aborted) {
return
return;
}
this.aborted = true
this.aborted = true;
return this[kHandler].onError(error)
return this[kHandler].onError(error);
}
onFinally () {
onFinally() {
if (this.errorHandler) {
this.body.off('error', this.errorHandler)
this.errorHandler = null
this.body.off('error', this.errorHandler);
this.errorHandler = null;
}
if (this.endHandler) {
this.body.off('end', this.endHandler)
this.endHandler = null
this.body.off('end', this.endHandler);
this.endHandler = null;
}
}
addHeader (key, value) {
processHeader(this, key, value)
return this
addHeader(key, value) {
processHeader(this, key, value);
return this;
}
}
function processHeader (request, key, val) {
if (val && (typeof val === 'object' && !Array.isArray(val))) {
throw new InvalidArgumentError(`invalid ${key} header`)
function processHeader(request, key, val) {
if (val && typeof val === 'object' && !Array.isArray(val)) {
throw new InvalidArgumentError(`invalid ${key} header`);
} else if (val === undefined) {
return
return;
}
let headerName = headerNameLowerCasedRecord[key]
let headerName = headerNameLowerCasedRecord[key];
if (headerName === undefined) {
headerName = key.toLowerCase()
if (headerNameLowerCasedRecord[headerName] === undefined && !isValidHTTPToken(headerName)) {
throw new InvalidArgumentError('invalid header key')
headerName = key.toLowerCase();
if (
headerNameLowerCasedRecord[headerName] === undefined &&
!isValidHTTPToken(headerName)
) {
throw new InvalidArgumentError('invalid header key');
}
}
if (Array.isArray(val)) {
const arr = []
const arr = [];
for (let i = 0; i < val.length; i++) {
if (typeof val[i] === 'string') {
if (!isValidHeaderValue(val[i])) {
throw new InvalidArgumentError(`invalid ${key} header`)
throw new InvalidArgumentError(`invalid ${key} header`);
}
arr.push(val[i])
arr.push(val[i]);
} else if (val[i] === null) {
arr.push('')
arr.push('');
} else if (typeof val[i] === 'object') {
throw new InvalidArgumentError(`invalid ${key} header`)
throw new InvalidArgumentError(`invalid ${key} header`);
} else {
arr.push(`${val[i]}`)
arr.push(`${val[i]}`);
}
}
val = arr
val = arr;
} else if (typeof val === 'string') {
if (!isValidHeaderValue(val)) {
throw new InvalidArgumentError(`invalid ${key} header`)
throw new InvalidArgumentError(`invalid ${key} header`);
}
} else if (val === null) {
val = ''
val = '';
} else {
val = `${val}`
val = `${val}`;
}
if (request.host === null && headerName === 'host') {
if (typeof val !== 'string') {
throw new InvalidArgumentError('invalid host header')
throw new InvalidArgumentError('invalid host header');
}
// Consumed by Client
request.host = val
} else if (request.contentLength === null && headerName === 'content-length') {
request.contentLength = parseInt(val, 10)
request.host = val;
} else if (
request.contentLength === null &&
headerName === 'content-length'
) {
request.contentLength = parseInt(val, 10);
if (!Number.isFinite(request.contentLength)) {
throw new InvalidArgumentError('invalid content-length header')
throw new InvalidArgumentError('invalid content-length header');
}
} else if (request.contentType === null && headerName === 'content-type') {
request.contentType = val
request.headers.push(key, val)
} else if (headerName === 'transfer-encoding' || headerName === 'keep-alive' || headerName === 'upgrade') {
throw new InvalidArgumentError(`invalid ${headerName} header`)
request.contentType = val;
request.headers.push(key, val);
} else if (
headerName === 'transfer-encoding' ||
headerName === 'keep-alive' ||
headerName === 'upgrade'
) {
throw new InvalidArgumentError(`invalid ${headerName} header`);
} else if (headerName === 'connection') {
const value = typeof val === 'string' ? val.toLowerCase() : null
const value = typeof val === 'string' ? val.toLowerCase() : null;
if (value !== 'close' && value !== 'keep-alive') {
throw new InvalidArgumentError('invalid connection header')
throw new InvalidArgumentError('invalid connection header');
}
if (value === 'close') {
request.reset = true
request.reset = true;
}
} else if (headerName === 'expect') {
throw new NotSupportedError('expect header not supported')
throw new NotSupportedError('expect header not supported');
} else {
request.headers.push(key, val)
request.headers.push(key, val);
}
}
module.exports = Request
module.exports = Request;

View File

@ -1,4 +1,4 @@
'use strict'
'use strict';
module.exports = {
kClose: Symbol('close'),
@ -64,5 +64,5 @@ module.exports = {
kMaxConcurrentStreams: Symbol('max concurrent streams'),
kNoProxyAgent: Symbol('no proxy agent'),
kHttpProxyAgent: Symbol('http proxy agent'),
kHttpsProxyAgent: Symbol('https proxy agent')
}
kHttpsProxyAgent: Symbol('https proxy agent'),
};

112
node_modules/undici/lib/core/tree.js generated vendored
View File

@ -1,39 +1,39 @@
'use strict'
'use strict';
const {
wellknownHeaderNames,
headerNameLowerCasedRecord
} = require('./constants')
headerNameLowerCasedRecord,
} = require('./constants');
class TstNode {
/** @type {any} */
value = null
value = null;
/** @type {null | TstNode} */
left = null
left = null;
/** @type {null | TstNode} */
middle = null
middle = null;
/** @type {null | TstNode} */
right = null
right = null;
/** @type {number} */
code
code;
/**
* @param {string} key
* @param {any} value
* @param {number} index
*/
constructor (key, value, index) {
constructor(key, value, index) {
if (index === undefined || index >= key.length) {
throw new TypeError('Unreachable')
throw new TypeError('Unreachable');
}
const code = this.code = key.charCodeAt(index)
const code = (this.code = key.charCodeAt(index));
// check code is ascii string
if (code > 0x7F) {
throw new TypeError('key must be ascii string')
if (code > 0x7f) {
throw new TypeError('key must be ascii string');
}
if (key.length !== ++index) {
this.middle = new TstNode(key, value, index)
this.middle = new TstNode(key, value, index);
} else {
this.value = value
this.value = value;
}
}
@ -42,44 +42,44 @@ class TstNode {
* @param {any} value
* @returns {void}
*/
add (key, value) {
const length = key.length
add(key, value) {
const length = key.length;
if (length === 0) {
throw new TypeError('Unreachable')
throw new TypeError('Unreachable');
}
let index = 0
let index = 0;
/**
* @type {TstNode}
*/
let node = this
let node = this;
while (true) {
const code = key.charCodeAt(index)
const code = key.charCodeAt(index);
// check code is ascii string
if (code > 0x7F) {
throw new TypeError('key must be ascii string')
if (code > 0x7f) {
throw new TypeError('key must be ascii string');
}
if (node.code === code) {
if (length === ++index) {
node.value = value
break
node.value = value;
break;
} else if (node.middle !== null) {
node = node.middle
node = node.middle;
} else {
node.middle = new TstNode(key, value, index)
break
node.middle = new TstNode(key, value, index);
break;
}
} else if (node.code < code) {
if (node.left !== null) {
node = node.left
node = node.left;
} else {
node.left = new TstNode(key, value, index)
break
node.left = new TstNode(key, value, index);
break;
}
} else if (node.right !== null) {
node = node.right
node = node.right;
} else {
node.right = new TstNode(key, value, index)
break
node.right = new TstNode(key, value, index);
break;
}
}
}
@ -88,53 +88,53 @@ class TstNode {
* @param {Uint8Array} key
* @return {TstNode | null}
*/
search (key) {
const keylength = key.length
let index = 0
search(key) {
const keylength = key.length;
let index = 0;
/**
* @type {TstNode|null}
*/
let node = this
let node = this;
while (node !== null && index < keylength) {
let code = key[index]
let code = key[index];
// A-Z
// First check if it is bigger than 0x5a.
// Lowercase letters have higher char codes than uppercase ones.
// Also we assume that headers will mostly contain lowercase characters.
if (code <= 0x5a && code >= 0x41) {
// Lowercase for uppercase.
code |= 32
code |= 32;
}
while (node !== null) {
if (code === node.code) {
if (keylength === ++index) {
// Returns Node since it is the last key.
return node
return node;
}
node = node.middle
break
node = node.middle;
break;
}
node = node.code < code ? node.left : node.right
node = node.code < code ? node.left : node.right;
}
}
return null
return null;
}
}
class TernarySearchTree {
/** @type {TstNode | null} */
node = null
node = null;
/**
* @param {string} key
* @param {any} value
* @returns {void}
* */
insert (key, value) {
insert(key, value) {
if (this.node === null) {
this.node = new TstNode(key, value, 0)
this.node = new TstNode(key, value, 0);
} else {
this.node.add(key, value)
this.node.add(key, value);
}
}
@ -142,19 +142,19 @@ class TernarySearchTree {
* @param {Uint8Array} key
* @returns {any}
*/
lookup (key) {
return this.node?.search(key)?.value ?? null
lookup(key) {
return this.node?.search(key)?.value ?? null;
}
}
const tree = new TernarySearchTree()
const tree = new TernarySearchTree();
for (let i = 0; i < wellknownHeaderNames.length; ++i) {
const key = headerNameLowerCasedRecord[wellknownHeaderNames[i]]
tree.insert(key, key)
const key = headerNameLowerCasedRecord[wellknownHeaderNames[i]];
tree.insert(key, key);
}
module.exports = {
TernarySearchTree,
tree
}
tree,
};

608
node_modules/undici/lib/core/util.js generated vendored

File diff suppressed because it is too large Load Diff