Skip to content

Commit 8a636d0

Browse files
authored
feat(ext/fetch): Request.bytes() and Response.bytes() (#23823)
Closes #23790
1 parent f5d0c4b commit 8a636d0

File tree

13 files changed

+75
-48
lines changed

13 files changed

+75
-48
lines changed

cli/tsc/dts/lib.dom.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3156,6 +3156,8 @@ interface Body {
31563156
arrayBuffer(): Promise<ArrayBuffer>;
31573157
/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/blob) */
31583158
blob(): Promise<Blob>;
3159+
/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/bytes) */
3160+
bytes(): Promise<Uint8Array>;
31593161
/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/formData) */
31603162
formData(): Promise<FormData>;
31613163
/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/json) */

cli/tsc/dts/lib.webworker.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1029,6 +1029,8 @@ interface Body {
10291029
arrayBuffer(): Promise<ArrayBuffer>;
10301030
/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/blob) */
10311031
blob(): Promise<Blob>;
1032+
/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/bytes) */
1033+
bytes(): Promise<Uint8Array>;
10321034
/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/formData) */
10331035
formData(): Promise<FormData>;
10341036
/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/json) */

ext/fetch/22_body.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,15 @@ function mixinBody(prototype, bodySymbol, mimeTypeSymbol) {
296296
configurable: true,
297297
enumerable: true,
298298
},
299+
bytes: {
300+
/** @returns {Promise<Uint8Array>} */
301+
value: function bytes() {
302+
return consumeBody(this, "bytes");
303+
},
304+
writable: true,
305+
configurable: true,
306+
enumerable: true,
307+
},
299308
formData: {
300309
/** @returns {Promise<FormData>} */
301310
value: function formData() {
@@ -330,7 +339,7 @@ function mixinBody(prototype, bodySymbol, mimeTypeSymbol) {
330339
/**
331340
* https://fetch.spec.whatwg.org/#concept-body-package-data
332341
* @param {Uint8Array | string} bytes
333-
* @param {"ArrayBuffer" | "Blob" | "FormData" | "JSON" | "text"} type
342+
* @param {"ArrayBuffer" | "Blob" | "FormData" | "JSON" | "text" | "bytes"} type
334343
* @param {MimeType | null} [mimeType]
335344
*/
336345
function packageData(bytes, type, mimeType) {
@@ -341,6 +350,8 @@ function packageData(bytes, type, mimeType) {
341350
return new Blob([bytes], {
342351
type: mimeType !== null ? mimesniff.serializeMimeType(mimeType) : "",
343352
});
353+
case "bytes":
354+
return chunkToU8(bytes);
344355
case "FormData": {
345356
if (mimeType !== null) {
346357
const essence = mimesniff.essence(mimeType);

ext/fetch/lib.deno_fetch.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ declare interface Body {
5858
* that resolves with a `Blob`.
5959
*/
6060
blob(): Promise<Blob>;
61+
/** Takes a `Response` stream and reads it to completion. It returns a promise
62+
* that resolves with a `Uint8Array`.
63+
*/
64+
bytes(): Promise<Uint8Array>;
6165
/** Takes a `Response` stream and reads it to completion. It returns a promise
6266
* that resolves with a `FormData` object.
6367
*/

tests/specs/run/045_proxy/proxy_test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ async function handler(req: Request): Promise<Response> {
2323
method: req.method,
2424
headers: headers,
2525
});
26-
return new Response(new Uint8Array(await resp.arrayBuffer()), {
26+
return new Response(await resp.bytes(), {
2727
status: resp.status,
2828
headers: resp.headers,
2929
});

tests/testdata/fmt/with_config/subdir/a.ts

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,11 @@ Deno.test(
2222
.statusText,
2323
)
2424
const u8a =
25-
new Uint8Array(
26-
await response
27-
.arrayBuffer(),
28-
)
25+
await response
26+
.bytes()
2927
const u8a1 =
30-
new Uint8Array(
31-
await response1
32-
.arrayBuffer(),
33-
)
28+
await response1
29+
.bytes()
3430
for (
3531
let i = 0;
3632
i <

tests/unit/fetch_test.ts

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -243,8 +243,8 @@ Deno.test({ permissions: { net: true } }, async function responseClone() {
243243
assert(response !== response1);
244244
assertEquals(response.status, response1.status);
245245
assertEquals(response.statusText, response1.statusText);
246-
const u8a = new Uint8Array(await response.arrayBuffer());
247-
const u8a1 = new Uint8Array(await response1.arrayBuffer());
246+
const u8a = await response.bytes();
247+
const u8a1 = await response1.bytes();
248248
for (let i = 0; i < u8a.byteLength; i++) {
249249
assertEquals(u8a[i], u8a1[i]);
250250
}
@@ -675,7 +675,7 @@ Deno.test(
675675
["Foo", "Bar"],
676676
],
677677
});
678-
await response.arrayBuffer();
678+
await response.body?.cancel();
679679
assertEquals(response.status, 404);
680680
assertEquals(response.headers.get("Content-Length"), "2");
681681

@@ -709,7 +709,7 @@ Deno.test(
709709
["Accept-Language", "en-US"],
710710
],
711711
});
712-
await response.arrayBuffer();
712+
await response.body?.cancel();
713713
assertEquals(response.status, 404);
714714
assertEquals(response.headers.get("Content-Length"), "2");
715715

@@ -743,7 +743,7 @@ Deno.test(
743743
],
744744
body,
745745
});
746-
await response.arrayBuffer();
746+
await response.body?.cancel();
747747
assertEquals(response.status, 404);
748748
assertEquals(response.headers.get("Content-Length"), "2");
749749

@@ -782,7 +782,7 @@ Deno.test(
782782
],
783783
body,
784784
});
785-
await response.arrayBuffer();
785+
await response.body?.cancel();
786786
assertEquals(response.status, 404);
787787
assertEquals(response.headers.get("Content-Length"), "2");
788788

@@ -816,7 +816,7 @@ Deno.test(
816816
["Content-Length", "10"],
817817
],
818818
});
819-
await response.arrayBuffer();
819+
await response.body?.cancel();
820820
assertEquals(response.status, 404);
821821
assertEquals(response.headers.get("Content-Length"), "2");
822822

@@ -847,7 +847,7 @@ Deno.test(
847847
["Transfer-Encoding", "chunked"],
848848
],
849849
});
850-
await response.arrayBuffer();
850+
await response.body?.cancel();
851851
assertEquals(response.status, 404);
852852
assertEquals(response.headers.get("Content-Length"), "2");
853853

@@ -933,7 +933,7 @@ Deno.test(function responseRedirectTakeURLObjectAsParameter() {
933933

934934
Deno.test(async function responseWithoutBody() {
935935
const response = new Response();
936-
assertEquals(await response.arrayBuffer(), new ArrayBuffer(0));
936+
assertEquals(await response.bytes(), new Uint8Array(0));
937937
const blob = await response.blob();
938938
assertEquals(blob.size, 0);
939939
assertEquals(await blob.arrayBuffer(), new ArrayBuffer(0));
@@ -1214,7 +1214,7 @@ Deno.test(
12141214
],
12151215
body: stream.readable,
12161216
});
1217-
await response.arrayBuffer();
1217+
await response.body?.cancel();
12181218
assertEquals(response.status, 404);
12191219
assertEquals(response.headers.get("Content-Length"), "2");
12201220

@@ -1793,10 +1793,9 @@ Deno.test(
17931793
const listener = invalidServer(addr, body);
17941794
const response = await fetch(`http://${addr}/`);
17951795

1796-
const res = await response.arrayBuffer();
1796+
const res = await response.bytes();
17971797
const buf = new TextEncoder().encode(data);
1798-
assertEquals(res.byteLength, buf.byteLength);
1799-
assertEquals(new Uint8Array(res), buf);
1798+
assertEquals(res, buf);
18001799

18011800
listener.close();
18021801
},
@@ -1850,10 +1849,10 @@ Deno.test(
18501849

18511850
// If content-length < totalLength, a maximum of content-length bytes
18521851
// should be returned.
1853-
const res = await response.arrayBuffer();
1852+
const res = await response.bytes();
18541853
const buf = new TextEncoder().encode(data);
18551854
assertEquals(res.byteLength, contentLength);
1856-
assertEquals(new Uint8Array(res), buf.subarray(contentLength));
1855+
assertEquals(res, buf.subarray(contentLength));
18571856

18581857
listener.close();
18591858
},
@@ -2029,15 +2028,15 @@ Deno.test(
20292028
Deno.test("Request with subarray TypedArray body", async () => {
20302029
const body = new Uint8Array([1, 2, 3, 4, 5]).subarray(1);
20312030
const req = new Request("https://example.com", { method: "POST", body });
2032-
const actual = new Uint8Array(await req.arrayBuffer());
2031+
const actual = await req.bytes();
20332032
const expected = new Uint8Array([2, 3, 4, 5]);
20342033
assertEquals(actual, expected);
20352034
});
20362035

20372036
Deno.test("Response with subarray TypedArray body", async () => {
20382037
const body = new Uint8Array([1, 2, 3, 4, 5]).subarray(1);
20392038
const req = new Response(body);
2040-
const actual = new Uint8Array(await req.arrayBuffer());
2039+
const actual = await req.bytes();
20412040
const expected = new Uint8Array([2, 3, 4, 5]);
20422041
assertEquals(actual, expected);
20432042
});

tests/unit/http_test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ Deno.test(
239239
headers: { "connection": "close" },
240240
});
241241

242-
await resp.arrayBuffer();
242+
await resp.body?.cancel();
243243
await promise;
244244
},
245245
);
@@ -963,7 +963,7 @@ Deno.test(
963963
await respondWith(new Response(f.readable, { status: 200 }));
964964
})();
965965
const resp = await fetch(`http://127.0.0.1:${listenPort}/`);
966-
const body = await resp.arrayBuffer();
966+
const body = await resp.bytes();
967967
assertEquals(body.byteLength, 70 * 1024);
968968
await promise;
969969
httpConn!.close();
@@ -1293,8 +1293,8 @@ Deno.test(
12931293

12941294
const resp = await fetch(`http://localhost:${listenPort}/`);
12951295
assertEquals(resp.status, 200);
1296-
const body = await resp.arrayBuffer();
1297-
assertEquals(new Uint8Array(body), new Uint8Array([128]));
1296+
const body = await resp.bytes();
1297+
assertEquals(body, new Uint8Array([128]));
12981298

12991299
await promise;
13001300
httpConn!.close();

tests/unit/serve_test.ts

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,7 @@ Deno.test(
340340
});
341341

342342
const resp = await fetch(`http://localhost:${servePort}`);
343-
dataPromise = resp.arrayBuffer();
343+
dataPromise = resp.bytes();
344344
}
345345

346346
assertEquals((await dataPromise).byteLength, 1048576);
@@ -358,7 +358,7 @@ Deno.test(
358358

359359
const [_, data] = await Promise.all([
360360
server.shutdown(),
361-
resp.arrayBuffer(),
361+
resp.bytes(),
362362
]);
363363

364364
assertEquals(data.byteLength, 1048576);
@@ -1861,13 +1861,12 @@ Deno.test(
18611861
signal: ac.signal,
18621862
});
18631863
const response = await fetch(`http://localhost:${servePort}/`);
1864-
const body = await response.arrayBuffer();
1864+
const body = await response.bytes();
18651865
assertEquals(1024 * 1024, body.byteLength);
1866-
const buffer = new Uint8Array(body);
18671866
for (let i = 0; i < 256; i++) {
18681867
assertEquals(
18691868
i,
1870-
buffer[i * 4096],
1869+
body[i * 4096],
18711870
`sentinel mismatch at index ${i * 4096}`,
18721871
);
18731872
}
@@ -2078,8 +2077,8 @@ Deno.test(
20782077
await deferred.promise;
20792078

20802079
assertEquals(resp.status, 200);
2081-
const body = await resp.arrayBuffer();
2082-
assertEquals(new Uint8Array(body), new Uint8Array([128]));
2080+
const body = await resp.bytes();
2081+
assertEquals(body, new Uint8Array([128]));
20832082

20842083
ac.abort();
20852084
await server.finished;
@@ -2694,7 +2693,7 @@ for (const testCase of compressionTestCases) {
26942693
headers: testCase.in as HeadersInit,
26952694
});
26962695
await deferred.promise;
2697-
const body = await resp.arrayBuffer();
2696+
const body = await resp.bytes();
26982697
if (testCase.expect == null) {
26992698
assertEquals(body.byteLength, testCase.length);
27002699
assertEquals(
@@ -2731,7 +2730,7 @@ Deno.test(
27312730
const server = Deno.serve({
27322731
handler: async (request) => {
27332732
assertEquals(
2734-
new Uint8Array(await request.arrayBuffer()),
2733+
await request.bytes(),
27352734
makeTempData(70 * 1024),
27362735
);
27372736
deferred.resolve();

tests/unit/worker_test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -689,7 +689,7 @@ Deno.test({
689689

690690
assert(worker);
691691
const response = await fetch("http://localhost:4506");
692-
assert(await response.arrayBuffer());
692+
assert(await response.bytes());
693693
worker.terminate();
694694
},
695695
});

tests/unit_node/http_test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ Deno.test("[node/http] server can respond with 101, 204, 205, 304 status", async
174174
// deno-lint-ignore no-explicit-any
175175
`http://127.0.0.1:${(server.address() as any).port}/`,
176176
);
177-
await res.arrayBuffer();
177+
await res.body?.cancel();
178178
assertEquals(res.status, status);
179179
server.close(() => resolve());
180180
});

tests/wpt/runner/expectation.json

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7153,6 +7153,12 @@
71537153
"response": {
71547154
"json.any.html": true,
71557155
"json.any.worker.html": true,
7156+
"response-blob-realm.any.html": [
7157+
"realm of the Uint8Array from Response bytes()"
7158+
],
7159+
"response-blob-realm.any.worker.html": [
7160+
"realm of the Uint8Array from Response bytes()"
7161+
],
71567162
"response-init-001.any.html": true,
71577163
"response-init-001.any.worker.html": true,
71587164
"response-init-002.any.html": true,
@@ -8148,7 +8154,11 @@
81488154
"HTTP/1.1 200 ",
81498155
"HTTP/1.1 999 DOES IT MATTER "
81508156
],
8151-
"resources-with-0x00-in-header.window.html": false
8157+
"resources-with-0x00-in-header.window.html": [
8158+
"Expect network error for script with 0x00 in a header",
8159+
"Expect network error for frame navigation to resource with 0x00 in a header",
8160+
"Expect network error for image with 0x00 in a header"
8161+
]
81528162
},
81538163
"range": {
81548164
"general.any.html": [
@@ -12825,8 +12835,6 @@
1282512835
"eventsource-onopen.any.worker.html": true,
1282612836
"eventsource-prototype.any.html": true,
1282712837
"eventsource-prototype.any.worker.html": true,
12828-
"eventsource-request-cancellation.window.any.html": false,
12829-
"eventsource-request-cancellation.window.any.worker.html": false,
1283012838
"eventsource-url.any.html": true,
1283112839
"eventsource-url.any.worker.html": true,
1283212840
"format-bom-2.any.html": true,
@@ -12883,6 +12891,12 @@
1288312891
"eventsource-constructor-stringify.window.html": false,
1288412892
"eventsource-cross-origin.window.html": false,
1288512893
"eventsource-reconnect.window.html": false,
12886-
"request-status-error.window.html": false
12894+
"request-status-error.window.html": false,
12895+
"eventsource-constructor-empty-url.any.serviceworker.html": false,
12896+
"eventsource-constructor-empty-url.any.sharedworker.html": false,
12897+
"eventsource-constructor-url-bogus.any.serviceworker.html": false,
12898+
"eventsource-constructor-url-bogus.any.sharedworker.html": false,
12899+
"request-credentials.window.html": false,
12900+
"request-redirect.window.html": false
1288712901
}
12888-
}
12902+
}

tests/wpt/suite

Submodule suite updated 462 files

0 commit comments

Comments
 (0)