From 42991017e9af59d6a5cb6b523228c62f1c32380e Mon Sep 17 00:00:00 2001 From: Matt Mastracci Date: Tue, 6 Jun 2023 04:29:55 -0600 Subject: feat(ext/node): Very basic node:http2 support (#19344) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds basic support for "node:http2" module. Not all APIs have been yet implemented, but this change already allows to use this module for some basic functions. The "grpc" package is still not working, but it's a good stepping stone. --------- Co-authored-by: Bartek IwaƄczuk --- cli/tests/unit_node/http2_test.ts | 104 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 cli/tests/unit_node/http2_test.ts (limited to 'cli/tests/unit_node') diff --git a/cli/tests/unit_node/http2_test.ts b/cli/tests/unit_node/http2_test.ts new file mode 100644 index 000000000..543543cbd --- /dev/null +++ b/cli/tests/unit_node/http2_test.ts @@ -0,0 +1,104 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. + +import * as http2 from "node:http2"; +import * as net from "node:net"; +import { deferred } from "../../../test_util/std/async/deferred.ts"; +import { assertEquals } from "https://deno.land/std@v0.42.0/testing/asserts.ts"; + +const { + HTTP2_HEADER_AUTHORITY, + HTTP2_HEADER_METHOD, + HTTP2_HEADER_PATH, + HTTP2_HEADER_STATUS, +} = http2.constants; + +Deno.test("[node/http2 client]", async () => { + // Create a server to respond to the HTTP2 requests + const portPromise = deferred(); + const reqPromise = deferred(); + const ready = deferred(); + const ac = new AbortController(); + const server = Deno.serve({ + port: 0, + signal: ac.signal, + onListen: ({ port }: { port: number }) => portPromise.resolve(port), + handler: async (req: Request) => { + reqPromise.resolve(req); + await ready; + return new Response("body", { + status: 401, + headers: { "resp-header-name": "resp-header-value" }, + }); + }, + }); + + const port = await portPromise; + + // Get a session + const sessionPromise = deferred(); + const session = http2.connect( + `localhost:${port}`, + {}, + sessionPromise.resolve.bind(sessionPromise), + ); + const session2 = await sessionPromise; + assertEquals(session, session2); + + // Write a request, including a body + const stream = session.request({ + [HTTP2_HEADER_AUTHORITY]: `localhost:${port}`, + [HTTP2_HEADER_METHOD]: "POST", + [HTTP2_HEADER_PATH]: "/path", + "req-header-name": "req-header-value", + }); + stream.write("body"); + stream.end(); + + // Check the request + const req = await reqPromise; + assertEquals(req.headers.get("req-header-name"), "req-header-value"); + assertEquals(await req.text(), "body"); + + ready.resolve(); + + // Read a response + const headerPromise = new Promise>(( + resolve, + ) => stream.on("headers", resolve)); + const headers = await headerPromise; + assertEquals(headers["resp-header-name"], "resp-header-value"); + assertEquals(headers[HTTP2_HEADER_STATUS], "401"); + + ac.abort(); + await server.finished; +}); + +Deno.test("[node/http2 server]", async () => { + const server = http2.createServer(); + server.listen(0); + const port = ( server.address()).port; + const sessionPromise = new Promise((resolve) => + server.on("session", resolve) + ); + + const responsePromise = fetch(`http://localhost:${port}/path`, { + method: "POST", + body: "body", + }); + + const session = await sessionPromise; + const stream = await new Promise((resolve) => + session.on("stream", resolve) + ); + const _headers = await new Promise((resolve) => + stream.on("headers", resolve) + ); + const _data = await new Promise((resolve) => stream.on("data", resolve)); + const _end = await new Promise((resolve) => stream.on("end", resolve)); + stream.respond(); + stream.end(); + const resp = await responsePromise; + await resp.text(); + + await new Promise((resolve) => server.close(resolve)); +}); -- cgit v1.2.3