New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

undici

Package Overview
Dependencies
Maintainers
3
Versions
235
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

undici - npm Package Compare versions

Comparing version 4.11.3 to 4.12.0

29

lib/core/util.js

@@ -153,3 +153,3 @@ 'use strict'

function isAborted (stream) {
function isReadableAborted (stream) {
const state = stream && stream._readableState

@@ -248,11 +248,24 @@ return isDestroyed(stream) && state && !state.endEmitted

function isDisturbed (body) {
const state = body && body._readableState
return !!(body && (
(stream.isDisturbed && stream.isDisturbed(body)) ||
body[kBodyUsed] ||
body.readableDidRead || (state && state.dataEmitted) ||
isAborted(body)
stream.isDisturbed
? stream.isDisturbed(body) || body[kBodyUsed] // TODO (fix): Why is body[kBodyUsed] needed?
: body[kBodyUsed] ||
body.readableDidRead ||
(body._readableState && body._readableState.dataEmitted) ||
isReadableAborted(body)
))
}
function isErrored (body) {
return !!(body && (
stream.isErrored
? stream.isErrored(body)
: /state: 'errored'/.test(nodeUtil.inspect(body)
)))
}
function isReadable (body) {
return !!(body && /state: 'readable'/.test(nodeUtil.inspect(body)))
}
function getSocketInfo (socket) {

@@ -315,4 +328,6 @@ return {

isDisturbed,
isErrored,
isReadable,
toUSVString: nodeUtil.toUSVString || ((val) => `${val}`),
isAborted,
isReadableAborted,
isBlobLike,

@@ -319,0 +334,0 @@ parseOrigin,

@@ -6,3 +6,3 @@ 'use strict'

const { FormData } = require('./formdata')
const { kState, kError } = require('./symbols')
const { kState } = require('./symbols')
const { Blob } = require('buffer')

@@ -13,2 +13,3 @@ const { kBodyUsed } = require('../core/symbols')

const { NotSupportedError } = require('../core/errors')
const { isErrored } = require('../core/util')

@@ -192,3 +193,3 @@ let ReadableStream

// bytes into stream.
if (!/state: 'errored'/.test(nodeUtil.inspect(stream))) {
if (!isErrored(stream)) {
controller.enqueue(new Uint8Array(value))

@@ -274,6 +275,2 @@ }

if (stream[kError]) {
throw stream[kError]
}
if (util.isDisturbed(stream)) {

@@ -359,8 +356,2 @@ throw new TypeError('disturbed')

function cancelBody (body, reason) {
if (body.stream && !/state: 'errored'/.test(nodeUtil.inspect(body.stream))) {
body.stream.cancel(reason)
}
}
function mixinBody (prototype) {

@@ -372,3 +363,2 @@ Object.assign(prototype, methods)

module.exports = {
cancelBody,
extractBody,

@@ -375,0 +365,0 @@ safelyExtractBody,

@@ -27,3 +27,3 @@ // https://github.com/Ethan-Arrowood/undici-fetch

tryUpgradeRequestToAPotentiallyTrustworthyURL,
makeTimingInfo,
createOpaqueTimingInfo,
appendFetchMetadata,

@@ -35,6 +35,6 @@ corsCheck,

} = require('./util')
const { kState, kHeaders, kGuard, kRealm, kError } = require('./symbols')
const { kState, kHeaders, kGuard, kRealm } = require('./symbols')
const { AbortError } = require('../core/errors')
const assert = require('assert')
const { safelyExtractBody, cancelBody } = require('./body')
const { safelyExtractBody } = require('./body')
const {

@@ -49,11 +49,29 @@ redirectStatus,

const EE = require('events')
const { PassThrough, pipeline, compose } = require('stream')
const { PassThrough, pipeline } = require('stream')
const { isErrored, isReadable } = require('../core/util')
let ReadableStream
// https://fetch.spec.whatwg.org/#garbage-collection
const registry = new FinalizationRegistry((abort) => {
abort()
})
class Fetch extends EE {
constructor (dispatcher) {
super()
this.dispatcher = dispatcher
this.terminated = null
this.connection = null
this.dump = false
}
terminate ({ reason, aborted } = {}) {
if (this.terminated) {
return
}
this.terminated = { aborted, reason }
this.connection?.destroy(reason)
this.emit('terminated', reason)
}
}
// https://fetch.spec.whatwg.org/#fetch-method

@@ -79,22 +97,4 @@ async function fetch (...args) {

const context = Object.assign(new EE(), {
dispatcher: this,
terminated: false,
connection: null,
dump: false,
terminate ({ reason, aborted } = {}) {
if (this.terminated) {
return
}
this.terminated = { aborted }
const context = new Fetch(this)
if (this.connection) {
this.connection.destroy(reason)
this.connection = null
}
this.emit('terminated', reason)
}
})
// 1. Let p be a new promise.

@@ -160,3 +160,3 @@ const p = createDeferredPromise()

// 12. Fetch request with processResponseDone set to handleFetchDone,
// 12. Fetch request with processResponseEndOfBody set to handleFetchDone,
// and processResponse given response being these substeps:

@@ -201,3 +201,3 @@ const processResponse = (response) => {

request,
processResponseDone: handleFetchDone,
processResponseEndOfBody: handleFetchDone,
processResponse

@@ -235,7 +235,5 @@ })

if (!timingInfo.timingAllowPassed) {
// 1. Set timingInfo to a new fetch timing info whose start time and
// post-redirect start time are timingInfo’s start time.
timingInfo = makeTimingInfo({
startTime: timingInfo.startTime,
postRedirectStartTime: timingInfo.postRedirectStartTime
// 1. Set timingInfo to a the result of creating an opaque timing info for timingInfo.
timingInfo = createOpaqueTimingInfo({
startTime: timingInfo.startTime
})

@@ -283,4 +281,10 @@

// body with error.
if (request.body != null) {
cancelBody(request.body, error)
if (request.body != null && isReadable(request.body?.stream)) {
request.body.stream.cancel(error).catch((err) => {
if (err.code === 'ERR_INVALID_STATE') {
// Node bug?
return
}
throw err
})
}

@@ -298,4 +302,10 @@

// body with error.
if (response.body != null) {
cancelBody(response.body, error)
if (response.body != null && isReadable(response.body?.stream)) {
response.body.stream.cancel(error).catch((err) => {
if (err.code === 'ERR_INVALID_STATE') {
// Node bug?
return
}
throw err
})
}

@@ -305,3 +315,11 @@ }

// https://fetch.spec.whatwg.org/#fetching
function fetching ({ request, processResponse, processResponseDone }) {
function fetching ({
request,
processRequestBodyChunkLength,
processRequestEndOfBody,
processResponse,
processResponseEndOfBody,
processResponseConsumeBody,
useParallelQueue = false,
}) {
// 1. Let taskDestination be null.

@@ -332,22 +350,24 @@ let taskDestination = null

const currenTime = coarsenedSharedCurrentTime(crossOriginIsolatedCapability)
const timingInfo = makeTimingInfo({
startTime: currenTime,
postRedirectStartTime: currenTime
const timingInfo = createOpaqueTimingInfo({
startTime: currenTime
})
// 6. Let fetchParams be a new fetch params whose request is request, timing
// info is timingInfo, process request body is processRequestBody,
// process request end-of-body is processRequestEndOfBody, process response
// is processResponse, process response end-of-body is
// processResponseEndOfBody, process response done is processResponseDone,
// task destination is taskDestination, and cross-origin isolated capability
// is crossOriginIsolatedCapability.
// 6. Let fetchParams be a new fetch params whose
// request is request,
// timing info is timingInfo,
// process request body chunk length is processRequestBodyChunkLength,
// process request end-of-body is processRequestEndOfBody,
// process response is processResponse,
// process response consume body is processResponseConsumeBody,
// process response end-of-body is processResponseEndOfBody,
// task destination is taskDestination,
// and cross-origin isolated capability is crossOriginIsolatedCapability.
const fetchParams = {
request,
timingInfo,
processRequestBody: null,
processRequestEndOfBody: null,
processRequestBodyChunkLength,
processRequestEndOfBody,
processResponse,
processResponseEndOfBody: null,
processResponseDone,
processResponseConsumeBody,
processResponseEndOfBody,
taskDestination,

@@ -670,6 +690,5 @@ crossOriginIsolatedCapability

// 2. If request’s response tainting is "opaque", response is a network
// error, or response’s body is null, then run processBodyError and abort
// these steps.
if (request.responseTainting === 'opaque' && response.status === 0) {
// 2. If request’s response tainting is "opaque", or response’s body is null,
// then run processBodyError and abort these steps.
if (request.responseTainting === 'opaque' || response.body == null) {
processBodyError(response.error)

@@ -732,9 +751,9 @@ return

// 2. If fetchParams’s process response end-of-body is non-null, then:.
// 2. If fetchParams’s process response consume is non-null, then:.
// TODO
// 1. Let processBody given nullOrBytes be this step: run fetchParams’s
// process response end-of-body given response and nullOrBytes.on.
// process response consume given response and nullOrBytes.on.
// TODO
// 2. Let processBodyError be this step: run fetchParams’s process
// response end-of-body given response and failure.on.
// response consume given response and failure.on.
// TODO

@@ -1272,7 +1291,11 @@ // 3. If response’s body is null, then queue a fetch task to run

// 1. Let aborted be the termination’s aborted flag.
const aborted = context.terminated.aborted
// 2. If aborted is set, then return an aborted network error.
if (aborted) {
return makeNetworkError(new AbortError())
}
// 3. Return a network error.
return makeNetworkError(
context.terminated.aborted ? new AbortError() : null
)
return makeNetworkError(context.terminated.reason)
}

@@ -1307,6 +1330,8 @@

// 2. If aborted is set, then return an aborted network error.
const reason = aborted ? new AbortError() : new Error('terminated')
if (aborted) {
return makeNetworkError(new AbortError())
}
// 3. Return a network error.
return makeNetworkError(reason)
return makeNetworkError(context.terminated.reason)
}

@@ -1498,9 +1523,11 @@

// 2. If connection uses HTTP/2, then transmit an RST_STREAM frame.
this.connection?.destroy()
this.connection.destroy()
// 3. If aborted is set, then return an aborted network error.
const reason = aborted ? new AbortError() : new Error('terminated')
if (aborted) {
return resolve(makeNetworkError(new AbortError()))
}
// 4. Return a network error.
resolve(makeNetworkError(reason))
return resolve(makeNetworkError(this.terminated.reason))
}

@@ -1550,3 +1577,2 @@

async cancel (reason) {
stream[kError] = reason
await cancelAlgorithm(reason)

@@ -1590,19 +1616,9 @@ }

// 2. If stream is readable, error stream with an "AbortError" DOMException.
try {
if (isReadable(stream)) {
this.controller.error(new AbortError())
} catch (err) {
// Will throw TypeError if body is not readable.
if (err.name !== 'TypeError') {
throw err
}
}
} else {
// 4. Otherwise, if stream is readable, error stream with a TypeError.
try {
if (isReadable(stream)) {
this.controller.error(new TypeError('terminated'))
} catch (err) {
// Will throw TypeError if body is not readable.
if (err.name !== 'TypeError') {
throw err
}
}

@@ -1613,3 +1629,3 @@ }

// 6. Otherwise, the user agent should close connection unless it would be bad for performance to do so.
this.connection?.destroy()
this.connection.destroy()
}

@@ -1660,4 +1676,2 @@

registry.register(stream, this.abort, this)
response = makeResponse({

@@ -1695,26 +1709,13 @@ status,

let iterator
if (decoders.length > 1) {
if (compose) {
this.decoder = compose(...decoders)
iterator = this.decoder[Symbol.asyncIterator]()
} else {
this.decoder = new PassThrough()
iterator = pipeline(this.decoder, ...decoders, () => {})[
Symbol.asyncIterator
]()
}
} else if (decoders.length === 1) {
this.decoder = decoders[0]
iterator = this.decoder[Symbol.asyncIterator]()
} else {
this.decoder = new PassThrough()
iterator = this.decoder[Symbol.asyncIterator]()
pipeline(...decoders, () => {})
} else if (decoders.length === 0) {
// TODO (perf): Avoid intermediate.
decoders.push(new PassThrough())
}
if (this.decoder) {
this.decoder.on('drain', resume)
}
this.decoder = decoders[0].on('drain', resume)
const iterator = decoders[decoders.length - 1][Symbol.asyncIterator]()
pullAlgorithm = async (controller) => {

@@ -1762,4 +1763,4 @@ // 4. Set bytes to the result of handling content codings given

// 8. If stream is errored, then terminate the ongoing fetch.
if (stream[kError]) {
this.context.terminate({ reason: stream[kError] })
if (isErrored(stream)) {
this.context.terminate()
return

@@ -1807,4 +1808,2 @@ }

onComplete () {
registry.unregister(this)
this.decoder.end()

@@ -1814,4 +1813,2 @@ },

onError (error) {
registry.unregister(this)
this.decoder?.destroy(error)

@@ -1818,0 +1815,0 @@

@@ -31,2 +31,6 @@ /* globals AbortController */

const requestFinalizer = new FinalizationRegistry(({ signal, abort }) => {
signal.removeEventListener('abort', abort)
})
// https://fetch.spec.whatwg.org/#request-class

@@ -138,4 +142,44 @@ class Request {

request = makeRequest({
...request,
window
// URL request’s URL.
// undici implementation note: this is set as the first item in request's urlList in makeRequest
// method request’s method.
method: request.method,
// header list A copy of request’s header list.
// undici implementation note: headersList is cloned in makeRequest
headersList: request.headersList,
// unsafe-request flag Set.
unsafeRequest: request.unsafeRequest,
// client This’s relevant settings object.
client: request.client,
// window window.
window,
// priority request’s priority.
priority: request.priority,
// origin request’s origin. The propagation of the origin is only significant for navigation requests
// being handled by a service worker. In this scenario a request can have an origin that is different
// from the current client.
origin: request.origin,
// referrer request’s referrer.
referrer: request.referrer,
// referrer policy request’s referrer policy.
referrerPolicy: request.referrerPolicy,
// mode request’s mode.
mode: request.mode,
// credentials mode request’s credentials mode.
credentials: request.credentials,
// cache mode request’s cache mode.
cache: request.cache,
// redirect mode request’s redirect mode.
redirect: request.redirect,
// integrity metadata request’s integrity metadata.
integrity: request.integrity,
// keepalive request’s keepalive.
keepalive: request.keepalive,
// reload-navigation flag request’s reload-navigation flag.
reloadNavigation: request.reloadNavigation,
// history-navigation flag request’s history-navigation flag.
historyNavigation: request.historyNavigation,
// URL list A clone of request’s URL list.
// undici implementation note: urlList is cloned in makeRequest
urlList: request.urlList
})

@@ -156,7 +200,16 @@

// 4. Set request’s referrer to "client"
// 4. Set request’s origin to "client".
request.origin = 'client'
// 5. Set request’s referrer to "client"
request.referrer = 'client'
// 5. Set request’s referrer policy to the empty string.
// 6. Set request’s referrer policy to the empty string.
request.referrerPolicy = ''
// 7. Set request’s URL to request’s current URL.
request.url = request.urlList[request.urlList.length - 1]
// 8. Set request’s URL list to « request’s URL ».
request.urlList = [request.url]
}

@@ -170,3 +223,3 @@

// 2. If referrer is the empty string, then set request’s referrer to "no-referrer".
if (!referrer === '') {
if (referrer === '') {
request.referrer = 'no-referrer'

@@ -335,10 +388,5 @@ } else {

} else {
// TODO: Remove this listener on failure/success.
signal.addEventListener(
'abort',
function () {
ac.abort()
},
{ once: true }
)
const abort = () => ac.abort()
signal.addEventListener('abort', abort, { once: true })
requestFinalizer.register(this, { signal, abort })
}

@@ -345,0 +393,0 @@ }

@@ -9,4 +9,3 @@ 'use strict'

kGuard: Symbol('guard'),
kRealm: Symbol('realm'),
kError: Symbol('error')
kRealm: Symbol('realm')
}

@@ -256,8 +256,9 @@ 'use strict'

function makeTimingInfo (init) {
// https://fetch.spec.whatwg.org/#create-an-opaque-timing-info
function createOpaqueTimingInfo (timingInfo) {
return {
startTime: 0,
startTime: timingInfo.startTime ?? 0,
redirectStartTime: 0,
redirectEndTime: 0,
postRedirectStartTime: 0,
postRedirectStartTime: timingInfo.startTime ?? 0,
finalServiceWorkerStartTime: 0,

@@ -269,4 +270,3 @@ finalNetworkResponseStartTime: 0,

decodedBodySize: 0,
finalConnectionTimingInfo: null,
...init
finalConnectionTimingInfo: null
}

@@ -323,3 +323,3 @@ }

crossOriginResourcePolicyCheck,
makeTimingInfo,
createOpaqueTimingInfo,
setRequestReferrerPolicyOnRedirect,

@@ -326,0 +326,0 @@ isValidHTTPToken,

{
"name": "undici",
"version": "4.11.3",
"version": "4.12.0",
"description": "An HTTP/1.1 client, written from scratch for Node.js",

@@ -5,0 +5,0 @@ "homepage": "https://undici.nodejs.org",

@@ -206,10 +206,10 @@ # undici

The [Fetch Standard](https://fetch.spec.whatwg.org) allows users to skip consuming the response body by relying on
[garbage collection](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_Management#garbage_collection) to release connection resources. Undici does the same. However,
garbage collection in Node is less aggressive and deterministic (due to the lack
of clear idle periods that browser have through the rendering refresh rate)
which means that leaving the release of connection resources to the garbage collector
can lead to excessive connection usage, reduced performance (due to less connection re-use),
and even stalls or deadlocks when running out of connections. Therefore, it is highly
recommended to always either consume or cancel the response body.
[garbage collection](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_Management#garbage_collection) to release connection resources. Undici does not do the same. Therefore, it is important to always either consume or cancel the response body.
Garbage collection in Node is less aggressive and deterministic
(due to the lack of clear idle periods that browser have through the rendering refresh rate)
which means that leaving the release of connection resources to the garbage collector can lead
to excessive connection usage, reduced performance (due to less connection re-use), and even
stalls or deadlocks when running out of connections.
```js

@@ -293,3 +293,3 @@ // Do

Undici will immediately pipeline when retrying requests afters a failed
Undici will immediately pipeline when retrying requests after a failed
connection. However, Undici will not retry the first remaining requests in

@@ -296,0 +296,0 @@ the prior pipeline and instead error the corresponding callback/promise/stream.

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc