diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml index bff3c5ef7d2..295e44b2c55 100644 --- a/.github/workflows/bench.yml +++ b/.github/workflows/bench.yml @@ -12,12 +12,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Code - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 with: persist-credentials: false ref: ${{ github.base_ref }} - name: Setup Node - uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0 + uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1 with: node-version: lts/* - name: Install Modules @@ -30,11 +30,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Code - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 with: persist-credentials: false - name: Setup Node - uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0 + uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1 with: node-version: lts/* - name: Install Modules diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index b921c4eebe4..520750ff88a 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -46,11 +46,11 @@ jobs: egress-policy: audit - name: Checkout repository - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@0ba4244466797eb048eb91a6cd43d5c03ca8bd05 # v2.3.3 + uses: github/codeql-action/init@00e563ead9f72a8461b24876bee2d0c2e8bd2ee8 # v2.3.3 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -60,7 +60,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@0ba4244466797eb048eb91a6cd43d5c03ca8bd05 # v2.3.3 + uses: github/codeql-action/autobuild@00e563ead9f72a8461b24876bee2d0c2e8bd2ee8 # v2.3.3 # ℹī¸ Command-line programs to run using the OS shell. # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun @@ -73,6 +73,6 @@ jobs: # ./location_of_script_within_repo/buildscript.sh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@0ba4244466797eb048eb91a6cd43d5c03ca8bd05 # v2.3.3 + uses: github/codeql-action/analyze@00e563ead9f72a8461b24876bee2d0c2e8bd2ee8 # v2.3.3 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index b95c4b9752b..eb24b0d0d6f 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -22,6 +22,6 @@ jobs: egress-policy: audit - name: 'Checkout Repository' - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 - name: 'Dependency Review' - uses: actions/dependency-review-action@1360a344ccb0ab6e9475edef90ad2f46bf8003b1 # v3.0.6 + uses: actions/dependency-review-action@f6fff72a3217f580d5afd49a46826795305b63c7 # v3.0.8 diff --git a/.github/workflows/fuzz.yml b/.github/workflows/fuzz.yml index 85247144889..c2c918d3544 100644 --- a/.github/workflows/fuzz.yml +++ b/.github/workflows/fuzz.yml @@ -11,12 +11,12 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 with: persist-credentials: false - name: Setup Node - uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0 + uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1 with: node-version: lts/* diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index e00f3fe7bf0..62645af1bc0 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -7,10 +7,10 @@ jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 with: persist-credentials: false - - uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0 + - uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1 with: node-version: lts/* - run: npm install diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index 1c41627e289..27533ab77bf 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -34,6 +34,6 @@ jobs: pull-requests: write contents: write steps: - - uses: fastify/github-action-merge-dependabot@d37100b180dfd816bb1d7e4fbb544b3c734957a1 # v3.9.0 + - uses: fastify/github-action-merge-dependabot@59fc8817458fac20df8884576cfe69dbb77c9a07 # v3.9.1 with: github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 040de504a44..f641f9512b8 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -29,7 +29,7 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 with: persist-credentials: false @@ -51,6 +51,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@0ba4244466797eb048eb91a6cd43d5c03ca8bd05 # v2.21.2 + uses: github/codeql-action/upload-sarif@00e563ead9f72a8461b24876bee2d0c2e8bd2ee8 # v2.21.5 with: sarif_file: results.sarif diff --git a/README.md b/README.md index 05a5d21ed11..e6c3552ade4 100644 --- a/README.md +++ b/README.md @@ -18,30 +18,34 @@ npm i undici ## Benchmarks The benchmark is a simple `hello world` [example](benchmarks/benchmark.js) using a -number of unix sockets (connections) with a pipelining depth of 10 running on Node 16. -The benchmarks below have the [simd](https://github.com/WebAssembly/simd) feature enabled. +number of unix sockets (connections) with a pipelining depth of 10 running on Node 20.6.0. ### Connections 1 -| Tests | Samples | Result | Tolerance | Difference with slowest | -|---------------------|---------|---------------|-----------|-------------------------| -| http - no keepalive | 15 | 4.63 req/sec | Âą 2.77 % | - | -| http - keepalive | 10 | 4.81 req/sec | Âą 2.16 % | + 3.94 % | -| undici - stream | 25 | 62.22 req/sec | Âą 2.67 % | + 1244.58 % | -| undici - dispatch | 15 | 64.33 req/sec | Âą 2.47 % | + 1290.24 % | -| undici - request | 15 | 66.08 req/sec | Âą 2.48 % | + 1327.88 % | -| undici - pipeline | 10 | 66.13 req/sec | Âą 1.39 % | + 1329.08 % | + +│ Tests │ Samples │ Result │ Tolerance │ Difference with slowest │ +|─────────────────────|─────────|───────────────|───────────|─────────────────────────| +│ http - no keepalive │ 15 │ 5.32 req/sec │ Âą 2.61 % │ - │ +│ http - keepalive │ 10 │ 5.35 req/sec │ Âą 2.47 % │ + 0.44 % │ +│ undici - fetch │ 15 │ 41.85 req/sec │ Âą 2.49 % │ + 686.04 % │ +│ undici - pipeline │ 40 │ 50.36 req/sec │ Âą 2.77 % │ + 845.92 % │ +│ undici - stream │ 15 │ 60.58 req/sec │ Âą 2.75 % │ + 1037.72 % │ +│ undici - request │ 10 │ 61.19 req/sec │ Âą 2.60 % │ + 1049.24 % │ +│ undici - dispatch │ 20 │ 64.84 req/sec │ Âą 2.81 % │ + 1117.81 % │ + ### Connections 50 -| Tests | Samples | Result | Tolerance | Difference with slowest | -|---------------------|---------|------------------|-----------|-------------------------| -| http - no keepalive | 50 | 3546.49 req/sec | Âą 2.90 % | - | -| http - keepalive | 15 | 5692.67 req/sec | Âą 2.48 % | + 60.52 % | -| undici - pipeline | 25 | 8478.71 req/sec | Âą 2.62 % | + 139.07 % | -| undici - request | 20 | 9766.66 req/sec | Âą 2.79 % | + 175.39 % | -| undici - stream | 15 | 10109.74 req/sec | Âą 2.94 % | + 185.06 % | -| undici - dispatch | 25 | 10949.73 req/sec | Âą 2.54 % | + 208.75 % | +│ Tests │ Samples │ Result │ Tolerance │ Difference with slowest │ +|─────────────────────|─────────|──────────────────|───────────|─────────────────────────| +│ undici - fetch │ 30 │ 2107.19 req/sec │ Âą 2.69 % │ - │ +│ http - no keepalive │ 10 │ 2698.90 req/sec │ Âą 2.68 % │ + 28.08 % │ +│ http - keepalive │ 10 │ 4639.49 req/sec │ Âą 2.55 % │ + 120.17 % │ +│ undici - pipeline │ 40 │ 6123.33 req/sec │ Âą 2.97 % │ + 190.59 % │ +│ undici - stream │ 50 │ 9426.51 req/sec │ Âą 2.92 % │ + 347.35 % │ +│ undici - request │ 10 │ 10162.88 req/sec │ Âą 2.13 % │ + 382.29 % │ +│ undici - dispatch │ 50 │ 11191.11 req/sec │ Âą 2.98 % │ + 431.09 % │ + ## Quick Start diff --git a/index.js b/index.js index 7e8831ceeea..7c0c8adcd6c 100644 --- a/index.js +++ b/index.js @@ -106,7 +106,10 @@ if (util.nodeMajor > 16 || (util.nodeMajor === 16 && util.nodeMinor >= 8)) { try { return await fetchImpl(...arguments) } catch (err) { - Error.captureStackTrace(err, this) + if (typeof err === 'object') { + Error.captureStackTrace(err, this) + } + throw err } } diff --git a/lib/core/util.js b/lib/core/util.js index b77db3c59ba..0e6197a4b29 100644 --- a/lib/core/util.js +++ b/lib/core/util.js @@ -359,6 +359,12 @@ function getSocketInfo (socket) { } } +async function * convertIterableToBuffer (iterable) { + for await (const chunk of iterable) { + yield Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk) + } +} + let ReadableStream function ReadableStreamFrom (iterable) { if (!ReadableStream) { @@ -366,8 +372,7 @@ function ReadableStreamFrom (iterable) { } if (ReadableStream.from) { - // https://github.com/whatwg/streams/pull/1083 - return ReadableStream.from(iterable) + return ReadableStream.from(convertIterableToBuffer(iterable)) } let iterator diff --git a/lib/fetch/body.js b/lib/fetch/body.js index 11b945d18bf..105eb553157 100644 --- a/lib/fetch/body.js +++ b/lib/fetch/body.js @@ -387,6 +387,7 @@ function bodyMixinMethods (instance) { try { busboy = Busboy({ headers, + preservePath: true, defParamCharset: 'utf8' }) } catch (err) { diff --git a/package.json b/package.json index 680ae6f4c43..863e85604f4 100644 --- a/package.json +++ b/package.json @@ -98,7 +98,7 @@ "standard": "^17.0.0", "table": "^6.8.0", "tap": "^16.1.0", - "tsd": "^0.28.1", + "tsd": "^0.29.0", "typescript": "^5.0.2", "wait-on": "^7.0.1", "ws": "^8.11.0" diff --git a/test/fetch/client-fetch.js b/test/fetch/client-fetch.js index 048b76a9f78..9009d547ec6 100644 --- a/test/fetch/client-fetch.js +++ b/test/fetch/client-fetch.js @@ -272,6 +272,18 @@ test('busboy emit error', async (t) => { await t.rejects(res.formData(), 'Unexpected end of multipart data') }) +// https://github.com/nodejs/undici/issues/2244 +test('parsing formData preserve full path on files', async (t) => { + t.plan(1) + const formData = new FormData() + formData.append('field1', new File(['foo'], 'a/b/c/foo.txt')) + + const tempRes = new Response(formData) + const form = await tempRes.formData() + + t.equal(form.get('field1').name, 'a/b/c/foo.txt') +}) + test('urlencoded formData', (t) => { t.plan(2) diff --git a/test/fetch/issue-2242.js b/test/fetch/issue-2242.js new file mode 100644 index 00000000000..fe704123e9a --- /dev/null +++ b/test/fetch/issue-2242.js @@ -0,0 +1,8 @@ +'use strict' + +const { test } = require('tap') +const { fetch } = require('../..') + +test('fetch with signal already aborted', async (t) => { + await t.rejects(fetch('http://localhost', { signal: AbortSignal.abort('Already aborted') }), 'Already aborted') +}) diff --git a/test/utils/redirecting-servers.js b/test/utils/redirecting-servers.js index db7a4dd6ded..53d674c4862 100644 --- a/test/utils/redirecting-servers.js +++ b/test/utils/redirecting-servers.js @@ -2,6 +2,17 @@ const { createServer } = require('http') +function close (server) { + return function () { + return new Promise(resolve => { + if (typeof server.closeAllConnections === 'function') { + server.closeAllConnections() + } + server.close(resolve) + }) + } +} + function startServer (t, handler) { return new Promise(resolve => { const server = createServer(handler) @@ -10,7 +21,7 @@ function startServer (t, handler) { resolve(`localhost:${server.address().port}`) }) - t.teardown(server.close.bind(server)) + t.teardown(close(server)) }) }