Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement BodyReadable.bytes #3391

Merged
merged 3 commits into from
Jul 6, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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[0])
}
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(new TextEncoder().encode(JSON.stringify(obj)), bytes)
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
Loading