summaryrefslogtreecommitdiff
path: root/cli/tests/unit/fetch_test.ts
diff options
context:
space:
mode:
Diffstat (limited to 'cli/tests/unit/fetch_test.ts')
-rw-r--r--cli/tests/unit/fetch_test.ts2071
1 files changed, 0 insertions, 2071 deletions
diff --git a/cli/tests/unit/fetch_test.ts b/cli/tests/unit/fetch_test.ts
deleted file mode 100644
index 84e94de0d..000000000
--- a/cli/tests/unit/fetch_test.ts
+++ /dev/null
@@ -1,2071 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import {
- assert,
- assertEquals,
- assertRejects,
- assertThrows,
- delay,
- fail,
- unimplemented,
-} from "./test_util.ts";
-import { Buffer } from "@test_util/std/io/buffer.ts";
-
-const listenPort = 4506;
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchRequiresOneArgument() {
- await assertRejects(
- fetch as unknown as () => Promise<void>,
- TypeError,
- );
- },
-);
-
-Deno.test({ permissions: { net: true } }, async function fetchProtocolError() {
- await assertRejects(
- async () => {
- await fetch("ftp://localhost:21/a/file");
- },
- TypeError,
- "not supported",
- );
-});
-
-function findClosedPortInRange(
- minPort: number,
- maxPort: number,
-): number | never {
- let port = minPort;
-
- // If we hit the return statement of this loop
- // that means that we did not throw an
- // AddrInUse error when we executed Deno.listen.
- while (port < maxPort) {
- try {
- const listener = Deno.listen({ port });
- listener.close();
- return port;
- } catch (_e) {
- port++;
- }
- }
-
- unimplemented(
- `No available ports between ${minPort} and ${maxPort} to test fetch`,
- );
-}
-
-Deno.test(
- // TODO(bartlomieju): reenable this test
- // https://github.com/denoland/deno/issues/18350
- { ignore: Deno.build.os === "windows", permissions: { net: true } },
- async function fetchConnectionError() {
- const port = findClosedPortInRange(4000, 9999);
- await assertRejects(
- async () => {
- await fetch(`http://localhost:${port}`);
- },
- TypeError,
- "error trying to connect",
- );
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchDnsError() {
- await assertRejects(
- async () => {
- await fetch("http://nil/");
- },
- TypeError,
- "error trying to connect",
- );
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchInvalidUriError() {
- await assertRejects(
- async () => {
- await fetch("http://<invalid>/");
- },
- TypeError,
- );
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchMalformedUriError() {
- await assertRejects(
- async () => {
- const url = new URL("http://{{google/");
- await fetch(url);
- },
- TypeError,
- );
- },
-);
-
-Deno.test({ permissions: { net: true } }, async function fetchJsonSuccess() {
- const response = await fetch("http://localhost:4545/assets/fixture.json");
- const json = await response.json();
- assertEquals(json.name, "deno");
-});
-
-Deno.test({ permissions: { net: false } }, async function fetchPerm() {
- await assertRejects(async () => {
- await fetch("http://localhost:4545/assets/fixture.json");
- }, Deno.errors.PermissionDenied);
-});
-
-Deno.test({ permissions: { net: true } }, async function fetchUrl() {
- const response = await fetch("http://localhost:4545/assets/fixture.json");
- assertEquals(response.url, "http://localhost:4545/assets/fixture.json");
- const _json = await response.json();
-});
-
-Deno.test({ permissions: { net: true } }, async function fetchURL() {
- const response = await fetch(
- new URL("http://localhost:4545/assets/fixture.json"),
- );
- assertEquals(response.url, "http://localhost:4545/assets/fixture.json");
- const _json = await response.json();
-});
-
-Deno.test({ permissions: { net: true } }, async function fetchHeaders() {
- const response = await fetch("http://localhost:4545/assets/fixture.json");
- const headers = response.headers;
- assertEquals(headers.get("Content-Type"), "application/json");
- const _json = await response.json();
-});
-
-Deno.test({ permissions: { net: true } }, async function fetchBlob() {
- const response = await fetch("http://localhost:4545/assets/fixture.json");
- const headers = response.headers;
- const blob = await response.blob();
- assertEquals(blob.type, headers.get("Content-Type"));
- assertEquals(blob.size, Number(headers.get("Content-Length")));
-});
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchBodyUsedReader() {
- const response = await fetch(
- "http://localhost:4545/assets/fixture.json",
- );
- assert(response.body !== null);
-
- const reader = response.body.getReader();
- // Getting a reader should lock the stream but does not consume the body
- // so bodyUsed should not be true
- assertEquals(response.bodyUsed, false);
- reader.releaseLock();
- await response.json();
- assertEquals(response.bodyUsed, true);
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchBodyUsedCancelStream() {
- const response = await fetch(
- "http://localhost:4545/assets/fixture.json",
- );
- assert(response.body !== null);
-
- assertEquals(response.bodyUsed, false);
- const promise = response.body.cancel();
- assertEquals(response.bodyUsed, true);
- await promise;
- },
-);
-
-Deno.test({ permissions: { net: true } }, async function fetchAsyncIterator() {
- const response = await fetch("http://localhost:4545/assets/fixture.json");
- const headers = response.headers;
-
- assert(response.body !== null);
- let total = 0;
- for await (const chunk of response.body) {
- assert(chunk instanceof Uint8Array);
- total += chunk.length;
- }
-
- assertEquals(total, Number(headers.get("Content-Length")));
-});
-
-Deno.test({ permissions: { net: true } }, async function fetchBodyReader() {
- const response = await fetch("http://localhost:4545/assets/fixture.json");
- const headers = response.headers;
- assert(response.body !== null);
- const reader = response.body.getReader();
- let total = 0;
- while (true) {
- const { done, value } = await reader.read();
- if (done) break;
- assert(value);
- assert(value instanceof Uint8Array);
- total += value.length;
- }
-
- assertEquals(total, Number(headers.get("Content-Length")));
-});
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchBodyReaderBigBody() {
- const data = "a".repeat(10 << 10); // 10mb
- const response = await fetch("http://localhost:4545/echo_server", {
- method: "POST",
- body: data,
- });
- assert(response.body !== null);
- const reader = await response.body.getReader();
- let total = 0;
- while (true) {
- const { done, value } = await reader.read();
- if (done) break;
- assert(value);
- total += value.length;
- }
-
- assertEquals(total, data.length);
- },
-);
-
-Deno.test({ permissions: { net: true } }, async function responseClone() {
- const response = await fetch("http://localhost:4545/assets/fixture.json");
- const response1 = response.clone();
- assert(response !== response1);
- assertEquals(response.status, response1.status);
- assertEquals(response.statusText, response1.statusText);
- const u8a = new Uint8Array(await response.arrayBuffer());
- const u8a1 = new Uint8Array(await response1.arrayBuffer());
- for (let i = 0; i < u8a.byteLength; i++) {
- assertEquals(u8a[i], u8a1[i]);
- }
-});
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchMultipartFormDataSuccess() {
- const response = await fetch(
- "http://localhost:4545/multipart_form_data.txt",
- );
- const formData = await response.formData();
- assert(formData.has("field_1"));
- assertEquals(formData.get("field_1")!.toString(), "value_1 \r\n");
- assert(formData.has("field_2"));
- const file = formData.get("field_2") as File;
- assertEquals(file.name, "file.js");
-
- assertEquals(await file.text(), `console.log("Hi")`);
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchMultipartFormBadContentType() {
- const response = await fetch(
- "http://localhost:4545/multipart_form_bad_content_type",
- );
- assert(response.body !== null);
-
- await assertRejects(
- async () => {
- await response.formData();
- },
- TypeError,
- "Body can not be decoded as form data",
- );
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchURLEncodedFormDataSuccess() {
- const response = await fetch(
- "http://localhost:4545/subdir/form_urlencoded.txt",
- );
- const formData = await response.formData();
- assert(formData.has("field_1"));
- assertEquals(formData.get("field_1")!.toString(), "Hi");
- assert(formData.has("field_2"));
- assertEquals(formData.get("field_2")!.toString(), "<Deno>");
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchInitFormDataBinaryFileBody() {
- // Some random bytes
- // deno-fmt-ignore
- const binaryFile = new Uint8Array([108,2,0,0,145,22,162,61,157,227,166,77,138,75,180,56,119,188,177,183]);
- const response = await fetch("http://localhost:4545/echo_multipart_file", {
- method: "POST",
- body: binaryFile,
- });
- const resultForm = await response.formData();
- const resultFile = resultForm.get("file") as File;
-
- assertEquals(resultFile.type, "application/octet-stream");
- assertEquals(resultFile.name, "file.bin");
- assertEquals(new Uint8Array(await resultFile.arrayBuffer()), binaryFile);
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchInitFormDataMultipleFilesBody() {
- const files = [
- {
- // deno-fmt-ignore
- content: new Uint8Array([137,80,78,71,13,10,26,10, 137, 1, 25]),
- type: "image/png",
- name: "image",
- fileName: "some-image.png",
- },
- {
- // deno-fmt-ignore
- content: new Uint8Array([108,2,0,0,145,22,162,61,157,227,166,77,138,75,180,56,119,188,177,183]),
- name: "file",
- fileName: "file.bin",
- expectedType: "application/octet-stream",
- },
- {
- content: new TextEncoder().encode("deno land"),
- type: "text/plain",
- name: "text",
- fileName: "deno.txt",
- },
- ];
- const form = new FormData();
- form.append("field", "value");
- for (const file of files) {
- form.append(
- file.name,
- new Blob([file.content], { type: file.type }),
- file.fileName,
- );
- }
- const response = await fetch("http://localhost:4545/echo_server", {
- method: "POST",
- body: form,
- });
- const resultForm = await response.formData();
- assertEquals(form.get("field"), resultForm.get("field"));
- for (const file of files) {
- const inputFile = form.get(file.name) as File;
- const resultFile = resultForm.get(file.name) as File;
- assertEquals(inputFile.size, resultFile.size);
- assertEquals(inputFile.name, resultFile.name);
- assertEquals(file.expectedType || file.type, resultFile.type);
- assertEquals(
- new Uint8Array(await resultFile.arrayBuffer()),
- file.content,
- );
- }
- },
-);
-
-Deno.test(
- {
- permissions: { net: true },
- },
- async function fetchWithRedirection() {
- const response = await fetch("http://localhost:4546/assets/hello.txt");
- assertEquals(response.status, 200);
- assertEquals(response.statusText, "OK");
- assertEquals(response.url, "http://localhost:4545/assets/hello.txt");
- const body = await response.text();
- assert(body.includes("Hello world!"));
- },
-);
-
-Deno.test(
- {
- permissions: { net: true },
- },
- async function fetchWithRelativeRedirection() {
- const response = await fetch(
- "http://localhost:4545/run/001_hello.js",
- );
- assertEquals(response.status, 200);
- assertEquals(response.statusText, "OK");
- const body = await response.text();
- assert(body.includes("Hello"));
- },
-);
-
-Deno.test(
- {
- permissions: { net: true },
- },
- async function fetchWithRelativeRedirectionUrl() {
- const cases = [
- ["end", "http://localhost:4550/a/b/end"],
- ["/end", "http://localhost:4550/end"],
- ];
- for (const [loc, redUrl] of cases) {
- const response = await fetch("http://localhost:4550/a/b/c", {
- headers: new Headers([["x-location", loc]]),
- });
- assertEquals(response.url, redUrl);
- assertEquals(response.redirected, true);
- assertEquals(response.status, 404);
- assertEquals(await response.text(), "");
- }
- },
-);
-
-Deno.test(
- {
- permissions: { net: true },
- },
- async function fetchWithInfRedirection() {
- await assertRejects(
- () => fetch("http://localhost:4549"),
- TypeError,
- "redirect",
- );
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchInitStringBody() {
- const data = "Hello World";
- const response = await fetch("http://localhost:4545/echo_server", {
- method: "POST",
- body: data,
- });
- const text = await response.text();
- assertEquals(text, data);
- assert(response.headers.get("content-type")!.startsWith("text/plain"));
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchRequestInitStringBody() {
- const data = "Hello World";
- const req = new Request("http://localhost:4545/echo_server", {
- method: "POST",
- body: data,
- });
- const response = await fetch(req);
- const text = await response.text();
- assertEquals(text, data);
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchSeparateInit() {
- // related to: https://github.com/denoland/deno/issues/10396
- const req = new Request("http://localhost:4545/run/001_hello.js");
- const init = {
- method: "GET",
- };
- req.headers.set("foo", "bar");
- const res = await fetch(req, init);
- assertEquals(res.status, 200);
- await res.text();
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchInitTypedArrayBody() {
- const data = "Hello World";
- const response = await fetch("http://localhost:4545/echo_server", {
- method: "POST",
- body: new TextEncoder().encode(data),
- });
- const text = await response.text();
- assertEquals(text, data);
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchInitArrayBufferBody() {
- const data = "Hello World";
- const response = await fetch("http://localhost:4545/echo_server", {
- method: "POST",
- body: new TextEncoder().encode(data).buffer,
- });
- const text = await response.text();
- assertEquals(text, data);
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchInitURLSearchParamsBody() {
- const data = "param1=value1&param2=value2";
- const params = new URLSearchParams(data);
- const response = await fetch("http://localhost:4545/echo_server", {
- method: "POST",
- body: params,
- });
- const text = await response.text();
- assertEquals(text, data);
- assert(
- response.headers
- .get("content-type")!
- .startsWith("application/x-www-form-urlencoded"),
- );
- },
-);
-
-Deno.test({ permissions: { net: true } }, async function fetchInitBlobBody() {
- const data = "const a = 1 🦕";
- const blob = new Blob([data], {
- type: "text/javascript",
- });
- const response = await fetch("http://localhost:4545/echo_server", {
- method: "POST",
- body: blob,
- });
- const text = await response.text();
- assertEquals(text, data);
- assert(response.headers.get("content-type")!.startsWith("text/javascript"));
-});
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchInitFormDataBody() {
- const form = new FormData();
- form.append("field", "value");
- const response = await fetch("http://localhost:4545/echo_server", {
- method: "POST",
- body: form,
- });
- const resultForm = await response.formData();
- assertEquals(form.get("field"), resultForm.get("field"));
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchInitFormDataBlobFilenameBody() {
- const form = new FormData();
- form.append("field", "value");
- form.append(
- "file",
- new Blob([new TextEncoder().encode("deno")]),
- "file name",
- );
- const response = await fetch("http://localhost:4545/echo_server", {
- method: "POST",
- body: form,
- });
- const resultForm = await response.formData();
- assertEquals(form.get("field"), resultForm.get("field"));
- const file = resultForm.get("file");
- assert(file instanceof File);
- assertEquals(file.name, "file name");
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchInitFormDataFileFilenameBody() {
- const form = new FormData();
- form.append("field", "value");
- form.append(
- "file",
- new File([new Blob([new TextEncoder().encode("deno")])], "file name"),
- );
- const response = await fetch("http://localhost:4545/echo_server", {
- method: "POST",
- body: form,
- });
- const resultForm = await response.formData();
- assertEquals(form.get("field"), resultForm.get("field"));
- const file = resultForm.get("file");
- assert(file instanceof File);
- assertEquals(file.name, "file name");
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchInitFormDataTextFileBody() {
- const fileContent = "deno land";
- const form = new FormData();
- form.append("field", "value");
- form.append(
- "file",
- new Blob([new TextEncoder().encode(fileContent)], {
- type: "text/plain",
- }),
- "deno.txt",
- );
- const response = await fetch("http://localhost:4545/echo_server", {
- method: "POST",
- body: form,
- });
- const resultForm = await response.formData();
- assertEquals(form.get("field"), resultForm.get("field"));
-
- const file = form.get("file") as File;
- const resultFile = resultForm.get("file") as File;
-
- assertEquals(file.size, resultFile.size);
- assertEquals(file.name, resultFile.name);
- assertEquals(file.type, resultFile.type);
- assertEquals(await file.text(), await resultFile.text());
- },
-);
-
-Deno.test({ permissions: { net: true } }, async function fetchUserAgent() {
- const data = "Hello World";
- const response = await fetch("http://localhost:4545/echo_server", {
- method: "POST",
- body: new TextEncoder().encode(data),
- });
- assertEquals(response.headers.get("user-agent"), `Deno/${Deno.version.deno}`);
- await response.text();
-});
-
-function bufferServer(addr: string): Promise<Buffer> {
- const [hostname, port] = addr.split(":");
- const listener = Deno.listen({
- hostname,
- port: Number(port),
- }) as Deno.Listener;
- return listener.accept().then(async (conn: Deno.Conn) => {
- const buf = new Buffer();
- const p1 = buf.readFrom(conn);
- const p2 = conn.write(
- new TextEncoder().encode(
- "HTTP/1.0 404 Not Found\r\nContent-Length: 2\r\n\r\nNF",
- ),
- );
- // Wait for both an EOF on the read side of the socket and for the write to
- // complete before closing it. Due to keep-alive, the EOF won't be sent
- // until the Connection close (HTTP/1.0) response, so readFrom() can't
- // proceed write. Conversely, if readFrom() is async, waiting for the
- // write() to complete is not a guarantee that we've read the incoming
- // request.
- await Promise.all([p1, p2]);
- conn.close();
- listener.close();
- return buf;
- });
-}
-
-Deno.test(
- {
- permissions: { net: true },
- },
- async function fetchRequest() {
- const addr = `127.0.0.1:${listenPort}`;
- const bufPromise = bufferServer(addr);
- const response = await fetch(`http://${addr}/blah`, {
- method: "POST",
- headers: [
- ["Hello", "World"],
- ["Foo", "Bar"],
- ],
- });
- await response.arrayBuffer();
- assertEquals(response.status, 404);
- assertEquals(response.headers.get("Content-Length"), "2");
-
- const actual = new TextDecoder().decode((await bufPromise).bytes());
- const expected = [
- "POST /blah HTTP/1.1\r\n",
- "content-length: 0\r\n",
- "hello: World\r\n",
- "foo: Bar\r\n",
- "accept: */*\r\n",
- "accept-language: *\r\n",
- `user-agent: Deno/${Deno.version.deno}\r\n`,
- "accept-encoding: gzip, br\r\n",
- `host: ${addr}\r\n\r\n`,
- ].join("");
- assertEquals(actual, expected);
- },
-);
-
-Deno.test(
- {
- permissions: { net: true },
- },
- async function fetchRequestAcceptHeaders() {
- const addr = `127.0.0.1:${listenPort}`;
- const bufPromise = bufferServer(addr);
- const response = await fetch(`http://${addr}/blah`, {
- method: "POST",
- headers: [
- ["Accept", "text/html"],
- ["Accept-Language", "en-US"],
- ],
- });
- await response.arrayBuffer();
- assertEquals(response.status, 404);
- assertEquals(response.headers.get("Content-Length"), "2");
-
- const actual = new TextDecoder().decode((await bufPromise).bytes());
- const expected = [
- "POST /blah HTTP/1.1\r\n",
- "content-length: 0\r\n",
- "accept: text/html\r\n",
- "accept-language: en-US\r\n",
- `user-agent: Deno/${Deno.version.deno}\r\n`,
- "accept-encoding: gzip, br\r\n",
- `host: ${addr}\r\n\r\n`,
- ].join("");
- assertEquals(actual, expected);
- },
-);
-
-Deno.test(
- {
- permissions: { net: true },
- },
- async function fetchPostBodyString() {
- const addr = `127.0.0.1:${listenPort}`;
- const bufPromise = bufferServer(addr);
- const body = "hello world";
- const response = await fetch(`http://${addr}/blah`, {
- method: "POST",
- headers: [
- ["Hello", "World"],
- ["Foo", "Bar"],
- ],
- body,
- });
- await response.arrayBuffer();
- assertEquals(response.status, 404);
- assertEquals(response.headers.get("Content-Length"), "2");
-
- const actual = new TextDecoder().decode((await bufPromise).bytes());
- const expected = [
- "POST /blah HTTP/1.1\r\n",
- "hello: World\r\n",
- "foo: Bar\r\n",
- "content-type: text/plain;charset=UTF-8\r\n",
- "accept: */*\r\n",
- "accept-language: *\r\n",
- `user-agent: Deno/${Deno.version.deno}\r\n`,
- "accept-encoding: gzip, br\r\n",
- `host: ${addr}\r\n`,
- `content-length: ${body.length}\r\n\r\n`,
- body,
- ].join("");
- assertEquals(actual, expected);
- },
-);
-
-Deno.test(
- {
- permissions: { net: true },
- },
- async function fetchPostBodyTypedArray() {
- const addr = `127.0.0.1:${listenPort}`;
- const bufPromise = bufferServer(addr);
- const bodyStr = "hello world";
- const body = new TextEncoder().encode(bodyStr);
- const response = await fetch(`http://${addr}/blah`, {
- method: "POST",
- headers: [
- ["Hello", "World"],
- ["Foo", "Bar"],
- ],
- body,
- });
- await response.arrayBuffer();
- assertEquals(response.status, 404);
- assertEquals(response.headers.get("Content-Length"), "2");
-
- const actual = new TextDecoder().decode((await bufPromise).bytes());
- const expected = [
- "POST /blah HTTP/1.1\r\n",
- "hello: World\r\n",
- "foo: Bar\r\n",
- "accept: */*\r\n",
- "accept-language: *\r\n",
- `user-agent: Deno/${Deno.version.deno}\r\n`,
- "accept-encoding: gzip, br\r\n",
- `host: ${addr}\r\n`,
- `content-length: ${body.byteLength}\r\n\r\n`,
- bodyStr,
- ].join("");
- assertEquals(actual, expected);
- },
-);
-
-Deno.test(
- {
- permissions: { net: true },
- },
- async function fetchUserSetContentLength() {
- const addr = `127.0.0.1:${listenPort}`;
- const bufPromise = bufferServer(addr);
- const response = await fetch(`http://${addr}/blah`, {
- method: "POST",
- headers: [
- ["Content-Length", "10"],
- ],
- });
- await response.arrayBuffer();
- assertEquals(response.status, 404);
- assertEquals(response.headers.get("Content-Length"), "2");
-
- const actual = new TextDecoder().decode((await bufPromise).bytes());
- const expected = [
- "POST /blah HTTP/1.1\r\n",
- "content-length: 0\r\n",
- "accept: */*\r\n",
- "accept-language: *\r\n",
- `user-agent: Deno/${Deno.version.deno}\r\n`,
- "accept-encoding: gzip, br\r\n",
- `host: ${addr}\r\n\r\n`,
- ].join("");
- assertEquals(actual, expected);
- },
-);
-
-Deno.test(
- {
- permissions: { net: true },
- },
- async function fetchUserSetTransferEncoding() {
- const addr = `127.0.0.1:${listenPort}`;
- const bufPromise = bufferServer(addr);
- const response = await fetch(`http://${addr}/blah`, {
- method: "POST",
- headers: [
- ["Transfer-Encoding", "chunked"],
- ],
- });
- await response.arrayBuffer();
- assertEquals(response.status, 404);
- assertEquals(response.headers.get("Content-Length"), "2");
-
- const actual = new TextDecoder().decode((await bufPromise).bytes());
- const expected = [
- "POST /blah HTTP/1.1\r\n",
- "content-length: 0\r\n",
- `host: ${addr}\r\n`,
- "accept: */*\r\n",
- "accept-language: *\r\n",
- `user-agent: Deno/${Deno.version.deno}\r\n`,
- "accept-encoding: gzip, br\r\n\r\n",
- ].join("");
- assertEquals(actual, expected);
- },
-);
-
-Deno.test(
- {
- permissions: { net: true },
- },
- async function fetchWithNonAsciiRedirection() {
- const response = await fetch("http://localhost:4545/non_ascii_redirect", {
- redirect: "manual",
- });
- assertEquals(response.status, 301);
- assertEquals(response.headers.get("location"), "/redirect®");
- await response.text();
- },
-);
-
-Deno.test(
- {
- permissions: { net: true },
- },
- async function fetchWithManualRedirection() {
- const response = await fetch("http://localhost:4546/", {
- redirect: "manual",
- }); // will redirect to http://localhost:4545/
- assertEquals(response.status, 301);
- assertEquals(response.url, "http://localhost:4546/");
- assertEquals(response.type, "basic");
- assertEquals(response.headers.get("Location"), "http://localhost:4545/");
- await response.body!.cancel();
- },
-);
-
-Deno.test(
- {
- permissions: { net: true },
- },
- async function fetchWithErrorRedirection() {
- await assertRejects(
- () =>
- fetch("http://localhost:4546/", {
- redirect: "error",
- }),
- TypeError,
- "redirect",
- );
- },
-);
-
-Deno.test(function responseRedirect() {
- const redir = Response.redirect("http://example.com/newLocation", 301);
- assertEquals(redir.status, 301);
- assertEquals(redir.statusText, "");
- assertEquals(redir.url, "");
- assertEquals(
- redir.headers.get("Location"),
- "http://example.com/newLocation",
- );
- assertEquals(redir.type, "default");
-});
-
-Deno.test(function responseRedirectTakeURLObjectAsParameter() {
- const redir = Response.redirect(new URL("https://example.com/"));
- assertEquals(
- redir.headers.get("Location"),
- "https://example.com/",
- );
-});
-
-Deno.test(async function responseWithoutBody() {
- const response = new Response();
- assertEquals(await response.arrayBuffer(), new ArrayBuffer(0));
- const blob = await response.blob();
- assertEquals(blob.size, 0);
- assertEquals(await blob.arrayBuffer(), new ArrayBuffer(0));
- assertEquals(await response.text(), "");
- await assertRejects(async () => {
- await response.json();
- });
-});
-
-Deno.test({ permissions: { net: true } }, async function fetchBodyReadTwice() {
- const response = await fetch("http://localhost:4545/assets/fixture.json");
-
- // Read body
- const _json = await response.json();
- assert(_json);
-
- // All calls after the body was consumed, should fail
- const methods = ["json", "text", "formData", "arrayBuffer"] as const;
- for (const method of methods) {
- try {
- await response[method]();
- fail(
- "Reading body multiple times should failed, the stream should've been locked.",
- );
- } catch {
- // pass
- }
- }
-});
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchBodyReaderAfterRead() {
- const response = await fetch(
- "http://localhost:4545/assets/fixture.json",
- );
- assert(response.body !== null);
- const reader = await response.body.getReader();
- while (true) {
- const { done, value } = await reader.read();
- if (done) break;
- assert(value);
- }
-
- try {
- response.body.getReader();
- fail("The stream should've been locked.");
- } catch {
- // pass
- }
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchBodyReaderWithCancelAndNewReader() {
- const data = "a".repeat(1 << 10);
- const response = await fetch("http://localhost:4545/echo_server", {
- method: "POST",
- body: data,
- });
- assert(response.body !== null);
- const firstReader = await response.body.getReader();
-
- // Acquire reader without reading & release
- await firstReader.releaseLock();
-
- const reader = await response.body.getReader();
-
- let total = 0;
- while (true) {
- const { done, value } = await reader.read();
- if (done) break;
- assert(value);
- total += value.length;
- }
-
- assertEquals(total, data.length);
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchBodyReaderWithReadCancelAndNewReader() {
- const data = "a".repeat(1 << 10);
-
- const response = await fetch("http://localhost:4545/echo_server", {
- method: "POST",
- body: data,
- });
- assert(response.body !== null);
- const firstReader = await response.body.getReader();
-
- // Do one single read with first reader
- const { value: firstValue } = await firstReader.read();
- assert(firstValue);
- await firstReader.releaseLock();
-
- // Continue read with second reader
- const reader = await response.body.getReader();
- let total = firstValue.length || 0;
- while (true) {
- const { done, value } = await reader.read();
- if (done) break;
- assert(value);
- total += value.length;
- }
- assertEquals(total, data.length);
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchResourceCloseAfterStreamCancel() {
- const res = await fetch("http://localhost:4545/assets/fixture.json");
- assert(res.body !== null);
-
- // After ReadableStream.cancel is called, resource handle must be closed
- // The test should not fail with: Test case is leaking resources
- await res.body.cancel();
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchNullBodyStatus() {
- const nullBodyStatus = [101, 204, 205, 304];
-
- for (const status of nullBodyStatus) {
- const headers = new Headers([["x-status", String(status)]]);
- const res = await fetch("http://localhost:4545/echo_server", {
- body: "deno",
- method: "POST",
- headers,
- });
- assertEquals(res.body, null);
- assertEquals(res.status, status);
- }
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchResponseContentLength() {
- const body = new Uint8Array(2 ** 16);
- const headers = new Headers([["content-type", "application/octet-stream"]]);
- const res = await fetch("http://localhost:4545/echo_server", {
- body: body,
- method: "POST",
- headers,
- });
- assertEquals(Number(res.headers.get("content-length")), body.byteLength);
-
- const blob = await res.blob();
- // Make sure Body content-type is correctly set
- assertEquals(blob.type, "application/octet-stream");
- assertEquals(blob.size, body.byteLength);
- },
-);
-
-Deno.test(function fetchResponseConstructorNullBody() {
- const nullBodyStatus = [204, 205, 304];
-
- for (const status of nullBodyStatus) {
- try {
- new Response("deno", { status });
- fail("Response with null body status cannot have body");
- } catch (e) {
- assert(e instanceof TypeError);
- assertEquals(
- e.message,
- "Response with null body status cannot have body",
- );
- }
- }
-});
-
-Deno.test(function fetchResponseConstructorInvalidStatus() {
- const invalidStatus = [100, 600, 199, null, "", NaN];
-
- for (const status of invalidStatus) {
- try {
- // deno-lint-ignore ban-ts-comment
- // @ts-ignore
- new Response("deno", { status });
- fail(`Invalid status: ${status}`);
- } catch (e) {
- assert(e instanceof RangeError);
- assert(
- e.message.endsWith(
- "is not equal to 101 and outside the range [200, 599].",
- ),
- );
- }
- }
-});
-
-Deno.test(function fetchResponseEmptyConstructor() {
- const response = new Response();
- assertEquals(response.status, 200);
- assertEquals(response.body, null);
- assertEquals(response.type, "default");
- assertEquals(response.url, "");
- assertEquals(response.redirected, false);
- assertEquals(response.ok, true);
- assertEquals(response.bodyUsed, false);
- assertEquals([...response.headers], []);
-});
-
-Deno.test(
- { permissions: { net: true, read: true } },
- async function fetchCustomHttpClientParamCertificateSuccess(): Promise<
- void
- > {
- const caCert = Deno.readTextFileSync("cli/tests/testdata/tls/RootCA.pem");
- const client = Deno.createHttpClient({ caCerts: [caCert] });
- const response = await fetch("https://localhost:5545/assets/fixture.json", {
- client,
- });
- const json = await response.json();
- assertEquals(json.name, "deno");
- client.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true, read: true } },
- function createHttpClientAcceptPoolIdleTimeout() {
- const client = Deno.createHttpClient({
- poolIdleTimeout: 1000,
- });
- client.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchCustomClientUserAgent(): Promise<
- void
- > {
- const data = "Hello World";
- const client = Deno.createHttpClient({});
- const response = await fetch("http://localhost:4545/echo_server", {
- client,
- method: "POST",
- body: new TextEncoder().encode(data),
- });
- assertEquals(
- response.headers.get("user-agent"),
- `Deno/${Deno.version.deno}`,
- );
- await response.text();
- client.close();
- },
-);
-
-Deno.test(
- {
- permissions: { net: true },
- },
- async function fetchPostBodyReadableStream() {
- const addr = `127.0.0.1:${listenPort}`;
- const bufPromise = bufferServer(addr);
- const stream = new TransformStream();
- const writer = stream.writable.getWriter();
- // transformer writes don't resolve until they are read, so awaiting these
- // will cause the transformer to hang, as the suspend the transformer, it
- // is also illogical to await for the reads, as that is the whole point of
- // streams is to have a "queue" which gets drained...
- writer.write(new TextEncoder().encode("hello "));
- writer.write(new TextEncoder().encode("world"));
- writer.close();
- const response = await fetch(`http://${addr}/blah`, {
- method: "POST",
- headers: [
- ["Hello", "World"],
- ["Foo", "Bar"],
- ],
- body: stream.readable,
- });
- await response.arrayBuffer();
- assertEquals(response.status, 404);
- assertEquals(response.headers.get("Content-Length"), "2");
-
- const actual = new TextDecoder().decode((await bufPromise).bytes());
- const expected = [
- "POST /blah HTTP/1.1\r\n",
- "hello: World\r\n",
- "foo: Bar\r\n",
- "accept: */*\r\n",
- "accept-language: *\r\n",
- `user-agent: Deno/${Deno.version.deno}\r\n`,
- "accept-encoding: gzip, br\r\n",
- `host: ${addr}\r\n`,
- `transfer-encoding: chunked\r\n\r\n`,
- "B\r\n",
- "hello world\r\n",
- "0\r\n\r\n",
- ].join("");
- assertEquals(actual, expected);
- },
-);
-
-Deno.test({}, function fetchWritableRespProps() {
- const original = new Response("https://deno.land", {
- status: 404,
- headers: { "x-deno": "foo" },
- });
- const new_ = new Response("https://deno.land", original);
- assertEquals(original.status, new_.status);
- assertEquals(new_.headers.get("x-deno"), "foo");
-});
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchFilterOutCustomHostHeader(): Promise<
- void
- > {
- const addr = `127.0.0.1:${listenPort}`;
- const [hostname, port] = addr.split(":");
- const listener = Deno.listen({
- hostname,
- port: Number(port),
- }) as Deno.Listener;
-
- let httpConn: Deno.HttpConn;
- listener.accept().then(async (conn: Deno.Conn) => {
- httpConn = Deno.serveHttp(conn);
-
- await httpConn.nextRequest()
- .then(async (requestEvent: Deno.RequestEvent | null) => {
- const hostHeader = requestEvent?.request.headers.get("Host");
- const headersToReturn = hostHeader
- ? { "Host": hostHeader }
- : undefined;
-
- await requestEvent?.respondWith(
- new Response("", {
- status: 200,
- headers: headersToReturn,
- }),
- );
- });
- });
-
- const response = await fetch(`http://${addr}/`, {
- headers: { "Host": "example.com" },
- });
- await response.text();
- listener.close();
- httpConn!.close();
-
- assertEquals(response.headers.get("Host"), addr);
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchNoServerReadableStreamBody() {
- const completed = Promise.withResolvers<void>();
- const failed = Promise.withResolvers<void>();
- const body = new ReadableStream({
- start(controller) {
- controller.enqueue(new Uint8Array([1]));
- setTimeout(async () => {
- // This is technically a race. If the fetch has failed by this point, the enqueue will
- // throw. If not, it will succeed. Windows appears to take a while to time out the fetch,
- // so we will just wait for that here before we attempt to enqueue so it's consistent
- // across platforms.
- await failed.promise;
- assertThrows(() => controller.enqueue(new Uint8Array([2])));
- completed.resolve();
- }, 1000);
- },
- });
- const nonExistentHostname = "http://localhost:47582";
- await assertRejects(async () => {
- await fetch(nonExistentHostname, { body, method: "POST" });
- }, TypeError);
- failed.resolve();
- await completed.promise;
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchHeadRespBody() {
- const res = await fetch("http://localhost:4545/echo_server", {
- method: "HEAD",
- });
- assertEquals(res.body, null);
- },
-);
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function fetchClientCertWrongPrivateKey(): Promise<void> {
- await assertRejects(async () => {
- const client = Deno.createHttpClient({
- certChain: "bad data",
- privateKey: await Deno.readTextFile(
- "cli/tests/testdata/tls/localhost.key",
- ),
- });
- await fetch("https://localhost:5552/assets/fixture.json", {
- client,
- });
- }, Deno.errors.InvalidData);
- },
-);
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function fetchClientCertBadPrivateKey(): Promise<void> {
- await assertRejects(async () => {
- const client = Deno.createHttpClient({
- certChain: await Deno.readTextFile(
- "cli/tests/testdata/tls/localhost.crt",
- ),
- privateKey: "bad data",
- });
- await fetch("https://localhost:5552/assets/fixture.json", {
- client,
- });
- }, Deno.errors.InvalidData);
- },
-);
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function fetchClientCertNotPrivateKey(): Promise<void> {
- await assertRejects(async () => {
- const client = Deno.createHttpClient({
- certChain: await Deno.readTextFile(
- "cli/tests/testdata/tls/localhost.crt",
- ),
- privateKey: "",
- });
- await fetch("https://localhost:5552/assets/fixture.json", {
- client,
- });
- }, Deno.errors.InvalidData);
- },
-);
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function fetchCustomClientPrivateKey(): Promise<
- void
- > {
- const data = "Hello World";
- const caCert = await Deno.readTextFile("cli/tests/testdata/tls/RootCA.crt");
- const client = Deno.createHttpClient({
- certChain: await Deno.readTextFile(
- "cli/tests/testdata/tls/localhost.crt",
- ),
- privateKey: await Deno.readTextFile(
- "cli/tests/testdata/tls/localhost.key",
- ),
- caCerts: [caCert],
- });
- const response = await fetch("https://localhost:5552/echo_server", {
- client,
- method: "POST",
- body: new TextEncoder().encode(data),
- });
- assertEquals(
- response.headers.get("user-agent"),
- `Deno/${Deno.version.deno}`,
- );
- await response.text();
- client.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchAbortWhileUploadStreaming(): Promise<void> {
- const abortController = new AbortController();
- try {
- await fetch(
- "http://localhost:5552/echo_server",
- {
- method: "POST",
- body: new ReadableStream({
- pull(controller) {
- abortController.abort();
- controller.enqueue(new Uint8Array([1, 2, 3, 4]));
- },
- }),
- signal: abortController.signal,
- },
- );
- fail("Fetch didn't reject.");
- } catch (error) {
- assert(error instanceof DOMException);
- assertEquals(error.name, "AbortError");
- assertEquals(error.message, "The signal has been aborted");
- }
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchAbortWhileUploadStreamingWithReason(): Promise<void> {
- const abortController = new AbortController();
- const abortReason = new Error();
- try {
- await fetch(
- "http://localhost:5552/echo_server",
- {
- method: "POST",
- body: new ReadableStream({
- pull(controller) {
- abortController.abort(abortReason);
- controller.enqueue(new Uint8Array([1, 2, 3, 4]));
- },
- }),
- signal: abortController.signal,
- },
- );
- fail("Fetch didn't reject.");
- } catch (error) {
- assertEquals(error, abortReason);
- }
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchAbortWhileUploadStreamingWithPrimitiveReason(): Promise<
- void
- > {
- const abortController = new AbortController();
- try {
- await fetch(
- "http://localhost:5552/echo_server",
- {
- method: "POST",
- body: new ReadableStream({
- pull(controller) {
- abortController.abort("Abort reason");
- controller.enqueue(new Uint8Array([1, 2, 3, 4]));
- },
- }),
- signal: abortController.signal,
- },
- );
- fail("Fetch didn't reject.");
- } catch (error) {
- assertEquals(error, "Abort reason");
- }
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchHeaderValueShouldNotPanic() {
- for (let i = 0; i < 0x21; i++) {
- if (i === 0x09 || i === 0x0A || i === 0x0D || i === 0x20) {
- continue; // these header value will be normalized, will not cause an error.
- }
- // ensure there will be an error instead of panic.
- await assertRejects(() =>
- fetch("http://localhost:4545/echo_server", {
- method: "HEAD",
- headers: { "val": String.fromCharCode(i) },
- }), TypeError);
- }
- await assertRejects(() =>
- fetch("http://localhost:4545/echo_server", {
- method: "HEAD",
- headers: { "val": String.fromCharCode(127) },
- }), TypeError);
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchHeaderNameShouldNotPanic() {
- const validTokens =
- "!#$%&'*+-.0123456789ABCDEFGHIJKLMNOPQRSTUWVXYZ^_`abcdefghijklmnopqrstuvwxyz|~"
- .split("");
- for (let i = 0; i <= 255; i++) {
- const token = String.fromCharCode(i);
- if (validTokens.includes(token)) {
- continue;
- }
- // ensure there will be an error instead of panic.
- await assertRejects(() =>
- fetch("http://localhost:4545/echo_server", {
- method: "HEAD",
- headers: { [token]: "value" },
- }), TypeError);
- }
- await assertRejects(() =>
- fetch("http://localhost:4545/echo_server", {
- method: "HEAD",
- headers: { "": "value" },
- }), TypeError);
- },
-);
-
-Deno.test(
- { permissions: { net: true, read: true } },
- async function fetchSupportsHttpsOverIpAddress() {
- const caCert = await Deno.readTextFile("cli/tests/testdata/tls/RootCA.pem");
- const client = Deno.createHttpClient({ caCerts: [caCert] });
- const res = await fetch("https://localhost:5546/http_version", { client });
- assert(res.ok);
- assertEquals(await res.text(), "HTTP/1.1");
- client.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true, read: true } },
- async function fetchSupportsHttp1Only() {
- const caCert = await Deno.readTextFile("cli/tests/testdata/tls/RootCA.pem");
- const client = Deno.createHttpClient({ caCerts: [caCert] });
- const res = await fetch("https://localhost:5546/http_version", { client });
- assert(res.ok);
- assertEquals(await res.text(), "HTTP/1.1");
- client.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true, read: true } },
- async function fetchSupportsHttp2() {
- const caCert = await Deno.readTextFile("cli/tests/testdata/tls/RootCA.pem");
- const client = Deno.createHttpClient({ caCerts: [caCert] });
- const res = await fetch("https://localhost:5547/http_version", { client });
- assert(res.ok);
- assertEquals(await res.text(), "HTTP/2.0");
- client.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true, read: true } },
- async function fetchForceHttp1OnHttp2Server() {
- const client = Deno.createHttpClient({ http2: false, http1: true });
- await assertRejects(
- () => fetch("http://localhost:5549/http_version", { client }),
- TypeError,
- );
- client.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true, read: true } },
- async function fetchForceHttp2OnHttp1Server() {
- const client = Deno.createHttpClient({ http2: true, http1: false });
- await assertRejects(
- () => fetch("http://localhost:5548/http_version", { client }),
- TypeError,
- );
- client.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true, read: true } },
- async function fetchPrefersHttp2() {
- const caCert = await Deno.readTextFile("cli/tests/testdata/tls/RootCA.pem");
- const client = Deno.createHttpClient({ caCerts: [caCert] });
- const res = await fetch("https://localhost:5545/http_version", { client });
- assert(res.ok);
- assertEquals(await res.text(), "HTTP/2.0");
- client.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true, read: true } },
- async function createHttpClientAllowHost() {
- const client = Deno.createHttpClient({
- allowHost: true,
- });
- const res = await fetch("http://localhost:4545/echo_server", {
- headers: {
- "host": "example.com",
- },
- client,
- });
- assert(res.ok);
- assertEquals(res.headers.get("host"), "example.com");
- await res.body?.cancel();
- client.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function createHttpClientExplicitResourceManagement() {
- using client = Deno.createHttpClient({});
- const response = await fetch("http://localhost:4545/assets/fixture.json", {
- client,
- });
- const json = await response.json();
- assertEquals(json.name, "deno");
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function createHttpClientExplicitResourceManagementDoubleClose() {
- using client = Deno.createHttpClient({});
- const response = await fetch("http://localhost:4545/assets/fixture.json", {
- client,
- });
- const json = await response.json();
- assertEquals(json.name, "deno");
- // Close the client even though we declared it with `using` to confirm that
- // the cleanup done as per `Symbol.dispose` will not throw any errors.
- client.close();
- },
-);
-
-Deno.test({ permissions: { read: false } }, async function fetchFilePerm() {
- await assertRejects(async () => {
- await fetch(import.meta.resolve("../testdata/subdir/json_1.json"));
- }, Deno.errors.PermissionDenied);
-});
-
-Deno.test(
- { permissions: { read: false } },
- async function fetchFilePermDoesNotExist() {
- await assertRejects(async () => {
- await fetch(import.meta.resolve("./bad.json"));
- }, Deno.errors.PermissionDenied);
- },
-);
-
-Deno.test(
- { permissions: { read: true } },
- async function fetchFileBadMethod() {
- await assertRejects(
- async () => {
- await fetch(
- import.meta.resolve("../testdata/subdir/json_1.json"),
- {
- method: "POST",
- },
- );
- },
- TypeError,
- "Fetching files only supports the GET method. Received POST.",
- );
- },
-);
-
-Deno.test(
- { permissions: { read: true } },
- async function fetchFileDoesNotExist() {
- await assertRejects(
- async () => {
- await fetch(import.meta.resolve("./bad.json"));
- },
- TypeError,
- );
- },
-);
-
-Deno.test(
- { permissions: { read: true } },
- async function fetchFile() {
- const res = await fetch(
- import.meta.resolve("../testdata/subdir/json_1.json"),
- );
- assert(res.ok);
- const fixture = await Deno.readTextFile(
- "cli/tests/testdata/subdir/json_1.json",
- );
- assertEquals(await res.text(), fixture);
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchContentLengthPost() {
- const response = await fetch("http://localhost:4545/content_length", {
- method: "POST",
- });
- const length = await response.text();
- assertEquals(length, 'Some("0")');
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchContentLengthPut() {
- const response = await fetch("http://localhost:4545/content_length", {
- method: "PUT",
- });
- const length = await response.text();
- assertEquals(length, 'Some("0")');
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchContentLengthPatch() {
- const response = await fetch("http://localhost:4545/content_length", {
- method: "PATCH",
- });
- const length = await response.text();
- assertEquals(length, "None");
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchContentLengthPostWithStringBody() {
- const response = await fetch("http://localhost:4545/content_length", {
- method: "POST",
- body: "Hey!",
- });
- const length = await response.text();
- assertEquals(length, 'Some("4")');
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchContentLengthPostWithBufferBody() {
- const response = await fetch("http://localhost:4545/content_length", {
- method: "POST",
- body: new TextEncoder().encode("Hey!"),
- });
- const length = await response.text();
- assertEquals(length, 'Some("4")');
- },
-);
-
-Deno.test(async function staticResponseJson() {
- const data = { hello: "world" };
- const resp = Response.json(data);
- assertEquals(resp.status, 200);
- assertEquals(resp.headers.get("content-type"), "application/json");
- const res = await resp.json();
- assertEquals(res, data);
-});
-
-function invalidServer(addr: string, body: Uint8Array): Deno.Listener {
- const [hostname, port] = addr.split(":");
- const listener = Deno.listen({
- hostname,
- port: Number(port),
- }) as Deno.Listener;
-
- (async () => {
- for await (const conn of listener) {
- const p1 = conn.read(new Uint8Array(2 ** 14));
- const p2 = conn.write(body);
-
- await Promise.all([p1, p2]);
- conn.close();
- }
- })();
-
- return listener;
-}
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchWithInvalidContentLengthAndTransferEncoding(): Promise<
- void
- > {
- const addr = `127.0.0.1:${listenPort}`;
- const data = "a".repeat(10 << 10);
-
- const body = new TextEncoder().encode(
- `HTTP/1.1 200 OK\r\nContent-Length: ${
- Math.round(data.length * 2)
- }\r\nTransfer-Encoding: chunked\r\n\r\n${
- data.length.toString(16)
- }\r\n${data}\r\n0\r\n\r\n`,
- );
-
- // if transfer-encoding is sent, content-length is ignored
- // even if it has an invalid value (content-length > totalLength)
- const listener = invalidServer(addr, body);
- const response = await fetch(`http://${addr}/`);
-
- const res = await response.arrayBuffer();
- const buf = new TextEncoder().encode(data);
- assertEquals(res.byteLength, buf.byteLength);
- assertEquals(new Uint8Array(res), buf);
-
- listener.close();
- },
-);
-
-Deno.test(
- // TODO(bartlomieju): reenable this test
- // https://github.com/denoland/deno/issues/18350
- { ignore: Deno.build.os === "windows", permissions: { net: true } },
- async function fetchWithInvalidContentLength(): Promise<
- void
- > {
- const addr = `127.0.0.1:${listenPort}`;
- const data = "a".repeat(10 << 10);
-
- const body = new TextEncoder().encode(
- `HTTP/1.1 200 OK\r\nContent-Length: ${
- Math.round(data.length / 2)
- }\r\nContent-Length: ${data.length}\r\n\r\n${data}`,
- );
-
- // It should fail if multiple content-length headers with different values are sent
- const listener = invalidServer(addr, body);
- await assertRejects(
- async () => {
- await fetch(`http://${addr}/`);
- },
- TypeError,
- "invalid content-length parsed",
- );
-
- listener.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchWithInvalidContentLength2(): Promise<
- void
- > {
- const addr = `127.0.0.1:${listenPort}`;
- const data = "a".repeat(10 << 10);
-
- const contentLength = data.length / 2;
- const body = new TextEncoder().encode(
- `HTTP/1.1 200 OK\r\nContent-Length: ${contentLength}\r\n\r\n${data}`,
- );
-
- const listener = invalidServer(addr, body);
- const response = await fetch(`http://${addr}/`);
-
- // If content-length < totalLength, a maximum of content-length bytes
- // should be returned.
- const res = await response.arrayBuffer();
- const buf = new TextEncoder().encode(data);
- assertEquals(res.byteLength, contentLength);
- assertEquals(new Uint8Array(res), buf.subarray(contentLength));
-
- listener.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchWithInvalidContentLength3(): Promise<
- void
- > {
- const addr = `127.0.0.1:${listenPort}`;
- const data = "a".repeat(10 << 10);
-
- const contentLength = data.length * 2;
- const body = new TextEncoder().encode(
- `HTTP/1.1 200 OK\r\nContent-Length: ${contentLength}\r\n\r\n${data}`,
- );
-
- const listener = invalidServer(addr, body);
- const response = await fetch(`http://${addr}/`);
- // If content-length > totalLength, a maximum of content-length bytes
- // should be returned.
- await assertRejects(
- async () => {
- await response.arrayBuffer();
- },
- Error,
- "end of file before message length reached",
- );
-
- listener.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchBlobUrl(): Promise<void> {
- const blob = new Blob(["ok"], { type: "text/plain" });
- const url = URL.createObjectURL(blob);
- assert(url.startsWith("blob:"), `URL was ${url}`);
- const res = await fetch(url);
- assertEquals(res.url, url);
- assertEquals(res.status, 200);
- assertEquals(res.headers.get("content-length"), "2");
- assertEquals(res.headers.get("content-type"), "text/plain");
- assertEquals(await res.text(), "ok");
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchResponseStreamIsLockedWhileReading() {
- const response = await fetch("http://localhost:4545/echo_server", {
- body: new Uint8Array(5000),
- method: "POST",
- });
-
- assertEquals(response.body!.locked, false);
- const promise = response.arrayBuffer();
- assertEquals(response.body!.locked, true);
-
- await promise;
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchConstructorClones() {
- const req = new Request("https://example.com", {
- method: "POST",
- body: "foo",
- });
- assertEquals(await req.text(), "foo");
- await assertRejects(() => req.text());
-
- const req2 = new Request(req, { method: "PUT", body: "bar" }); // should not have any impact on req
- await assertRejects(() => req.text());
- assertEquals(await req2.text(), "bar");
-
- assertEquals(req.method, "POST");
- assertEquals(req2.method, "PUT");
-
- assertEquals(req.headers.get("x-foo"), null);
- assertEquals(req2.headers.get("x-foo"), null);
- req2.headers.set("x-foo", "bar"); // should not have any impact on req
- assertEquals(req.headers.get("x-foo"), null);
- assertEquals(req2.headers.get("x-foo"), "bar");
- },
-);
-
-Deno.test(
- // TODO(bartlomieju): reenable this test
- // https://github.com/denoland/deno/issues/18350
- { ignore: Deno.build.os === "windows", permissions: { net: true } },
- async function fetchRequestBodyErrorCatchable() {
- const listener = Deno.listen({ hostname: "127.0.0.1", port: listenPort });
- const server = (async () => {
- const conn = await listener.accept();
- listener.close();
- const buf = new Uint8Array(256);
- const n = await conn.read(buf);
- const data = new TextDecoder().decode(buf.subarray(0, n!)); // this is the request headers + first body chunk
- assert(data.startsWith("POST / HTTP/1.1\r\n"));
- assert(data.endsWith("1\r\na\r\n"));
- const n2 = await conn.read(buf);
- assertEquals(n2, 6); // this is the second body chunk
- const n3 = await conn.read(buf);
- assertEquals(n3, null); // the connection now abruptly closes because the client has errored
- conn.close();
- })();
-
- const stream = new ReadableStream({
- async start(controller) {
- controller.enqueue(new TextEncoder().encode("a"));
- await delay(1000);
- controller.enqueue(new TextEncoder().encode("b"));
- await delay(1000);
- controller.error(new Error("foo"));
- },
- });
-
- const err = await assertRejects(() =>
- fetch(`http://localhost:${listenPort}/`, {
- body: stream,
- method: "POST",
- })
- );
-
- assert(err instanceof TypeError, `err was not a TypeError ${err}`);
- assert(err.cause, `err.cause was null ${err}`);
- assert(
- err.cause instanceof Error,
- `err.cause was not an Error ${err.cause}`,
- );
- assertEquals(err.cause.message, "foo");
-
- await server;
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchRequestBodyEmptyStream() {
- const body = new ReadableStream({
- start(controller) {
- controller.enqueue(new Uint8Array([]));
- controller.close();
- },
- });
-
- await assertRejects(
- async () => {
- const controller = new AbortController();
- const promise = fetch("http://localhost:4545/echo_server", {
- body,
- method: "POST",
- signal: controller.signal,
- });
- try {
- controller.abort();
- } catch (e) {
- console.log(e);
- fail("abort should not throw");
- }
- await promise;
- },
- DOMException,
- "The signal has been aborted",
- );
- },
-);
-
-Deno.test("Request with subarray TypedArray body", async () => {
- const body = new Uint8Array([1, 2, 3, 4, 5]).subarray(1);
- const req = new Request("https://example.com", { method: "POST", body });
- const actual = new Uint8Array(await req.arrayBuffer());
- const expected = new Uint8Array([2, 3, 4, 5]);
- assertEquals(actual, expected);
-});
-
-Deno.test("Response with subarray TypedArray body", async () => {
- const body = new Uint8Array([1, 2, 3, 4, 5]).subarray(1);
- const req = new Response(body);
- const actual = new Uint8Array(await req.arrayBuffer());
- const expected = new Uint8Array([2, 3, 4, 5]);
- assertEquals(actual, expected);
-});