Skip to content

Commit

Permalink
feat: implement BodyReadable.bytes
Browse files Browse the repository at this point in the history
  • Loading branch information
tsctx committed Jul 3, 2024
1 parent 4b0921c commit 952d8ef
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 9 deletions.
42 changes: 33 additions & 9 deletions lib/api/readable.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,11 @@ class BodyReadable extends Readable {
return consume(this, 'blob')
}

// https://fetch.spec.whatwg.org/#dom-body-bytes
async bytes () {
return consume(this, 'bytes')
}

// https://fetch.spec.whatwg.org/#dom-body-arraybuffer
async arrayBuffer () {
return consume(this, 'arrayBuffer')
Expand Down Expand Up @@ -308,6 +313,31 @@ function chunksDecode (chunks, length) {
return buffer.utf8Slice(start, bufferLength)
}

/**
* @param {Buffer[]} chunks
* @param {number} length
* @returns {Uint8Array}
*/
function chunksConcat (chunks, length) {
if (chunks.length === 0 || length === 0) {
return new Uint8Array(0)
}
if (chunks.length === 1) {
// fast-path
return new Uint8Array(chunks[1])
}
const buffer = new Uint8Array(length)

let offset = 0
for (let i = 0; i < chunks.length; ++i) {
const chunk = chunks[i]
buffer.set(chunk, offset)
offset += chunk.length
}

return buffer
}

function consumeEnd (consume) {
const { type, body, resolve, stream, length } = consume

Expand All @@ -317,17 +347,11 @@ function consumeEnd (consume) {
} else if (type === 'json') {
resolve(JSON.parse(chunksDecode(body, length)))
} else if (type === 'arrayBuffer') {
const dst = new Uint8Array(length)

let pos = 0
for (const buf of body) {
dst.set(buf, pos)
pos += buf.byteLength
}

resolve(dst.buffer)
resolve(chunksConcat(body, length).buffer)
} else if (type === 'blob') {
resolve(new Blob(body, { type: stream[kContentType] }))
} else if (type === 'bytes') {
resolve(chunksConcat(body, length))
}

consumeFinish(consume)
Expand Down
26 changes: 26 additions & 0 deletions test/client-request.js
Original file line number Diff line number Diff line change
Expand Up @@ -655,6 +655,32 @@ test('request arrayBuffer', async (t) => {
await t.completed
})

test('request bytes', async (t) => {
t = tspl(t, { plan: 2 })

const obj = { asd: true }
const server = createServer((req, res) => {
res.end(JSON.stringify(obj))
})
after(() => server.close())

server.listen(0, async () => {
const client = new Client(`http://localhost:${server.address().port}`)
after(() => client.destroy())

const { body } = await client.request({
path: '/',
method: 'GET'
})
const bytes = await body.bytes()

t.deepStrictEqual(Buffer.from(JSON.stringify(obj)), bytes)

Check failure on line 677 in test/client-request.js

View workflow job for this annotation

GitHub Actions / test (21, ubuntu-latest) / Test with Node.js 21 on ubuntu-latest

request bytes

Error [ERR_TEST_FAILURE]: Expected values to be strictly deep-equal: + actual - expected + Buffer(12) [Uint8Array] [ + 123, + 34, + 97, + 115, + 100, + 34, + 58, + 116, + 114, + 117, + 101, + 125 + ] - Uint8Array(0) [] at process.emit (node:events:519:28) { code: 'ERR_TEST_FAILURE', failureType: 'unhandledRejection', cause: AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal: + actual - expected + Buffer(12) [Uint8Array] [ + 123, + 34, + 97, + 115, + 100, + 34, + 58, + 116, + 114, + 117, + 101, + 125 + ] - Uint8Array(0) [] at res.<computed> [as deepStrictEqual] (/home/runner/work/undici/undici/node_modules/@matteo.collina/tspl/tspl.js:52:35) at Server.<anonymous> (/home/runner/work/undici/undici/test/client-request.js:677:7) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) { generatedMessage: true, code: 'ERR_ASSERTION', actual: <Buffer 7b 22 61 73 64 22 3a 74 72 75 65 7d>, expected: Uint8Array(0) [], operator: 'deepStrictEqual' } }

Check failure on line 677 in test/client-request.js

View workflow job for this annotation

GitHub Actions / test (22, ubuntu-latest) / Test with Node.js 22 on ubuntu-latest

request bytes

Error [ERR_TEST_FAILURE]: Expected values to be strictly deep-equal: + actual - expected + Buffer(12) [Uint8Array] [ + 123, + 34, + 97, + 115, + 100, + 34, + 58, + 116, + 114, + 117, + 101, + 125 + ] - Uint8Array(0) [] at process.emit (node:events:520:28) { code: 'ERR_TEST_FAILURE', failureType: 'unhandledRejection', cause: AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal: + actual - expected + Buffer(12) [Uint8Array] [ + 123, + 34, + 97, + 115, + 100, + 34, + 58, + 116, + 114, + 117, + 101, + 125 + ] - Uint8Array(0) [] at res.<computed> [as deepStrictEqual] (/home/runner/work/undici/undici/node_modules/@matteo.collina/tspl/tspl.js:52:35) at Server.<anonymous> (/home/runner/work/undici/undici/test/client-request.js:677:7) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) { generatedMessage: true, code: 'ERR_ASSERTION', actual: <Buffer 7b 22 61 73 64 22 3a 74 72 75 65 7d>, expected: Uint8Array(0) [], operator: 'deepStrictEqual' } }

Check failure on line 677 in test/client-request.js

View workflow job for this annotation

GitHub Actions / test (20, ubuntu-latest) / Test with Node.js 20 on ubuntu-latest

request bytes

Error [ERR_TEST_FAILURE]: Expected values to be strictly deep-equal: + actual - expected + Buffer(12) [Uint8Array] [ + 123, + 34, + 97, + 115, + 100, + 34, + 58, + 116, + 114, + 117, + 101, + 125 + ] - Uint8Array(0) [] at process.emit (node:events:519:28) { code: 'ERR_TEST_FAILURE', failureType: 'unhandledRejection', cause: AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal: + actual - expected + Buffer(12) [Uint8Array] [ + 123, + 34, + 97, + 115, + 100, + 34, + 58, + 116, + 114, + 117, + 101, + 125 + ] - Uint8Array(0) [] at res.<computed> [as deepStrictEqual] (/home/runner/work/undici/undici/node_modules/@matteo.collina/tspl/tspl.js:52:35) at Server.<anonymous> (/home/runner/work/undici/undici/test/client-request.js:677:7) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) { generatedMessage: true, code: 'ERR_ASSERTION', actual: <Buffer 7b 22 61 73 64 22 3a 74 72 75 65 7d>, expected: Uint8Array(0) [], operator: 'deepStrictEqual' } }

Check failure on line 677 in test/client-request.js

View workflow job for this annotation

GitHub Actions / test (18, ubuntu-latest) / Test with Node.js 18 on ubuntu-latest

request bytes

Error [ERR_TEST_FAILURE]: Expected values to be strictly deep-equal: + actual - expected + Buffer(12) [Uint8Array] [ + 123, + 34, + 97, + 115, + 100, + 34, + 58, + 116, + 114, + 117, + 101, + 125 + ] - Uint8Array(0) [] at process.emit (node:events:517:28) { failureType: 'unhandledRejection', cause: AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal: + actual - expected + Buffer(12) [Uint8Array] [ + 123, + 34, + 97, + 115, + 100, + 34, + 58, + 116, + 114, + 117, + 101, + 125 + ] - Uint8Array(0) [] at res.<computed> [as deepStrictEqual] (/home/runner/work/undici/undici/node_modules/@matteo.collina/tspl/tspl.js:52:35) at Server.<anonymous> (/home/runner/work/undici/undici/test/client-request.js:677:7) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) { generatedMessage: true, code: 'ERR_ASSERTION', actual: <Buffer 7b 22 61 73 64 22 3a 74 72 75 65 7d>, expected: Uint8Array(0) [], operator: 'deepStrictEqual' }, code: 'ERR_TEST_FAILURE' }

Check failure on line 677 in test/client-request.js

View workflow job for this annotation

GitHub Actions / test (20, macos-latest) / Test with Node.js 20 on macos-latest

request bytes

Error [ERR_TEST_FAILURE]: Expected values to be strictly deep-equal: + actual - expected + Buffer(12) [Uint8Array] [ + 123, + 34, + 97, + 115, + 100, + 34, + 58, + 116, + 114, + 117, + 101, + 125 + ] - Uint8Array(0) [] at process.emit (node:events:519:28) { code: 'ERR_TEST_FAILURE', failureType: 'unhandledRejection', cause: AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal: + actual - expected + Buffer(12) [Uint8Array] [ + 123, + 34, + 97, + 115, + 100, + 34, + 58, + 116, + 114, + 117, + 101, + 125 + ] - Uint8Array(0) [] at res.<computed> [as deepStrictEqual] (/Users/runner/work/undici/undici/node_modules/@matteo.collina/tspl/tspl.js:52:35) at Server.<anonymous> (/Users/runner/work/undici/undici/test/client-request.js:677:7) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) { generatedMessage: true, code: 'ERR_ASSERTION', actual: <Buffer 7b 22 61 73 64 22 3a 74 72 75 65 7d>, expected: Uint8Array(0) [], operator: 'deepStrictEqual' } }

Check failure on line 677 in test/client-request.js

View workflow job for this annotation

GitHub Actions / test (22, macos-latest) / Test with Node.js 22 on macos-latest

request bytes

Error [ERR_TEST_FAILURE]: Expected values to be strictly deep-equal: + actual - expected + Buffer(12) [Uint8Array] [ + 123, + 34, + 97, + 115, + 100, + 34, + 58, + 116, + 114, + 117, + 101, + 125 + ] - Uint8Array(0) [] at process.emit (node:events:520:28) { code: 'ERR_TEST_FAILURE', failureType: 'unhandledRejection', cause: AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal: + actual - expected + Buffer(12) [Uint8Array] [ + 123, + 34, + 97, + 115, + 100, + 34, + 58, + 116, + 114, + 117, + 101, + 125 + ] - Uint8Array(0) [] at res.<computed> [as deepStrictEqual] (/Users/runner/work/undici/undici/node_modules/@matteo.collina/tspl/tspl.js:52:35) at Server.<anonymous> (/Users/runner/work/undici/undici/test/client-request.js:677:7) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) { generatedMessage: true, code: 'ERR_ASSERTION', actual: <Buffer 7b 22 61 73 64 22 3a 74 72 75 65 7d>, expected: Uint8Array(0) [], operator: 'deepStrictEqual' } }

Check failure on line 677 in test/client-request.js

View workflow job for this annotation

GitHub Actions / test (21, macos-latest) / Test with Node.js 21 on macos-latest

request bytes

Error [ERR_TEST_FAILURE]: Expected values to be strictly deep-equal: + actual - expected + Buffer(12) [Uint8Array] [ + 123, + 34, + 97, + 115, + 100, + 34, + 58, + 116, + 114, + 117, + 101, + 125 + ] - Uint8Array(0) [] at process.emit (node:events:519:28) { code: 'ERR_TEST_FAILURE', failureType: 'unhandledRejection', cause: AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal: + actual - expected + Buffer(12) [Uint8Array] [ + 123, + 34, + 97, + 115, + 100, + 34, + 58, + 116, + 114, + 117, + 101, + 125 + ] - Uint8Array(0) [] at res.<computed> [as deepStrictEqual] (/Users/runner/work/undici/undici/node_modules/@matteo.collina/tspl/tspl.js:52:35) at Server.<anonymous> (/Users/runner/work/undici/undici/test/client-request.js:677:7) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) { generatedMessage: true, code: 'ERR_ASSERTION', actual: <Buffer 7b 22 61 73 64 22 3a 74 72 75 65 7d>, expected: Uint8Array(0) [], operator: 'deepStrictEqual' } }

Check failure on line 677 in test/client-request.js

View workflow job for this annotation

GitHub Actions / test (18, macos-latest) / Test with Node.js 18 on macos-latest

request bytes

Error [ERR_TEST_FAILURE]: Expected values to be strictly deep-equal: + actual - expected + Buffer(12) [Uint8Array] [ + 123, + 34, + 97, + 115, + 100, + 34, + 58, + 116, + 114, + 117, + 101, + 125 + ] - Uint8Array(0) [] at process.emit (node:events:517:28) { failureType: 'unhandledRejection', cause: AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal: + actual - expected + Buffer(12) [Uint8Array] [ + 123, + 34, + 97, + 115, + 100, + 34, + 58, + 116, + 114, + 117, + 101, + 125 + ] - Uint8Array(0) [] at res.<computed> [as deepStrictEqual] (/Users/runner/work/undici/undici/node_modules/@matteo.collina/tspl/tspl.js:52:35) at Server.<anonymous> (/Users/runner/work/undici/undici/test/client-request.js:677:7) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) { generatedMessage: true, code: 'ERR_ASSERTION', actual: <Buffer 7b 22 61 73 64 22 3a 74 72 75 65 7d>, expected: Uint8Array(0) [], operator: 'deepStrictEqual' }, code: 'ERR_TEST_FAILURE' }

Check failure on line 677 in test/client-request.js

View workflow job for this annotation

GitHub Actions / Test with Node.js 20 compiled --without-intl

request bytes

Error [ERR_TEST_FAILURE]: Expected values to be strictly deep-equal: + actual - expected + Buffer(12) [Uint8Array] [ + 123, + 34, + 97, + 115, + 100, + 34, + 58, + 116, + 114, + 117, + 101, + 125 + ] - Uint8Array(0) [] at process.emit (node:events:519:28) { code: 'ERR_TEST_FAILURE', failureType: 'unhandledRejection', cause: AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal: + actual - expected + Buffer(12) [Uint8Array] [ + 123, + 34, + 97, + 115, + 100, + 34, + 58, + 116, + 114, + 117, + 101, + 125 + ] - Uint8Array(0) [] at res.<computed> [as deepStrictEqual] (/home/runner/work/undici/undici/node_modules/@matteo.collina/tspl/tspl.js:52:35) at Server.<anonymous> (/home/runner/work/undici/undici/test/client-request.js:677:7) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) { generatedMessage: true, code: 'ERR_ASSERTION', actual: <Buffer 7b 22 61 73 64 22 3a 74 72 75 65 7d>, expected: Uint8Array(0) [], operator: 'deepStrictEqual' } }

Check failure on line 677 in test/client-request.js

View workflow job for this annotation

GitHub Actions / Test with Node.js 21 compiled --without-intl

request bytes

Error [ERR_TEST_FAILURE]: Expected values to be strictly deep-equal: + actual - expected + Buffer(12) [Uint8Array] [ + 123, + 34, + 97, + 115, + 100, + 34, + 58, + 116, + 114, + 117, + 101, + 125 + ] - Uint8Array(0) [] at process.emit (node:events:519:28) { code: 'ERR_TEST_FAILURE', failureType: 'unhandledRejection', cause: AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal: + actual - expected + Buffer(12) [Uint8Array] [ + 123, + 34, + 97, + 115, + 100, + 34, + 58, + 116, + 114, + 117, + 101, + 125 + ] - Uint8Array(0) [] at res.<computed> [as deepStrictEqual] (/home/runner/work/undici/undici/node_modules/@matteo.collina/tspl/tspl.js:52:35) at Server.<anonymous> (/home/runner/work/undici/undici/test/client-request.js:677:7) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) { generatedMessage: true, code: 'ERR_ASSERTION', actual: <Buffer 7b 22 61 73 64 22 3a 74 72 75 65 7d>, expected: Uint8Array(0) [], operator: 'deepStrictEqual' } }

Check failure on line 677 in test/client-request.js

View workflow job for this annotation

GitHub Actions / Test with Node.js 22 compiled --without-intl

request bytes

Error [ERR_TEST_FAILURE]: Expected values to be strictly deep-equal: + actual - expected + Buffer(12) [Uint8Array] [ + 123, + 34, + 97, + 115, + 100, + 34, + 58, + 116, + 114, + 117, + 101, + 125 + ] - Uint8Array(0) [] at process.emit (node:events:520:28) { code: 'ERR_TEST_FAILURE', failureType: 'unhandledRejection', cause: AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal: + actual - expected + Buffer(12) [Uint8Array] [ + 123, + 34, + 97, + 115, + 100, + 34, + 58, + 116, + 114, + 117, + 101, + 125 + ] - Uint8Array(0) [] at res.<computed> [as deepStrictEqual] (/home/runner/work/undici/undici/node_modules/@matteo.collina/tspl/tspl.js:52:35) at Server.<anonymous> (/home/runner/work/undici/undici/test/client-request.js:677:7) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) { generatedMessage: true, code: 'ERR_ASSERTION', actual: <Buffer 7b 22 61 73 64 22 3a 74 72 75 65 7d>, expected: Uint8Array(0) [], operator: 'deepStrictEqual' } }
t.ok(bytes instanceof Uint8Array)
})

await t.completed
})

test('request body', async (t) => {
t = tspl(t, { plan: 1 })

Expand Down
3 changes: 3 additions & 0 deletions test/types/readable.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ expectAssignable<BodyReadable>(new BodyReadable())
// blob
expectAssignable<Promise<Blob>>(readable.blob())

// bytes
expectAssignable<Promise<Uint8Array>>(readable.bytes())

// arrayBuffer
expectAssignable<Promise<ArrayBuffer>>(readable.arrayBuffer())

Expand Down
1 change: 1 addition & 0 deletions types/dispatcher.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ declare namespace Dispatcher {
readonly bodyUsed: boolean;
arrayBuffer(): Promise<ArrayBuffer>;
blob(): Promise<Blob>;
bytes(): Promise<Uint8Array>;
formData(): Promise<never>;
json(): Promise<unknown>;
text(): Promise<string>;
Expand Down
5 changes: 5 additions & 0 deletions types/readable.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ declare class BodyReadable extends Readable {
*/
blob(): Promise<Blob>

/** Consumes and returns the body as an Uint8Array
* https://fetch.spec.whatwg.org/#dom-body-bytes
*/
bytes(): Promise<Uint8Array>

/** Consumes and returns the body as an ArrayBuffer
* https://fetch.spec.whatwg.org/#dom-body-arraybuffer
*/
Expand Down

0 comments on commit 952d8ef

Please sign in to comment.