Skip to content

Commit

Permalink
deps: update undici to 6.19.8
Browse files Browse the repository at this point in the history
PR-URL: nodejs#54456
Reviewed-By: Marco Ippolito <[email protected]>
Reviewed-By: Matteo Collina <[email protected]>
  • Loading branch information
nodejs-github-bot authored Aug 22, 2024
1 parent 4d5c885 commit e70bd47
Show file tree
Hide file tree
Showing 11 changed files with 172 additions and 87 deletions.
1 change: 1 addition & 0 deletions deps/undici/src/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ an unbundled version instead of bundling one in `libnode.so`.
To enable this, pass `EXTERNAL_PATH=/path/to/global/node_modules/undici` to `build/wasm.js`.
Pass this path with `loader.js` appended to `--shared-builtin-undici/undici-path` in Node.js's `configure.py`.
If building on a non-Alpine Linux distribution, you may need to also set the `WASM_CC`, `WASM_CFLAGS`, `WASM_LDFLAGS` and `WASM_LDLIBS` environment variables before running `build/wasm.js`.
Similarly, you can set the `WASM_OPT` environment variable to utilize your own `wasm-opt` optimizer.

<a id="benchmarks"></a>
### Benchmarks
Expand Down
7 changes: 4 additions & 3 deletions deps/undici/src/build/wasm.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const WASM_CC = process.env.WASM_CC || 'clang'
let WASM_CFLAGS = process.env.WASM_CFLAGS || '--sysroot=/usr/share/wasi-sysroot -target wasm32-unknown-wasi'
let WASM_LDFLAGS = process.env.WASM_LDFLAGS || ''
const WASM_LDLIBS = process.env.WASM_LDLIBS || ''
const WASM_OPT = process.env.WASM_OPT || './wasm-opt'

// For compatibility with Node.js' `configure --shared-builtin-undici/undici-path ...`
const EXTERNAL_PATH = process.env.EXTERNAL_PATH
Expand Down Expand Up @@ -77,7 +78,7 @@ const hasApk = (function () {
try { execSync('command -v apk'); return true } catch (error) { return false }
})()
const hasOptimizer = (function () {
try { execSync('./wasm-opt --version'); return true } catch (error) { return false }
try { execSync(`${WASM_OPT} --version`); return true } catch (error) { return false }
})()
if (hasApk) {
// Gather information about the tools used for the build
Expand All @@ -97,7 +98,7 @@ ${join(WASM_SRC, 'src')}/*.c \
${WASM_LDLIBS}`, { stdio: 'inherit' })

if (hasOptimizer) {
execSync(`./wasm-opt ${WASM_OPT_FLAGS} -o ${join(WASM_OUT, 'llhttp.wasm')} ${join(WASM_OUT, 'llhttp.wasm')}`, { stdio: 'inherit' })
execSync(`${WASM_OPT} ${WASM_OPT_FLAGS} -o ${join(WASM_OUT, 'llhttp.wasm')} ${join(WASM_OUT, 'llhttp.wasm')}`, { stdio: 'inherit' })
}
writeWasmChunk('llhttp.wasm', 'llhttp-wasm.js')

Expand All @@ -109,7 +110,7 @@ ${join(WASM_SRC, 'src')}/*.c \
${WASM_LDLIBS}`, { stdio: 'inherit' })

if (hasOptimizer) {
execSync(`./wasm-opt ${WASM_OPT_FLAGS} --enable-simd -o ${join(WASM_OUT, 'llhttp_simd.wasm')} ${join(WASM_OUT, 'llhttp_simd.wasm')}`, { stdio: 'inherit' })
execSync(`${WASM_OPT} ${WASM_OPT_FLAGS} --enable-simd -o ${join(WASM_OUT, 'llhttp_simd.wasm')} ${join(WASM_OUT, 'llhttp_simd.wasm')}`, { stdio: 'inherit' })
}
writeWasmChunk('llhttp_simd.wasm', 'llhttp_simd-wasm.js')

Expand Down
25 changes: 22 additions & 3 deletions deps/undici/src/lib/dispatcher/balanced-pool.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,23 @@ const kWeight = Symbol('kWeight')
const kMaxWeightPerServer = Symbol('kMaxWeightPerServer')
const kErrorPenalty = Symbol('kErrorPenalty')

/**
* Calculate the greatest common divisor of two numbers by
* using the Euclidean algorithm.
*
* @param {number} a
* @param {number} b
* @returns {number}
*/
function getGreatestCommonDivisor (a, b) {
if (b === 0) return a
return getGreatestCommonDivisor(b, a % b)
if (a === 0) return b

while (b !== 0) {
const t = b
b = a % b
a = t
}
return a
}

function defaultFactory (origin, opts) {
Expand Down Expand Up @@ -105,7 +119,12 @@ class BalancedPool extends PoolBase {
}

_updateBalancedPoolStats () {
this[kGreatestCommonDivisor] = this[kClients].map(p => p[kWeight]).reduce(getGreatestCommonDivisor, 0)
let result = 0
for (let i = 0; i < this[kClients].length; i++) {
result = getGreatestCommonDivisor(this[kClients][i][kWeight], result)
}

this[kGreatestCommonDivisor] = result
}

removeUpstream (upstream) {
Expand Down
4 changes: 2 additions & 2 deletions deps/undici/src/lib/llhttp/wasm_build_env.txt
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@

> [email protected].7 prebuild:wasm
> [email protected].8 prebuild:wasm
> node build/wasm.js --prebuild

> docker build --platform=linux/x86_64 -t llhttp_wasm_builder -f /home/runner/work/node/node/deps/undici/src/build/Dockerfile /home/runner/work/node/node/deps/undici/src



> [email protected].7 build:wasm
> [email protected].8 build:wasm
> node build/wasm.js --docker

> docker run --rm -t --platform=linux/x86_64 --user 1001:127 --mount type=bind,source=/home/runner/work/node/node/deps/undici/src/lib/llhttp,target=/home/node/undici/lib/llhttp llhttp_wasm_builder node build/wasm.js
Expand Down
32 changes: 27 additions & 5 deletions deps/undici/src/lib/web/fetch/body.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,25 @@ const { kState } = require('./symbols')
const { webidl } = require('./webidl')
const { Blob } = require('node:buffer')
const assert = require('node:assert')
const { isErrored } = require('../../core/util')
const { isErrored, isDisturbed } = require('node:stream')
const { isArrayBuffer } = require('node:util/types')
const { serializeAMimeType } = require('./data-url')
const { multipartFormDataParser } = require('./formdata-parser')

const textEncoder = new TextEncoder()
function noop () {}

const hasFinalizationRegistry = globalThis.FinalizationRegistry && process.version.indexOf('v18') !== 0
let streamRegistry

if (hasFinalizationRegistry) {
streamRegistry = new FinalizationRegistry((weakRef) => {
const stream = weakRef.deref()
if (stream && !stream.locked && !isDisturbed(stream) && !isErrored(stream)) {
stream.cancel('Response object has been garbage collected').catch(noop)
}
})
}

// https://fetch.spec.whatwg.org/#concept-bodyinit-extract
function extractBody (object, keepalive = false) {
Expand Down Expand Up @@ -264,14 +277,18 @@ function safelyExtractBody (object, keepalive = false) {
return extractBody(object, keepalive)
}

function cloneBody (body) {
function cloneBody (instance, body) {
// To clone a body body, run these steps:

// https://fetch.spec.whatwg.org/#concept-body-clone

// 1. Let « out1, out2 » be the result of teeing body’s stream.
const [out1, out2] = body.stream.tee()

if (hasFinalizationRegistry) {
streamRegistry.register(instance, new WeakRef(out1))
}

// 2. Set body’s stream to out1.
body.stream = out1

Expand Down Expand Up @@ -414,7 +431,7 @@ async function consumeBody (object, convertBytesToJSValue, instance) {

// 1. If object is unusable, then return a promise rejected
// with a TypeError.
if (bodyUnusable(object[kState].body)) {
if (bodyUnusable(object)) {
throw new TypeError('Body is unusable: Body has already been read')
}

Expand Down Expand Up @@ -454,7 +471,9 @@ async function consumeBody (object, convertBytesToJSValue, instance) {
}

// https://fetch.spec.whatwg.org/#body-unusable
function bodyUnusable (body) {
function bodyUnusable (object) {
const body = object[kState].body

// An object including the Body interface mixin is
// said to be unusable if its body is non-null and
// its body’s stream is disturbed or locked.
Expand Down Expand Up @@ -496,5 +515,8 @@ module.exports = {
extractBody,
safelyExtractBody,
cloneBody,
mixinBody
mixinBody,
streamRegistry,
hasFinalizationRegistry,
bodyUnusable
}
8 changes: 4 additions & 4 deletions deps/undici/src/lib/web/fetch/request.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

'use strict'

const { extractBody, mixinBody, cloneBody } = require('./body')
const { extractBody, mixinBody, cloneBody, bodyUnusable } = require('./body')
const { Headers, fill: fillHeaders, HeadersList, setHeadersGuard, getHeadersGuard, setHeadersList, getHeadersList } = require('./headers')
const { FinalizationRegistry } = require('./dispatcher-weakref')()
const util = require('../../core/util')
Expand Down Expand Up @@ -557,7 +557,7 @@ class Request {
// 40. If initBody is null and inputBody is non-null, then:
if (initBody == null && inputBody != null) {
// 1. If input is unusable, then throw a TypeError.
if (util.isDisturbed(inputBody.stream) || inputBody.stream.locked) {
if (bodyUnusable(input)) {
throw new TypeError(
'Cannot construct a Request with a Request object that has already been used.'
)
Expand Down Expand Up @@ -759,7 +759,7 @@ class Request {
webidl.brandCheck(this, Request)

// 1. If this is unusable, then throw a TypeError.
if (this.bodyUsed || this.body?.locked) {
if (bodyUnusable(this)) {
throw new TypeError('unusable')
}

Expand Down Expand Up @@ -877,7 +877,7 @@ function cloneRequest (request) {
// 2. If request’s body is non-null, set newRequest’s body to the
// result of cloning request’s body.
if (request.body != null) {
newRequest.body = cloneBody(request.body)
newRequest.body = cloneBody(newRequest, request.body)
}

// 3. Return newRequest.
Expand Down
23 changes: 4 additions & 19 deletions deps/undici/src/lib/web/fetch/response.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use strict'

const { Headers, HeadersList, fill, getHeadersGuard, setHeadersGuard, setHeadersList } = require('./headers')
const { extractBody, cloneBody, mixinBody } = require('./body')
const { extractBody, cloneBody, mixinBody, hasFinalizationRegistry, streamRegistry, bodyUnusable } = require('./body')
const util = require('../../core/util')
const nodeUtil = require('node:util')
const { kEnumerableProperty } = util
Expand All @@ -26,24 +26,9 @@ const { URLSerializer } = require('./data-url')
const { kConstruct } = require('../../core/symbols')
const assert = require('node:assert')
const { types } = require('node:util')
const { isDisturbed, isErrored } = require('node:stream')

const textEncoder = new TextEncoder('utf-8')

const hasFinalizationRegistry = globalThis.FinalizationRegistry && process.version.indexOf('v18') !== 0
let registry

if (hasFinalizationRegistry) {
registry = new FinalizationRegistry((weakRef) => {
const stream = weakRef.deref()
if (stream && !stream.locked && !isDisturbed(stream) && !isErrored(stream)) {
stream.cancel('Response object has been garbage collected').catch(noop)
}
})
}

function noop () {}

// https://fetch.spec.whatwg.org/#response-class
class Response {
// Creates network error Response.
Expand Down Expand Up @@ -244,7 +229,7 @@ class Response {
webidl.brandCheck(this, Response)

// 1. If this is unusable, then throw a TypeError.
if (this.bodyUsed || this.body?.locked) {
if (bodyUnusable(this)) {
throw webidl.errors.exception({
header: 'Response.clone',
message: 'Body has already been consumed.'
Expand Down Expand Up @@ -327,7 +312,7 @@ function cloneResponse (response) {
// 3. If response’s body is non-null, then set newResponse’s body to the
// result of cloning response’s body.
if (response.body != null) {
newResponse.body = cloneBody(response.body)
newResponse.body = cloneBody(newResponse, response.body)
}

// 4. Return newResponse.
Expand Down Expand Up @@ -532,7 +517,7 @@ function fromInnerResponse (innerResponse, guard) {
// a primitive or an object, even undefined. If the held value is an object, the registry keeps
// a strong reference to it (so it can pass it to the cleanup callback later). Reworded from
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/FinalizationRegistry
registry.register(response, new WeakRef(innerResponse.body.stream))
streamRegistry.register(response, new WeakRef(innerResponse.body.stream))
}

return response
Expand Down
Loading

0 comments on commit e70bd47

Please sign in to comment.