| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -159,6 +159,7 @@ an unbundled version instead of bundling one in `libnode.so`. | |||
| 159 | 159 | To enable this, pass `EXTERNAL_PATH=/path/to/global/node_modules/undici` to `build/wasm.js`. | |
| 160 | 160 | Pass this path with `loader.js` appended to `--shared-builtin-undici/undici-path` in Node.js's `configure.py`. | |
| 161 | 161 | 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`. | |
| 162 | + Similarly, you can set the `WASM_OPT` environment variable to utilize your own `wasm-opt` optimizer. | ||
| 162 | 163 | ||
| 163 | 164 | <a id="benchmarks"></a> | |
| 164 | 165 | ### Benchmarks | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -14,6 +14,7 @@ const WASM_CC = process.env.WASM_CC || 'clang' | |||
| 14 | 14 | let WASM_CFLAGS = process.env.WASM_CFLAGS || '--sysroot=/usr/share/wasi-sysroot -target wasm32-unknown-wasi' | |
| 15 | 15 | let WASM_LDFLAGS = process.env.WASM_LDFLAGS || '' | |
| 16 | 16 | const WASM_LDLIBS = process.env.WASM_LDLIBS || '' | |
| 17 | + const WASM_OPT = process.env.WASM_OPT || './wasm-opt' | ||
| 17 | 18 | ||
| 18 | 19 | // For compatibility with Node.js' `configure --shared-builtin-undici/undici-path ...` | |
| 19 | 20 | const EXTERNAL_PATH = process.env.EXTERNAL_PATH | |
@@ -77,7 +78,7 @@ const hasApk = (function () { | |||
| 77 | 78 | try { execSync('command -v apk'); return true } catch (error) { return false } | |
| 78 | 79 | })() | |
| 79 | 80 | const hasOptimizer = (function () { | |
| 80 | - try { execSync('./wasm-opt --version'); return true } catch (error) { return false } | ||
| 81 | + try { execSync(`${WASM_OPT} --version`); return true } catch (error) { return false } | ||
| 81 | 82 | })() | |
| 82 | 83 | if (hasApk) { | |
| 83 | 84 | // Gather information about the tools used for the build | |
@@ -97,7 +98,7 @@ ${join(WASM_SRC, 'src')}/*.c \ | |||
| 97 | 98 | ${WASM_LDLIBS}`, { stdio: 'inherit' }) | |
| 98 | 99 | ||
| 99 | 100 | if (hasOptimizer) { | |
| 100 | - execSync(`./wasm-opt ${WASM_OPT_FLAGS} -o ${join(WASM_OUT, 'llhttp.wasm')} ${join(WASM_OUT, 'llhttp.wasm')}`, { stdio: 'inherit' }) | ||
| 101 | + execSync(`${WASM_OPT} ${WASM_OPT_FLAGS} -o ${join(WASM_OUT, 'llhttp.wasm')} ${join(WASM_OUT, 'llhttp.wasm')}`, { stdio: 'inherit' }) | ||
| 101 | 102 | } | |
| 102 | 103 | writeWasmChunk('llhttp.wasm', 'llhttp-wasm.js') | |
| 103 | 104 | ||
@@ -109,7 +110,7 @@ ${join(WASM_SRC, 'src')}/*.c \ | |||
| 109 | 110 | ${WASM_LDLIBS}`, { stdio: 'inherit' }) | |
| 110 | 111 | ||
| 111 | 112 | if (hasOptimizer) { | |
| 112 | - execSync(`./wasm-opt ${WASM_OPT_FLAGS} --enable-simd -o ${join(WASM_OUT, 'llhttp_simd.wasm')} ${join(WASM_OUT, 'llhttp_simd.wasm')}`, { stdio: 'inherit' }) | ||
| 113 | + execSync(`${WASM_OPT} ${WASM_OPT_FLAGS} --enable-simd -o ${join(WASM_OUT, 'llhttp_simd.wasm')} ${join(WASM_OUT, 'llhttp_simd.wasm')}`, { stdio: 'inherit' }) | ||
| 113 | 114 | } | |
| 114 | 115 | writeWasmChunk('llhttp_simd.wasm', 'llhttp_simd-wasm.js') | |
| 115 | 116 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -25,9 +25,23 @@ const kWeight = Symbol('kWeight') | |||
| 25 | 25 | const kMaxWeightPerServer = Symbol('kMaxWeightPerServer') | |
| 26 | 26 | const kErrorPenalty = Symbol('kErrorPenalty') | |
| 27 | 27 | ||
| 28 | + /** | ||
| 29 | + * Calculate the greatest common divisor of two numbers by | ||
| 30 | + * using the Euclidean algorithm. | ||
| 31 | + * | ||
| 32 | + * @param {number} a | ||
| 33 | + * @param {number} b | ||
| 34 | + * @returns {number} | ||
| 35 | + */ | ||
| 28 | 36 | function getGreatestCommonDivisor (a, b) { | |
| 29 | - if (b === 0) return a | ||
| 30 | - return getGreatestCommonDivisor(b, a % b) | ||
| 37 | + if (a === 0) return b | ||
| 38 | + | ||
| 39 | + while (b !== 0) { | ||
| 40 | + const t = b | ||
| 41 | + b = a % b | ||
| 42 | + a = t | ||
| 43 | + } | ||
| 44 | + return a | ||
| 31 | 45 | } | |
| 32 | 46 | ||
| 33 | 47 | function defaultFactory (origin, opts) { | |
@@ -105,7 +119,12 @@ class BalancedPool extends PoolBase { | |||
| 105 | 119 | } | |
| 106 | 120 | ||
| 107 | 121 | _updateBalancedPoolStats () { | |
| 108 | - this[kGreatestCommonDivisor] = this[kClients].map(p => p[kWeight]).reduce(getGreatestCommonDivisor, 0) | ||
| 122 | + let result = 0 | ||
| 123 | + for (let i = 0; i < this[kClients].length; i++) { | ||
| 124 | + result = getGreatestCommonDivisor(this[kClients][i][kWeight], result) | ||
| 125 | + } | ||
| 126 | + | ||
| 127 | + this[kGreatestCommonDivisor] = result | ||
| 109 | 128 | } | |
| 110 | 129 | ||
| 111 | 130 | removeUpstream (upstream) { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,12 +1,12 @@ | |||
| 1 | 1 | ||
| 2 | - > undici@6.19.7 prebuild:wasm | ||
| 2 | + > undici@6.19.8 prebuild:wasm | ||
| 3 | 3 | > node build/wasm.js --prebuild | |
| 4 | 4 | ||
| 5 | 5 | > 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 | |
| 6 | 6 | ||
| 7 | 7 | ||
| 8 | 8 | ||
| 9 | - > undici@6.19.7 build:wasm | ||
| 9 | + > undici@6.19.8 build:wasm | ||
| 10 | 10 | > node build/wasm.js --docker | |
| 11 | 11 | ||
| 12 | 12 | > 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 | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -16,12 +16,25 @@ const { kState } = require('./symbols') | |||
| 16 | 16 | const { webidl } = require('./webidl') | |
| 17 | 17 | const { Blob } = require('node:buffer') | |
| 18 | 18 | const assert = require('node:assert') | |
| 19 | - const { isErrored } = require('../../core/util') | ||
| 19 | + const { isErrored, isDisturbed } = require('node:stream') | ||
| 20 | 20 | const { isArrayBuffer } = require('node:util/types') | |
| 21 | 21 | const { serializeAMimeType } = require('./data-url') | |
| 22 | 22 | const { multipartFormDataParser } = require('./formdata-parser') | |
| 23 | 23 | ||
| 24 | 24 | const textEncoder = new TextEncoder() | |
| 25 | + function noop () {} | ||
| 26 | + | ||
| 27 | + const hasFinalizationRegistry = globalThis.FinalizationRegistry && process.version.indexOf('v18') !== 0 | ||
| 28 | + let streamRegistry | ||
| 29 | + | ||
| 30 | + if (hasFinalizationRegistry) { | ||
| 31 | + streamRegistry = new FinalizationRegistry((weakRef) => { | ||
| 32 | + const stream = weakRef.deref() | ||
| 33 | + if (stream && !stream.locked && !isDisturbed(stream) && !isErrored(stream)) { | ||
| 34 | + stream.cancel('Response object has been garbage collected').catch(noop) | ||
| 35 | + } | ||
| 36 | + }) | ||
| 37 | + } | ||
| 25 | 38 | ||
| 26 | 39 | // https://fetch.spec.whatwg.org/#concept-bodyinit-extract | |
| 27 | 40 | function extractBody (object, keepalive = false) { | |
@@ -264,14 +277,18 @@ function safelyExtractBody (object, keepalive = false) { | |||
| 264 | 277 | return extractBody(object, keepalive) | |
| 265 | 278 | } | |
| 266 | 279 | ||
| 267 | - function cloneBody (body) { | ||
| 280 | + function cloneBody (instance, body) { | ||
| 268 | 281 | // To clone a body body, run these steps: | |
| 269 | 282 | ||
| 270 | 283 | // https://fetch.spec.whatwg.org/#concept-body-clone | |
| 271 | 284 | ||
| 272 | 285 | // 1. Let « out1, out2 » be the result of teeing body’s stream. | |
| 273 | 286 | const [out1, out2] = body.stream.tee() | |
| 274 | 287 | ||
| 288 | + if (hasFinalizationRegistry) { | ||
| 289 | + streamRegistry.register(instance, new WeakRef(out1)) | ||
| 290 | + } | ||
| 291 | + | ||
| 275 | 292 | // 2. Set body’s stream to out1. | |
| 276 | 293 | body.stream = out1 | |
| 277 | 294 | ||
@@ -414,7 +431,7 @@ async function consumeBody (object, convertBytesToJSValue, instance) { | |||
| 414 | 431 | ||
| 415 | 432 | // 1. If object is unusable, then return a promise rejected | |
| 416 | 433 | // with a TypeError. | |
| 417 | - if (bodyUnusable(object[kState].body)) { | ||
| 434 | + if (bodyUnusable(object)) { | ||
| 418 | 435 | throw new TypeError('Body is unusable: Body has already been read') | |
| 419 | 436 | } | |
| 420 | 437 | ||
@@ -454,7 +471,9 @@ async function consumeBody (object, convertBytesToJSValue, instance) { | |||
| 454 | 471 | } | |
| 455 | 472 | ||
| 456 | 473 | // https://fetch.spec.whatwg.org/#body-unusable | |
| 457 | - function bodyUnusable (body) { | ||
| 474 | + function bodyUnusable (object) { | ||
| 475 | + const body = object[kState].body | ||
| 476 | + | ||
| 458 | 477 | // An object including the Body interface mixin is | |
| 459 | 478 | // said to be unusable if its body is non-null and | |
| 460 | 479 | // its body’s stream is disturbed or locked. | |
@@ -496,5 +515,8 @@ module.exports = { | |||
| 496 | 515 | extractBody, | |
| 497 | 516 | safelyExtractBody, | |
| 498 | 517 | cloneBody, | |
| 499 | - mixinBody | ||
| 518 | + mixinBody, | ||
| 519 | + streamRegistry, | ||
| 520 | + hasFinalizationRegistry, | ||
| 521 | + bodyUnusable | ||
| 500 | 522 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2,7 +2,7 @@ | |||
| 2 | 2 | ||
| 3 | 3 | 'use strict' | |
| 4 | 4 | ||
| 5 | - const { extractBody, mixinBody, cloneBody } = require('./body') | ||
| 5 | + const { extractBody, mixinBody, cloneBody, bodyUnusable } = require('./body') | ||
| 6 | 6 | const { Headers, fill: fillHeaders, HeadersList, setHeadersGuard, getHeadersGuard, setHeadersList, getHeadersList } = require('./headers') | |
| 7 | 7 | const { FinalizationRegistry } = require('./dispatcher-weakref')() | |
| 8 | 8 | const util = require('../../core/util') | |
@@ -557,7 +557,7 @@ class Request { | |||
| 557 | 557 | // 40. If initBody is null and inputBody is non-null, then: | |
| 558 | 558 | if (initBody == null && inputBody != null) { | |
| 559 | 559 | // 1. If input is unusable, then throw a TypeError. | |
| 560 | - if (util.isDisturbed(inputBody.stream) || inputBody.stream.locked) { | ||
| 560 | + if (bodyUnusable(input)) { | ||
| 561 | 561 | throw new TypeError( | |
| 562 | 562 | 'Cannot construct a Request with a Request object that has already been used.' | |
| 563 | 563 | ) | |
@@ -759,7 +759,7 @@ class Request { | |||
| 759 | 759 | webidl.brandCheck(this, Request) | |
| 760 | 760 | ||
| 761 | 761 | // 1. If this is unusable, then throw a TypeError. | |
| 762 | - if (this.bodyUsed || this.body?.locked) { | ||
| 762 | + if (bodyUnusable(this)) { | ||
| 763 | 763 | throw new TypeError('unusable') | |
| 764 | 764 | } | |
| 765 | 765 | ||
@@ -877,7 +877,7 @@ function cloneRequest (request) { | |||
| 877 | 877 | // 2. If request’s body is non-null, set newRequest’s body to the | |
| 878 | 878 | // result of cloning request’s body. | |
| 879 | 879 | if (request.body != null) { | |
| 880 | - newRequest.body = cloneBody(request.body) | ||
| 880 | + newRequest.body = cloneBody(newRequest, request.body) | ||
| 881 | 881 | } | |
| 882 | 882 | ||
| 883 | 883 | // 3. Return newRequest. | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,7 +1,7 @@ | |||
| 1 | 1 | 'use strict' | |
| 2 | 2 | ||
| 3 | 3 | const { Headers, HeadersList, fill, getHeadersGuard, setHeadersGuard, setHeadersList } = require('./headers') | |
| 4 | - const { extractBody, cloneBody, mixinBody } = require('./body') | ||
| 4 | + const { extractBody, cloneBody, mixinBody, hasFinalizationRegistry, streamRegistry, bodyUnusable } = require('./body') | ||
| 5 | 5 | const util = require('../../core/util') | |
| 6 | 6 | const nodeUtil = require('node:util') | |
| 7 | 7 | const { kEnumerableProperty } = util | |
@@ -26,24 +26,9 @@ const { URLSerializer } = require('./data-url') | |||
| 26 | 26 | const { kConstruct } = require('../../core/symbols') | |
| 27 | 27 | const assert = require('node:assert') | |
| 28 | 28 | const { types } = require('node:util') | |
| 29 | - const { isDisturbed, isErrored } = require('node:stream') | ||
| 30 | 29 | ||
| 31 | 30 | const textEncoder = new TextEncoder('utf-8') | |
| 32 | 31 | ||
| 33 | - const hasFinalizationRegistry = globalThis.FinalizationRegistry && process.version.indexOf('v18') !== 0 | ||
| 34 | - let registry | ||
| 35 | - | ||
| 36 | - if (hasFinalizationRegistry) { | ||
| 37 | - registry = new FinalizationRegistry((weakRef) => { | ||
| 38 | - const stream = weakRef.deref() | ||
| 39 | - if (stream && !stream.locked && !isDisturbed(stream) && !isErrored(stream)) { | ||
| 40 | - stream.cancel('Response object has been garbage collected').catch(noop) | ||
| 41 | - } | ||
| 42 | - }) | ||
| 43 | - } | ||
| 44 | - | ||
| 45 | - function noop () {} | ||
| 46 | - | ||
| 47 | 32 | // https://fetch.spec.whatwg.org/#response-class | |
| 48 | 33 | class Response { | |
| 49 | 34 | // Creates network error Response. | |
@@ -244,7 +229,7 @@ class Response { | |||
| 244 | 229 | webidl.brandCheck(this, Response) | |
| 245 | 230 | ||
| 246 | 231 | // 1. If this is unusable, then throw a TypeError. | |
| 247 | - if (this.bodyUsed || this.body?.locked) { | ||
| 232 | + if (bodyUnusable(this)) { | ||
| 248 | 233 | throw webidl.errors.exception({ | |
| 249 | 234 | header: 'Response.clone', | |
| 250 | 235 | message: 'Body has already been consumed.' | |
@@ -327,7 +312,7 @@ function cloneResponse (response) { | |||
| 327 | 312 | // 3. If response’s body is non-null, then set newResponse’s body to the | |
| 328 | 313 | // result of cloning response’s body. | |
| 329 | 314 | if (response.body != null) { | |
| 330 | - newResponse.body = cloneBody(response.body) | ||
| 315 | + newResponse.body = cloneBody(newResponse, response.body) | ||
| 331 | 316 | } | |
| 332 | 317 | ||
| 333 | 318 | // 4. Return newResponse. | |
@@ -532,7 +517,7 @@ function fromInnerResponse (innerResponse, guard) { | |||
| 532 | 517 | // a primitive or an object, even undefined. If the held value is an object, the registry keeps | |
| 533 | 518 | // a strong reference to it (so it can pass it to the cleanup callback later). Reworded from | |
| 534 | 519 | // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/FinalizationRegistry | |
| 535 | - registry.register(response, new WeakRef(innerResponse.body.stream)) | ||
| 520 | + streamRegistry.register(response, new WeakRef(innerResponse.body.stream)) | ||
| 536 | 521 | } | |
| 537 | 522 | ||
| 538 | 523 | return response | |
| Back | FazBrowse Home | New Git URL |
0 commit comments