Comparing version 6.6.2 to 6.7.0
'use strict' | ||
const fetchImpl = require('./lib/fetch').fetch | ||
const fetchImpl = require('./lib/web/fetch').fetch | ||
module.exports.fetch = function fetch (resource, init = undefined) { | ||
return fetchImpl(resource, init).catch((err) => { | ||
if (typeof err === 'object') { | ||
if (err && typeof err === 'object') { | ||
Error.captureStackTrace(err, this) | ||
@@ -13,9 +13,10 @@ } | ||
} | ||
module.exports.FormData = require('./lib/fetch/formdata').FormData | ||
module.exports.Headers = require('./lib/fetch/headers').Headers | ||
module.exports.Response = require('./lib/fetch/response').Response | ||
module.exports.Request = require('./lib/fetch/request').Request | ||
module.exports.FormData = require('./lib/web/fetch/formdata').FormData | ||
module.exports.Headers = require('./lib/web/fetch/headers').Headers | ||
module.exports.Response = require('./lib/web/fetch/response').Response | ||
module.exports.Request = require('./lib/web/fetch/request').Request | ||
module.exports.WebSocket = require('./lib/websocket/websocket').WebSocket | ||
module.exports.WebSocket = require('./lib/web/websocket/websocket').WebSocket | ||
module.exports.MessageEvent = require('./lib/web/websocket/events').MessageEvent | ||
module.exports.EventSource = require('./lib/eventsource/eventsource').EventSource | ||
module.exports.EventSource = require('./lib/web/eventsource/eventsource').EventSource |
56
index.js
'use strict' | ||
const Client = require('./lib/client') | ||
const Dispatcher = require('./lib/dispatcher') | ||
const Client = require('./lib/dispatcher/client') | ||
const Dispatcher = require('./lib/dispatcher/dispatcher') | ||
const Pool = require('./lib/dispatcher/pool') | ||
const BalancedPool = require('./lib/dispatcher/balanced-pool') | ||
const Agent = require('./lib/dispatcher/agent') | ||
const ProxyAgent = require('./lib/dispatcher/proxy-agent') | ||
const RetryAgent = require('./lib/dispatcher/retry-agent') | ||
const errors = require('./lib/core/errors') | ||
const Pool = require('./lib/pool') | ||
const BalancedPool = require('./lib/balanced-pool') | ||
const Agent = require('./lib/agent') | ||
const util = require('./lib/core/util') | ||
@@ -17,8 +19,7 @@ const { InvalidArgumentError } = errors | ||
const mockErrors = require('./lib/mock/mock-errors') | ||
const ProxyAgent = require('./lib/proxy-agent') | ||
const RetryHandler = require('./lib/handler/RetryHandler') | ||
const RetryHandler = require('./lib/handler/retry-handler') | ||
const { getGlobalDispatcher, setGlobalDispatcher } = require('./lib/global') | ||
const DecoratorHandler = require('./lib/handler/DecoratorHandler') | ||
const RedirectHandler = require('./lib/handler/RedirectHandler') | ||
const createRedirectInterceptor = require('./lib/interceptor/redirectInterceptor') | ||
const DecoratorHandler = require('./lib/handler/decorator-handler') | ||
const RedirectHandler = require('./lib/handler/redirect-handler') | ||
const createRedirectInterceptor = require('./lib/interceptor/redirect-interceptor') | ||
@@ -33,2 +34,3 @@ Object.assign(Dispatcher.prototype, api) | ||
module.exports.ProxyAgent = ProxyAgent | ||
module.exports.RetryAgent = RetryAgent | ||
module.exports.RetryHandler = RetryHandler | ||
@@ -99,3 +101,3 @@ | ||
const fetchImpl = require('./lib/fetch').fetch | ||
const fetchImpl = require('./lib/web/fetch').fetch | ||
module.exports.fetch = async function fetch (init, options = undefined) { | ||
@@ -105,3 +107,3 @@ try { | ||
} catch (err) { | ||
if (typeof err === 'object') { | ||
if (err && typeof err === 'object') { | ||
Error.captureStackTrace(err, this) | ||
@@ -113,10 +115,10 @@ } | ||
} | ||
module.exports.Headers = require('./lib/fetch/headers').Headers | ||
module.exports.Response = require('./lib/fetch/response').Response | ||
module.exports.Request = require('./lib/fetch/request').Request | ||
module.exports.FormData = require('./lib/fetch/formdata').FormData | ||
module.exports.File = require('./lib/fetch/file').File | ||
module.exports.FileReader = require('./lib/fileapi/filereader').FileReader | ||
module.exports.Headers = require('./lib/web/fetch/headers').Headers | ||
module.exports.Response = require('./lib/web/fetch/response').Response | ||
module.exports.Request = require('./lib/web/fetch/request').Request | ||
module.exports.FormData = require('./lib/web/fetch/formdata').FormData | ||
module.exports.File = require('./lib/web/fetch/file').File | ||
module.exports.FileReader = require('./lib/web/fileapi/filereader').FileReader | ||
const { setGlobalOrigin, getGlobalOrigin } = require('./lib/fetch/global') | ||
const { setGlobalOrigin, getGlobalOrigin } = require('./lib/web/fetch/global') | ||
@@ -126,4 +128,4 @@ module.exports.setGlobalOrigin = setGlobalOrigin | ||
const { CacheStorage } = require('./lib/cache/cachestorage') | ||
const { kConstruct } = require('./lib/cache/symbols') | ||
const { CacheStorage } = require('./lib/web/cache/cachestorage') | ||
const { kConstruct } = require('./lib/web/cache/symbols') | ||
@@ -134,3 +136,3 @@ // Cache & CacheStorage are tightly coupled with fetch. Even if it may run | ||
const { deleteCookie, getCookies, getSetCookies, setCookie } = require('./lib/cookies') | ||
const { deleteCookie, getCookies, getSetCookies, setCookie } = require('./lib/web/cookies') | ||
@@ -142,3 +144,3 @@ module.exports.deleteCookie = deleteCookie | ||
const { parseMIMEType, serializeAMimeType } = require('./lib/fetch/dataURL') | ||
const { parseMIMEType, serializeAMimeType } = require('./lib/web/fetch/data-url') | ||
@@ -148,3 +150,7 @@ module.exports.parseMIMEType = parseMIMEType | ||
module.exports.WebSocket = require('./lib/websocket/websocket').WebSocket | ||
const { CloseEvent, ErrorEvent, MessageEvent } = require('./lib/web/websocket/events') | ||
module.exports.WebSocket = require('./lib/web/websocket/websocket').WebSocket | ||
module.exports.CloseEvent = CloseEvent | ||
module.exports.ErrorEvent = ErrorEvent | ||
module.exports.MessageEvent = MessageEvent | ||
@@ -162,4 +168,4 @@ module.exports.request = makeDispatcher(api.request) | ||
const { EventSource } = require('./lib/eventsource/eventsource') | ||
const { EventSource } = require('./lib/web/eventsource/eventsource') | ||
module.exports.EventSource = EventSource |
@@ -8,18 +8,18 @@ 'use strict' | ||
const assert = require('node:assert') | ||
const { kHTTP2BuildRequest, kHTTP2CopyHeaders, kHTTP1BuildRequest } = require('./symbols') | ||
const util = require('./util') | ||
const { | ||
isValidHTTPToken, | ||
isValidHeaderChar, | ||
isStream, | ||
destroy, | ||
isBuffer, | ||
isFormDataLike, | ||
isIterable, | ||
isBlobLike, | ||
buildURL, | ||
validateHandler, | ||
getServerName | ||
} = require('./util') | ||
const { channels } = require('./diagnostics.js') | ||
const { headerNameLowerCasedRecord } = require('./constants') | ||
// headerCharRegex have been lifted from | ||
// https://github.com/nodejs/node/blob/main/lib/_http_common.js | ||
/** | ||
* Matches if val contains an invalid field-vchar | ||
* field-value = *( field-content / obs-fold ) | ||
* field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ] | ||
* field-vchar = VCHAR / obs-text | ||
*/ | ||
const headerCharRegex = /[^\t\x20-\x7e\x80-\xff]/ | ||
// Verifies that a given path is valid does not contain control chars \x00 to \x20 | ||
@@ -30,4 +30,2 @@ const invalidPathRegex = /[^\u0021-\u00ff]/ | ||
let extractBody | ||
class Request { | ||
@@ -63,3 +61,3 @@ constructor (origin, { | ||
throw new InvalidArgumentError('method must be a string') | ||
} else if (!util.isValidHTTPToken(method)) { | ||
} else if (!isValidHTTPToken(method)) { | ||
throw new InvalidArgumentError('invalid request method') | ||
@@ -100,3 +98,3 @@ } | ||
this.body = null | ||
} else if (util.isStream(body)) { | ||
} else if (isStream(body)) { | ||
this.body = body | ||
@@ -107,3 +105,3 @@ | ||
this.endHandler = function autoDestroy () { | ||
util.destroy(this) | ||
destroy(this) | ||
} | ||
@@ -121,3 +119,3 @@ this.body.on('end', this.endHandler) | ||
this.body.on('error', this.errorHandler) | ||
} else if (util.isBuffer(body)) { | ||
} else if (isBuffer(body)) { | ||
this.body = body.byteLength ? body : null | ||
@@ -130,3 +128,3 @@ } else if (ArrayBuffer.isView(body)) { | ||
this.body = body.length ? Buffer.from(body) : null | ||
} else if (util.isFormDataLike(body) || util.isIterable(body) || util.isBlobLike(body)) { | ||
} else if (isFormDataLike(body) || isIterable(body) || isBlobLike(body)) { | ||
this.body = body | ||
@@ -143,3 +141,3 @@ } else { | ||
this.path = query ? util.buildURL(path, query) : path | ||
this.path = query ? buildURL(path, query) : path | ||
@@ -162,3 +160,3 @@ this.origin = origin | ||
this.headers = '' | ||
this.headers = [] | ||
@@ -176,6 +174,14 @@ // Only for H2 | ||
} else if (headers && typeof headers === 'object') { | ||
const keys = Object.keys(headers) | ||
for (let i = 0; i < keys.length; i++) { | ||
const key = keys[i] | ||
processHeader(this, key, headers[key]) | ||
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') | ||
} | ||
processHeader(this, header[0], header[1]) | ||
} | ||
} else { | ||
const keys = Object.keys(headers) | ||
for (let i = 0; i < keys.length; ++i) { | ||
processHeader(this, keys[i], headers[keys[i]]) | ||
} | ||
} | ||
@@ -186,23 +192,6 @@ } else if (headers != null) { | ||
if (util.isFormDataLike(this.body)) { | ||
if (!extractBody) { | ||
extractBody = require('../fetch/body.js').extractBody | ||
} | ||
validateHandler(handler, method, upgrade) | ||
const [bodyStream, contentType] = extractBody(body) | ||
if (this.contentType == null) { | ||
this.contentType = contentType | ||
this.headers += `content-type: ${contentType}\r\n` | ||
} | ||
this.body = bodyStream.stream | ||
this.contentLength = bodyStream.length | ||
} else if (util.isBlobLike(body) && this.contentType == null && body.type) { | ||
this.contentType = body.type | ||
this.headers += `content-type: ${body.type}\r\n` | ||
} | ||
this.servername = getServerName(this.host) | ||
util.validateHandler(handler, method, upgrade) | ||
this.servername = util.getServerName(this.host) | ||
this[kHandler] = handler | ||
@@ -334,3 +323,2 @@ | ||
// TODO: adjust to support H2 | ||
addHeader (key, value) { | ||
@@ -340,72 +328,5 @@ processHeader(this, key, value) | ||
} | ||
static [kHTTP1BuildRequest] (origin, opts, handler) { | ||
// TODO: Migrate header parsing here, to make Requests | ||
// HTTP agnostic | ||
return new Request(origin, opts, handler) | ||
} | ||
static [kHTTP2BuildRequest] (origin, opts, handler) { | ||
const headers = opts.headers | ||
opts = { ...opts, headers: null } | ||
const request = new Request(origin, opts, handler) | ||
request.headers = {} | ||
if (Array.isArray(headers)) { | ||
if (headers.length % 2 !== 0) { | ||
throw new InvalidArgumentError('headers array must be even') | ||
} | ||
for (let i = 0; i < headers.length; i += 2) { | ||
processHeader(request, headers[i], headers[i + 1], true) | ||
} | ||
} else if (headers && typeof headers === 'object') { | ||
const keys = Object.keys(headers) | ||
for (let i = 0; i < keys.length; i++) { | ||
const key = keys[i] | ||
processHeader(request, key, headers[key], true) | ||
} | ||
} else if (headers != null) { | ||
throw new InvalidArgumentError('headers must be an object or an array') | ||
} | ||
return request | ||
} | ||
static [kHTTP2CopyHeaders] (raw) { | ||
const rawHeaders = raw.split('\r\n') | ||
const headers = {} | ||
for (const header of rawHeaders) { | ||
const [key, value] = header.split(': ') | ||
if (value == null || value.length === 0) continue | ||
if (headers[key]) { | ||
headers[key] += `,${value}` | ||
} else { | ||
headers[key] = value | ||
} | ||
} | ||
return headers | ||
} | ||
} | ||
function processHeaderValue (key, val, skipAppend) { | ||
if (val && typeof val === 'object') { | ||
throw new InvalidArgumentError(`invalid ${key} header`) | ||
} | ||
val = val != null ? `${val}` : '' | ||
if (headerCharRegex.exec(val) !== null) { | ||
throw new InvalidArgumentError(`invalid ${key} header`) | ||
} | ||
return skipAppend ? val : `${key}: ${val}\r\n` | ||
} | ||
function processHeader (request, key, val, skipAppend = false) { | ||
function processHeader (request, key, val) { | ||
if (val && (typeof val === 'object' && !Array.isArray(val))) { | ||
@@ -421,3 +342,3 @@ throw new InvalidArgumentError(`invalid ${key} header`) | ||
headerName = key.toLowerCase() | ||
if (headerNameLowerCasedRecord[headerName] === undefined && !util.isValidHTTPToken(headerName)) { | ||
if (headerNameLowerCasedRecord[headerName] === undefined && !isValidHTTPToken(headerName)) { | ||
throw new InvalidArgumentError('invalid header key') | ||
@@ -427,6 +348,35 @@ } | ||
if (request.host === null && headerName === 'host') { | ||
if (headerCharRegex.exec(val) !== null) { | ||
if (Array.isArray(val)) { | ||
const arr = [] | ||
for (let i = 0; i < val.length; i++) { | ||
if (typeof val[i] === 'string') { | ||
if (!isValidHeaderChar(val[i])) { | ||
throw new InvalidArgumentError(`invalid ${key} header`) | ||
} | ||
arr.push(val[i]) | ||
} else if (val[i] === null) { | ||
arr.push('') | ||
} else if (typeof val[i] === 'object') { | ||
throw new InvalidArgumentError(`invalid ${key} header`) | ||
} else { | ||
arr.push(`${val[i]}`) | ||
} | ||
} | ||
val = arr | ||
} else if (typeof val === 'string') { | ||
if (!isValidHeaderChar(val)) { | ||
throw new InvalidArgumentError(`invalid ${key} header`) | ||
} | ||
} else if (val === null) { | ||
val = '' | ||
} else if (typeof val === 'object') { | ||
throw new InvalidArgumentError(`invalid ${key} header`) | ||
} else { | ||
val = `${val}` | ||
} | ||
if (request.host === null && headerName === 'host') { | ||
if (typeof val !== 'string') { | ||
throw new InvalidArgumentError('invalid host header') | ||
} | ||
// Consumed by Client | ||
@@ -441,4 +391,3 @@ request.host = val | ||
request.contentType = val | ||
if (skipAppend) request.headers[key] = processHeaderValue(key, val, skipAppend) | ||
else request.headers += processHeaderValue(key, val) | ||
request.headers.push(key, val) | ||
} else if (headerName === 'transfer-encoding' || headerName === 'keep-alive' || headerName === 'upgrade') { | ||
@@ -450,3 +399,5 @@ throw new InvalidArgumentError(`invalid ${headerName} header`) | ||
throw new InvalidArgumentError('invalid connection header') | ||
} else if (value === 'close') { | ||
} | ||
if (value === 'close') { | ||
request.reset = true | ||
@@ -456,18 +407,4 @@ } | ||
throw new NotSupportedError('expect header not supported') | ||
} else if (Array.isArray(val)) { | ||
for (let i = 0; i < val.length; i++) { | ||
if (skipAppend) { | ||
if (request.headers[key]) { | ||
request.headers[key] += `,${processHeaderValue(key, val[i], skipAppend)}` | ||
} else { | ||
request.headers[key] = processHeaderValue(key, val[i], skipAppend) | ||
} | ||
} else { | ||
request.headers += processHeaderValue(key, val[i]) | ||
} | ||
} | ||
} else if (skipAppend) { | ||
request.headers[key] = processHeaderValue(key, val, skipAppend) | ||
} else { | ||
request.headers += processHeaderValue(key, val) | ||
request.headers.push(key, val) | ||
} | ||
@@ -474,0 +411,0 @@ } |
@@ -36,2 +36,4 @@ module.exports = { | ||
kDestroyed: Symbol.for('nodejs.stream.destroyed'), | ||
kResume: Symbol('resume'), | ||
kOnError: Symbol('on error'), | ||
kMaxHeadersSize: Symbol('max headers size'), | ||
@@ -58,8 +60,7 @@ kRunningIdx: Symbol('running index'), | ||
kHTTP2SessionState: Symbol('http2Session state'), | ||
kHTTP2BuildRequest: Symbol('http2 build request'), | ||
kHTTP1BuildRequest: Symbol('http1 build request'), | ||
kHTTP2CopyHeaders: Symbol('http2 copy headers'), | ||
kHTTPConnVersion: Symbol('http connection version'), | ||
kRetryHandlerDefaultRetry: Symbol('retry agent default retry'), | ||
kConstruct: Symbol('constructable') | ||
kConstruct: Symbol('constructable'), | ||
kListeners: Symbol('listeners'), | ||
kHTTPContext: Symbol('http context'), | ||
kMaxConcurrentStreams: Symbol('max concurrent streams') | ||
} |
@@ -20,3 +20,3 @@ 'use strict' | ||
/** | ||
* @param {Uint8Array} key | ||
* @param {string} key | ||
* @param {any} value | ||
@@ -29,3 +29,7 @@ * @param {number} index | ||
} | ||
this.code = key[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 (key.length !== ++index) { | ||
@@ -39,29 +43,41 @@ this.middle = new TstNode(key, value, index) | ||
/** | ||
* @param {Uint8Array} key | ||
* @param {string} key | ||
* @param {any} value | ||
* @param {number} index | ||
*/ | ||
add (key, value, index) { | ||
if (index === undefined || index >= key.length) { | ||
add (key, value) { | ||
const length = key.length | ||
if (length === 0) { | ||
throw new TypeError('Unreachable') | ||
} | ||
const code = key[index] | ||
if (this.code === code) { | ||
if (key.length === ++index) { | ||
this.value = value | ||
} else if (this.middle !== null) { | ||
this.middle.add(key, value, index) | ||
} else { | ||
this.middle = new TstNode(key, value, index) | ||
let index = 0 | ||
let node = this | ||
while (true) { | ||
const code = key.charCodeAt(index) | ||
// check code is ascii string | ||
if (code > 0x7F) { | ||
throw new TypeError('key must be ascii string') | ||
} | ||
} else if (this.code < code) { | ||
if (this.left !== null) { | ||
this.left.add(key, value, index) | ||
if (node.code === code) { | ||
if (length === ++index) { | ||
node.value = value | ||
break | ||
} else if (node.middle !== null) { | ||
node = node.middle | ||
} else { | ||
node.middle = new TstNode(key, value, index) | ||
break | ||
} | ||
} else if (node.code < code) { | ||
if (node.left !== null) { | ||
node = node.left | ||
} else { | ||
node.left = new TstNode(key, value, index) | ||
break | ||
} | ||
} else if (node.right !== null) { | ||
node = node.right | ||
} else { | ||
this.left = new TstNode(key, value, index) | ||
node.right = new TstNode(key, value, index) | ||
break | ||
} | ||
} else if (this.right !== null) { | ||
this.right.add(key, value, index) | ||
} else { | ||
this.right = new TstNode(key, value, index) | ||
} | ||
@@ -81,3 +97,6 @@ } | ||
// A-Z | ||
if (code >= 0x41 && code <= 0x5a) { | ||
// 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. | ||
@@ -107,3 +126,3 @@ code |= 32 | ||
/** | ||
* @param {Uint8Array} key | ||
* @param {string} key | ||
* @param {any} value | ||
@@ -115,3 +134,3 @@ * */ | ||
} else { | ||
this.node.add(key, value, 0) | ||
this.node.add(key, value) | ||
} | ||
@@ -122,2 +141,3 @@ } | ||
* @param {Uint8Array} key | ||
* @return {any} | ||
*/ | ||
@@ -133,3 +153,3 @@ lookup (key) { | ||
const key = headerNameLowerCasedRecord[wellknownHeaderNames[i]] | ||
tree.insert(Buffer.from(key), key) | ||
tree.insert(key, key) | ||
} | ||
@@ -136,0 +156,0 @@ |
@@ -185,4 +185,4 @@ 'use strict' | ||
function isDestroyed (stream) { | ||
return !stream || !!(stream.destroyed || stream[kDestroyed]) | ||
function isDestroyed (body) { | ||
return body && !!(body.destroyed || body[kDestroyed] || (stream.isDestroyed?.(body))) | ||
} | ||
@@ -208,5 +208,5 @@ | ||
} else if (err) { | ||
process.nextTick((stream, err) => { | ||
queueMicrotask(() => { | ||
stream.emit('error', err) | ||
}, stream, err) | ||
}) | ||
} | ||
@@ -284,18 +284,26 @@ | ||
function parseRawHeaders (headers) { | ||
const ret = [] | ||
const len = headers.length | ||
const ret = new Array(len) | ||
let hasContentLength = false | ||
let contentDispositionIdx = -1 | ||
let key | ||
let val | ||
let kLen = 0 | ||
for (let n = 0; n < headers.length; n += 2) { | ||
const key = headers[n + 0].toString() | ||
const val = headers[n + 1].toString('utf8') | ||
key = headers[n] | ||
val = headers[n + 1] | ||
if (key.length === 14 && (key === 'content-length' || key.toLowerCase() === 'content-length')) { | ||
ret.push(key, val) | ||
typeof key !== 'string' && (key = key.toString()) | ||
typeof val !== 'string' && (val = val.toString('utf8')) | ||
kLen = key.length | ||
if (kLen === 14 && key[7] === '-' && (key === 'content-length' || key.toLowerCase() === 'content-length')) { | ||
hasContentLength = true | ||
} else if (key.length === 19 && (key === 'content-disposition' || key.toLowerCase() === 'content-disposition')) { | ||
contentDispositionIdx = ret.push(key, val) - 1 | ||
} else { | ||
ret.push(key, val) | ||
} else if (kLen === 19 && key[7] === '-' && (key === 'content-disposition' || key.toLowerCase() === 'content-disposition')) { | ||
contentDispositionIdx = n + 1 | ||
} | ||
ret[n] = key | ||
ret[n + 1] = val | ||
} | ||
@@ -444,9 +452,3 @@ | ||
function toUSVString (val) { | ||
if (hasToWellFormed) { | ||
return `${val}`.toWellFormed() | ||
} else if (nodeUtil.toUSVString) { | ||
return nodeUtil.toUSVString(val) | ||
} | ||
return `${val}` | ||
return hasToWellFormed ? `${val}`.toWellFormed() : nodeUtil.toUSVString(val) | ||
} | ||
@@ -500,2 +502,20 @@ | ||
// headerCharRegex have been lifted from | ||
// https://github.com/nodejs/node/blob/main/lib/_http_common.js | ||
/** | ||
* Matches if val contains an invalid field-vchar | ||
* field-value = *( field-content / obs-fold ) | ||
* field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ] | ||
* field-vchar = VCHAR / obs-text | ||
*/ | ||
const headerCharRegex = /[^\t\x20-\x7e\x80-\xff]/ | ||
/** | ||
* @param {string} characters | ||
*/ | ||
function isValidHeaderChar (characters) { | ||
return !headerCharRegex.test(characters) | ||
} | ||
// Parsed accordingly to RFC 9110 | ||
@@ -551,2 +571,3 @@ // https://www.rfc-editor.org/rfc/rfc9110#field.content-range | ||
isValidHTTPToken, | ||
isValidHeaderChar, | ||
isTokenCharCode, | ||
@@ -553,0 +574,0 @@ parseRangeHeader, |
@@ -7,3 +7,3 @@ 'use strict' | ||
const { InvalidArgumentError } = require('./core/errors') | ||
const Agent = require('./agent') | ||
const Agent = require('./dispatcher/agent') | ||
@@ -10,0 +10,0 @@ if (getGlobalDispatcher() === undefined) { |
'use strict' | ||
const { kClients } = require('../core/symbols') | ||
const Agent = require('../agent') | ||
const Agent = require('../dispatcher/agent') | ||
const { | ||
@@ -20,3 +20,3 @@ kAgent, | ||
const { InvalidArgumentError, UndiciError } = require('../core/errors') | ||
const Dispatcher = require('../dispatcher') | ||
const Dispatcher = require('../dispatcher/dispatcher') | ||
const Pluralizer = require('./pluralizer') | ||
@@ -23,0 +23,0 @@ const PendingInterceptorsFormatter = require('./pending-interceptors-formatter') |
'use strict' | ||
const { promisify } = require('node:util') | ||
const Client = require('../client') | ||
const Client = require('../dispatcher/client') | ||
const { buildMockDispatch } = require('./mock-utils') | ||
@@ -6,0 +6,0 @@ const { |
@@ -77,3 +77,3 @@ 'use strict' | ||
} else { | ||
// Matches https://github.com/nodejs/undici/blob/main/lib/fetch/index.js#L1811 | ||
// Matches https://github.com/nodejs/undici/blob/main/lib/web/fetch/index.js#L1811 | ||
const parsedURL = new URL(opts.path, 'data://') | ||
@@ -110,3 +110,3 @@ opts.path = parsedURL.pathname + parsedURL.search | ||
} | ||
if (typeof responseOptions !== 'object') { | ||
if (typeof responseOptions !== 'object' || responseOptions === null) { | ||
throw new InvalidArgumentError('responseOptions must be an object') | ||
@@ -113,0 +113,0 @@ } |
'use strict' | ||
const { promisify } = require('node:util') | ||
const Pool = require('../pool') | ||
const Pool = require('../dispatcher/pool') | ||
const { buildMockDispatch } = require('./mock-utils') | ||
@@ -6,0 +6,0 @@ const { |
@@ -141,3 +141,3 @@ 'use strict' | ||
if (matchedMockDispatches.length === 0) { | ||
throw new MockNotMatchedError(`Mock dispatch not matched for method '${key.method}'`) | ||
throw new MockNotMatchedError(`Mock dispatch not matched for method '${key.method}' on path '${resolvedPath}'`) | ||
} | ||
@@ -148,3 +148,3 @@ | ||
if (matchedMockDispatches.length === 0) { | ||
throw new MockNotMatchedError(`Mock dispatch not matched for body '${key.body}'`) | ||
throw new MockNotMatchedError(`Mock dispatch not matched for body '${key.body}' on path '${resolvedPath}'`) | ||
} | ||
@@ -155,3 +155,4 @@ | ||
if (matchedMockDispatches.length === 0) { | ||
throw new MockNotMatchedError(`Mock dispatch not matched for headers '${typeof key.headers === 'object' ? JSON.stringify(key.headers) : key.headers}'`) | ||
const headers = typeof key.headers === 'object' ? JSON.stringify(key.headers) : key.headers | ||
throw new MockNotMatchedError(`Mock dispatch not matched for headers '${headers}' on path '${resolvedPath}'`) | ||
} | ||
@@ -363,3 +364,4 @@ | ||
buildMockOptions, | ||
getHeaderByName | ||
getHeaderByName, | ||
buildHeadersFromArray | ||
} |
{ | ||
"name": "undici", | ||
"version": "6.6.2", | ||
"version": "6.7.0", | ||
"description": "An HTTP/1.1 client, written from scratch for Node.js", | ||
@@ -64,13 +64,4 @@ "homepage": "https://undici.nodejs.org", | ||
"types": "index.d.ts", | ||
"files": [ | ||
"*.d.ts", | ||
"index.js", | ||
"index-fetch.js", | ||
"loader.js", | ||
"lib", | ||
"types", | ||
"docs" | ||
], | ||
"scripts": { | ||
"build:node": "npx esbuild@0.19.4 index-fetch.js --bundle --platform=node --outfile=undici-fetch.js --define:esbuildDetection=1 --keep-names", | ||
"build:node": "npx esbuild@0.19.4 index-fetch.js --bundle --platform=node --outfile=undici-fetch.js --define:esbuildDetection=1 --keep-names && node scripts/strip-comments.js", | ||
"prebuild:wasm": "node build/wasm.js --prebuild", | ||
@@ -80,23 +71,24 @@ "build:wasm": "node build/wasm.js --docker", | ||
"lint:fix": "standard --fix | snazzy", | ||
"test": "node scripts/generate-pem && npm run test:tap && npm run test:node-fetch && npm run test:fetch && npm run test:cookies && npm run test:eventsource && npm run test:wpt && npm run test:websocket && npm run test:jest && npm run test:typescript && npm run test:node-test", | ||
"test:cookies": "borp --coverage -p \"test/cookie/*.js\"", | ||
"test:node-fetch": "mocha --exit test/node-fetch", | ||
"test:eventsource": "npm run build:node && borp --expose-gc --coverage -p \"test/eventsource/*.js\"", | ||
"test:fetch": "npm run build:node && borp --expose-gc --coverage -p \"test/fetch/*.js\" && borp --coverage -p \"test/webidl/*.js\"", | ||
"test:jest": "jest", | ||
"test:tap": "tap test/*.js", | ||
"test:node-test": "borp --coverage -p \"test/node-test/**/*.js\"", | ||
"test:tdd": "tap test/*.js --coverage -w", | ||
"test": "npm run test:javascript && cross-env NODE_V8_COVERAGE= npm run test:typescript", | ||
"test:javascript": "node scripts/generate-pem && npm run test:unit && npm run test:node-fetch && npm run test:fetch && npm run test:cookies && npm run test:eventsource && npm run test:wpt && npm run test:websocket && npm run test:node-test && npm run test:jest", | ||
"test:cookies": "borp -p \"test/cookie/*.js\"", | ||
"test:node-fetch": "borp -p \"test/node-fetch/**/*.js\"", | ||
"test:eventsource": "npm run build:node && borp --expose-gc -p \"test/eventsource/*.js\"", | ||
"test:fetch": "npm run build:node && borp --expose-gc -p \"test/fetch/*.js\" && borp -p \"test/webidl/*.js\"", | ||
"test:jest": "cross-env NODE_V8_COVERAGE= jest", | ||
"test:unit": "borp --expose-gc -p \"test/*.js\"", | ||
"test:node-test": "borp -p \"test/node-test/**/*.js\"", | ||
"test:tdd": "borp --expose-gc -p \"test/*.js\"", | ||
"test:tdd:node-test": "borp -p \"test/node-test/**/*.js\" -w", | ||
"test:typescript": "tsd && tsc --skipLibCheck test/imports/undici-import.ts", | ||
"test:websocket": "borp --coverage -p \"test/websocket/*.js\"", | ||
"test:websocket": "borp -p \"test/websocket/*.js\"", | ||
"test:wpt": "node test/wpt/start-fetch.mjs && node test/wpt/start-FileAPI.mjs && node test/wpt/start-mimesniff.mjs && node test/wpt/start-xhr.mjs && node test/wpt/start-websockets.mjs && node test/wpt/start-cacheStorage.mjs && node test/wpt/start-eventsource.mjs", | ||
"coverage": "nyc --reporter=text --reporter=html npm run test", | ||
"coverage:ci": "nyc --reporter=lcov npm run test", | ||
"bench": "PORT=3042 concurrently -k -s first npm:bench:server npm:bench:run", | ||
"bench:server": "node benchmarks/server.js", | ||
"prebench:run": "node benchmarks/wait.js", | ||
"bench:run": "SAMPLES=100 CONNECTIONS=50 node benchmarks/benchmark.js", | ||
"serve:website": "docsify serve .", | ||
"prepare": "husky install", | ||
"coverage": "npm run coverage:clean && cross-env NODE_V8_COVERAGE=./coverage/tmp npm run test:javascript && npm run coverage:report", | ||
"coverage:ci": "npm run coverage:clean && cross-env NODE_V8_COVERAGE=./coverage/tmp npm run test:javascript && npm run coverage:report:ci", | ||
"coverage:clean": "node ./scripts/clean-coverage.js", | ||
"coverage:report": "cross-env NODE_V8_COVERAGE= c8 report", | ||
"coverage:report:ci": "c8 report", | ||
"bench": "echo \"Error: Benchmarks have been moved to '\/benchmarks'\" && exit 1", | ||
"serve:website": "echo \"Error: Documentation has been moved to '\/docs'\" && exit 1", | ||
"prepare": "husky install && node ./scripts/platform-shell.js", | ||
"fuzz": "jsfuzz test/fuzzing/fuzz.js corpus" | ||
@@ -110,10 +102,5 @@ }, | ||
"borp": "^0.9.1", | ||
"chai": "^4.3.4", | ||
"chai-as-promised": "^7.1.1", | ||
"chai-iterator": "^3.0.2", | ||
"chai-string": "^1.5.0", | ||
"concurrently": "^8.0.1", | ||
"cronometro": "^2.0.2", | ||
"c8": "^9.1.0", | ||
"cross-env": "^7.0.3", | ||
"dns-packet": "^5.4.0", | ||
"docsify-cli": "^4.4.3", | ||
"form-data": "^4.0.0", | ||
@@ -123,24 +110,12 @@ "formdata-node": "^6.0.3", | ||
"husky": "^9.0.7", | ||
"import-fresh": "^3.3.0", | ||
"jest": "^29.0.2", | ||
"jsdom": "^24.0.0", | ||
"jsfuzz": "^1.0.15", | ||
"mitata": "^0.1.8", | ||
"mocha": "^10.0.0", | ||
"p-timeout": "^3.2.0", | ||
"pre-commit": "^1.2.2", | ||
"proxy": "^1.0.2", | ||
"proxyquire": "^2.1.3", | ||
"sinon": "^17.0.1", | ||
"proxy": "^2.1.1", | ||
"snazzy": "^9.0.0", | ||
"standard": "^17.0.0", | ||
"tap": "^16.1.0", | ||
"tsd": "^0.30.1", | ||
"typescript": "^5.0.2", | ||
"wait-on": "^7.0.1", | ||
"ws": "^8.11.0", | ||
"axios": "^1.6.5", | ||
"got": "^14.0.0", | ||
"node-fetch": "^3.3.2", | ||
"request": "^2.88.2" | ||
"ws": "^8.11.0" | ||
}, | ||
@@ -152,3 +127,3 @@ "engines": { | ||
"env": [ | ||
"mocha" | ||
"jest" | ||
], | ||
@@ -155,0 +130,0 @@ "ignore": [ |
@@ -103,3 +103,3 @@ import { URL } from 'url' | ||
/** Default: `null` */ | ||
headers?: IncomingHttpHeaders | string[] | null; | ||
headers?: IncomingHttpHeaders | string[] | Iterable<[string, string | string[] | undefined]> | null; | ||
/** Query string params to be embedded in the request URL. Default: `null` */ | ||
@@ -106,0 +106,0 @@ query?: Record<string, any>; |
@@ -30,3 +30,3 @@ // based on https://github.com/Ethan-Arrowood/undici-fetch/blob/249269714db874351589d2d364a0645d5160ae71/index.d.ts (MIT license) | ||
export interface BodyMixin { | ||
export class BodyMixin { | ||
readonly body: ReadableStream | null | ||
@@ -37,2 +37,19 @@ readonly bodyUsed: boolean | ||
readonly blob: () => Promise<Blob> | ||
/** | ||
* @deprecated This method is not recommended for parsing multipart/form-data bodies in server environments. | ||
* It is recommended to use a library such as [@fastify/busboy](https://www.npmjs.com/package/@fastify/busboy) as follows: | ||
* | ||
* @example | ||
* ```js | ||
* import { Busboy } from '@fastify/busboy' | ||
* import { Readable } from 'node:stream' | ||
* | ||
* const response = await fetch('...') | ||
* const busboy = new Busboy({ headers: { 'content-type': response.headers.get('content-type') } }) | ||
* | ||
* // handle events emitted from `busboy` | ||
* | ||
* Readable.fromWeb(response.body).pipe(busboy) | ||
* ``` | ||
*/ | ||
readonly formData: () => Promise<FormData> | ||
@@ -140,3 +157,3 @@ readonly json: () => Promise<unknown> | ||
export declare class Request implements BodyMixin { | ||
export declare class Request extends BodyMixin { | ||
constructor (input: RequestInfo, init?: RequestInit) | ||
@@ -159,11 +176,2 @@ | ||
readonly body: ReadableStream | null | ||
readonly bodyUsed: boolean | ||
readonly arrayBuffer: () => Promise<ArrayBuffer> | ||
readonly blob: () => Promise<Blob> | ||
readonly formData: () => Promise<FormData> | ||
readonly json: () => Promise<unknown> | ||
readonly text: () => Promise<string> | ||
readonly clone: () => Request | ||
@@ -188,3 +196,3 @@ } | ||
export declare class Response implements BodyMixin { | ||
export declare class Response extends BodyMixin { | ||
constructor (body?: BodyInit, init?: ResponseInit) | ||
@@ -200,11 +208,2 @@ | ||
readonly body: ReadableStream | null | ||
readonly bodyUsed: boolean | ||
readonly arrayBuffer: () => Promise<ArrayBuffer> | ||
readonly blob: () => Promise<Blob> | ||
readonly formData: () => Promise<FormData> | ||
readonly json: () => Promise<unknown> | ||
readonly text: () => Promise<string> | ||
readonly clone: () => Response | ||
@@ -211,0 +210,0 @@ |
@@ -18,2 +18,3 @@ import Dispatcher from'./dispatcher' | ||
import RetryHandler from'./retry-handler' | ||
import RetryAgent from'./retry-agent' | ||
import { request, pipeline, stream, connect, upgrade } from './api' | ||
@@ -34,3 +35,3 @@ | ||
export { Dispatcher, BalancedPool, Pool, Client, buildConnector, errors, Agent, request, stream, pipeline, connect, upgrade, setGlobalDispatcher, getGlobalDispatcher, setGlobalOrigin, getGlobalOrigin, MockClient, MockPool, MockAgent, mockErrors, ProxyAgent, RedirectHandler, DecoratorHandler, RetryHandler } | ||
export { Dispatcher, BalancedPool, Pool, Client, buildConnector, errors, Agent, request, stream, pipeline, connect, upgrade, setGlobalDispatcher, getGlobalDispatcher, setGlobalOrigin, getGlobalOrigin, MockClient, MockPool, MockAgent, mockErrors, ProxyAgent, RedirectHandler, DecoratorHandler, RetryHandler, RetryAgent } | ||
export default Undici | ||
@@ -37,0 +38,0 @@ |
@@ -8,3 +8,3 @@ // These types are not exported, and are only used internally | ||
type SequenceConverter<T> = (object: unknown) => T[] | ||
type SequenceConverter<T> = (object: unknown, iterable?: IterableIterator<T>) => T[] | ||
@@ -66,2 +66,7 @@ type RecordConverter<K extends string, V> = (object: unknown) => Record<K, V> | ||
IntegerPart (N: number): number | ||
/** | ||
* Stringifies {@param V} | ||
*/ | ||
Stringify (V: any): string | ||
} | ||
@@ -68,0 +73,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
22
167
22518
1
433
5
1024443
2