1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-28 01:59:06 -05:00
denoland-deno/cli/tests/unit/http_test.ts
2021-05-21 10:11:53 +09:00

341 lines
10 KiB
TypeScript

// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
import {
assert,
assertEquals,
assertThrowsAsync,
unitTest,
} from "./test_util.ts";
unitTest({ perms: { net: true } }, async function httpServerBasic() {
const promise = (async () => {
const listener = Deno.listen({ port: 4501 });
for await (const conn of listener) {
const httpConn = Deno.serveHttp(conn);
for await (const { request, respondWith } of httpConn) {
assertEquals(new URL(request.url).href, "http://127.0.0.1:4501/");
assertEquals(await request.text(), "");
respondWith(new Response("Hello World", { headers: { "foo": "bar" } }));
}
break;
}
})();
const resp = await fetch("http://127.0.0.1:4501/", {
headers: { "connection": "close" },
});
const text = await resp.text();
assertEquals(text, "Hello World");
assertEquals(resp.headers.get("foo"), "bar");
await promise;
});
unitTest(
{ perms: { net: true } },
async function httpServerStreamResponse() {
const stream = new TransformStream();
const writer = stream.writable.getWriter();
writer.write(new TextEncoder().encode("hello "));
writer.write(new TextEncoder().encode("world"));
writer.close();
const promise = (async () => {
const listener = Deno.listen({ port: 4501 });
const conn = await listener.accept();
const httpConn = Deno.serveHttp(conn);
const evt = await httpConn.nextRequest();
assert(evt);
const { request, respondWith } = evt;
assert(!request.body);
await respondWith(new Response(stream.readable));
httpConn.close();
listener.close();
})();
const resp = await fetch("http://127.0.0.1:4501/");
const respBody = await resp.text();
assertEquals("hello world", respBody);
await promise;
},
);
unitTest(
{ perms: { net: true } },
async function httpServerStreamRequest() {
const stream = new TransformStream();
const writer = stream.writable.getWriter();
writer.write(new TextEncoder().encode("hello "));
writer.write(new TextEncoder().encode("world"));
writer.close();
const promise = (async () => {
const listener = Deno.listen({ port: 4501 });
const conn = await listener.accept();
const httpConn = Deno.serveHttp(conn);
const evt = await httpConn.nextRequest();
assert(evt);
const { request, respondWith } = evt;
const reqBody = await request.text();
assertEquals("hello world", reqBody);
await respondWith(new Response(""));
// TODO(ry) If we don't call httpConn.nextRequest() here we get "error sending
// request for url (https://localhost:4501/): connection closed before
// message completed".
assertEquals(await httpConn.nextRequest(), null);
listener.close();
})();
const resp = await fetch("http://127.0.0.1:4501/", {
body: stream.readable,
method: "POST",
headers: { "connection": "close" },
});
await resp.arrayBuffer();
await promise;
},
);
unitTest({ perms: { net: true } }, async function httpServerStreamDuplex() {
const promise = (async () => {
const listener = Deno.listen({ port: 4501 });
const conn = await listener.accept();
const httpConn = Deno.serveHttp(conn);
const evt = await httpConn.nextRequest();
assert(evt);
const { request, respondWith } = evt;
assert(request.body);
await respondWith(new Response(request.body));
httpConn.close();
listener.close();
})();
const ts = new TransformStream();
const writable = ts.writable.getWriter();
const resp = await fetch("http://127.0.0.1:4501/", {
method: "POST",
body: ts.readable,
});
assert(resp.body);
const reader = resp.body.getReader();
await writable.write(new Uint8Array([1]));
const chunk1 = await reader.read();
assert(!chunk1.done);
assertEquals(chunk1.value, new Uint8Array([1]));
await writable.write(new Uint8Array([2]));
const chunk2 = await reader.read();
assert(!chunk2.done);
assertEquals(chunk2.value, new Uint8Array([2]));
await writable.close();
const chunk3 = await reader.read();
assert(chunk3.done);
await promise;
});
unitTest({ perms: { net: true } }, async function httpServerClose() {
const listener = Deno.listen({ port: 4501 });
const client = await Deno.connect({ port: 4501 });
const httpConn = Deno.serveHttp(await listener.accept());
client.close();
const evt = await httpConn.nextRequest();
assertEquals(evt, null);
// Note httpConn is automatically closed when "done" is reached.
listener.close();
});
unitTest({ perms: { net: true } }, async function httpServerInvalidMethod() {
const listener = Deno.listen({ port: 4501 });
const client = await Deno.connect({ port: 4501 });
const httpConn = Deno.serveHttp(await listener.accept());
await client.write(new Uint8Array([1, 2, 3]));
await assertThrowsAsync(
async () => {
await httpConn.nextRequest();
},
Deno.errors.Http,
"invalid HTTP method parsed",
);
// Note httpConn is automatically closed when it errors.
client.close();
listener.close();
});
unitTest(
{ perms: { read: true, net: true } },
async function httpServerWithTls(): Promise<void> {
const hostname = "localhost";
const port = 4501;
const promise = (async () => {
const listener = Deno.listenTls({
hostname,
port,
certFile: "cli/tests/tls/localhost.crt",
keyFile: "cli/tests/tls/localhost.key",
});
const conn = await listener.accept();
const httpConn = Deno.serveHttp(conn);
const evt = await httpConn.nextRequest();
assert(evt);
const { respondWith } = evt;
await respondWith(new Response("Hello World"));
// TODO(ry) If we don't call httpConn.nextRequest() here we get "error sending
// request for url (https://localhost:4501/): connection closed before
// message completed".
assertEquals(await httpConn.nextRequest(), null);
listener.close();
})();
const caData = Deno.readTextFileSync("cli/tests/tls/RootCA.pem");
const client = Deno.createHttpClient({ caData });
const resp = await fetch(`https://${hostname}:${port}/`, {
client,
headers: { "connection": "close" },
});
const respBody = await resp.text();
assertEquals("Hello World", respBody);
await promise;
client.close();
},
);
unitTest(
{ perms: { net: true } },
async function httpServerRegressionHang() {
const promise = (async () => {
const listener = Deno.listen({ port: 4501 });
const conn = await listener.accept();
const httpConn = Deno.serveHttp(conn);
const event = await httpConn.nextRequest();
assert(event);
const { request, respondWith } = event;
const reqBody = await request.text();
assertEquals("request", reqBody);
await respondWith(new Response("response"));
httpConn.close();
listener.close();
})();
const resp = await fetch("http://127.0.0.1:4501/", {
method: "POST",
body: "request",
});
const respBody = await resp.text();
assertEquals("response", respBody);
await promise;
},
);
unitTest(
{ perms: { net: true } },
async function httpServerCancelBodyOnResponseFailure() {
const promise = (async () => {
const listener = Deno.listen({ port: 4501 });
const conn = await listener.accept();
const httpConn = Deno.serveHttp(conn);
const event = await httpConn.nextRequest();
assert(event);
const { respondWith } = event;
let cancelReason = null;
const responseError = await assertThrowsAsync(
async () => {
let interval = 0;
await respondWith(
new Response(
new ReadableStream({
start(controller) {
interval = setInterval(() => {
const message = `data: ${Date.now()}\n\n`;
controller.enqueue(new TextEncoder().encode(message));
}, 200);
},
cancel(reason) {
cancelReason = reason;
clearInterval(interval);
},
}),
),
);
},
Deno.errors.Http,
);
assertEquals(cancelReason, responseError);
httpConn.close();
listener.close();
})();
const resp = await fetch("http://127.0.0.1:4501/");
await resp.body!.cancel();
await promise;
},
);
unitTest(
{ perms: { net: true } },
async function httpServerNextRequestErrorExposedInResponse() {
const promise = (async () => {
const listener = Deno.listen({ port: 4501 });
const conn = await listener.accept();
const httpConn = Deno.serveHttp(conn);
const event = await httpConn.nextRequest();
assert(event);
// Start polling for the next request before awaiting response.
const nextRequestPromise = httpConn.nextRequest();
const { respondWith } = event;
await assertThrowsAsync(
async () => {
let interval = 0;
await respondWith(
new Response(
new ReadableStream({
start(controller) {
interval = setInterval(() => {
const message = `data: ${Date.now()}\n\n`;
controller.enqueue(new TextEncoder().encode(message));
}, 200);
},
cancel() {
clearInterval(interval);
},
}),
),
);
},
Deno.errors.Http,
"connection closed",
);
// The error from `op_http_request_next` reroutes to `respondWith()`.
assertEquals(await nextRequestPromise, null);
listener.close();
})();
const resp = await fetch("http://127.0.0.1:4501/");
await resp.body!.cancel();
await promise;
},
);
unitTest(
{ perms: { net: true } },
async function httpServerEmptyBlobResponse() {
const promise = (async () => {
const listener = Deno.listen({ port: 4501 });
const conn = await listener.accept();
const httpConn = Deno.serveHttp(conn);
const event = await httpConn.nextRequest();
assert(event);
const { respondWith } = event;
await respondWith(new Response(new Blob([])));
httpConn.close();
listener.close();
})();
const resp = await fetch("http://127.0.0.1:4501/");
const respBody = await resp.text();
assertEquals("", respBody);
await promise;
},
);