From f643cb3d3092841529da6eb17a598138c4bf792b Mon Sep 17 00:00:00 2001 From: Satya Rohith Date: Wed, 21 Feb 2024 12:31:39 +0530 Subject: [PATCH 1/4] fix(ext/node): pass alpnProtocols to Deno.startTls --- ext/node/polyfills/_tls_wrap.ts | 5 +++-- ext/node/polyfills/http2.ts | 9 +++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/ext/node/polyfills/_tls_wrap.ts b/ext/node/polyfills/_tls_wrap.ts index 315cbf74abea5f..a70dd29f14e61e 100644 --- a/ext/node/polyfills/_tls_wrap.ts +++ b/ext/node/polyfills/_tls_wrap.ts @@ -68,7 +68,7 @@ export class TLSSocket extends net.Socket { secureConnecting: boolean; _SNICallback: any; servername: string | null; - alpnProtocol: any; + alpnProtocols: string[] | null; authorized: boolean; authorizationError: any; [kRes]: any; @@ -96,6 +96,7 @@ export class TLSSocket extends net.Socket { caCerts = [new TextDecoder().decode(caCerts)]; } tlsOptions.caCerts = caCerts; + tlsOptions.alpnProtocols = ["h2", "http/1.1"]; super({ handle: _wrapHandle(tlsOptions, socket), @@ -113,7 +114,7 @@ export class TLSSocket extends net.Socket { this.secureConnecting = true; this._SNICallback = null; this.servername = null; - this.alpnProtocol = null; + this.alpnProtocols = tlsOptions.alpnProtocols; this.authorized = false; this.authorizationError = null; this[kRes] = null; diff --git a/ext/node/polyfills/http2.ts b/ext/node/polyfills/http2.ts index a13953e760ef4d..d86148e4e2d064 100644 --- a/ext/node/polyfills/http2.ts +++ b/ext/node/polyfills/http2.ts @@ -210,11 +210,12 @@ export class Http2Session extends EventEmitter { } goaway( - _code: number, - _lastStreamID: number, - _opaqueData: Buffer | TypedArray | DataView, + code?: number, + lastStreamID?: number, + opaqueData?: Buffer | TypedArray | DataView, ) { - warnNotImplemented("Http2Session.goaway"); + // TODO(satyarohith): create goaway op and pass the args + debugHttp2(">>> goaway - ignored args", code, lastStreamID, opaqueData); if (this[kDenoConnRid]) { core.tryClose(this[kDenoConnRid]); } From dd3cdb254fb90f3063d1d0f36f63b73e85d61133 Mon Sep 17 00:00:00 2001 From: Satya Rohith Date: Wed, 21 Feb 2024 13:01:24 +0530 Subject: [PATCH 2/4] add test --- tests/unit_node/http2_test.ts | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/tests/unit_node/http2_test.ts b/tests/unit_node/http2_test.ts index 2ea2924853dce3..504efa0a37f53b 100644 --- a/tests/unit_node/http2_test.ts +++ b/tests/unit_node/http2_test.ts @@ -2,7 +2,7 @@ import * as http2 from "node:http2"; import * as net from "node:net"; -import { assertEquals } from "@std/assert/mod.ts"; +import { assert, assertEquals } from "@std/assert/mod.ts"; for (const url of ["http://127.0.0.1:4246", "https://127.0.0.1:4247"]) { Deno.test(`[node/http2 client] ${url}`, { @@ -136,3 +136,32 @@ Deno.test("[node/http2 server]", { sanitizeOps: false }, async () => { await new Promise((resolve) => server.close(resolve)); }); + +Deno.test( + "[node/http2 client GET https://google.com]", + { + // TODO(satyarohith): re-enable sanitizers after fixing the leaks + // 2 async operations to resolve a DNS name were started in this test, but never completed. + // This is often caused by not awaiting the result of a `Deno.resolveDns` call + sanitizeOps: false, + }, + () => { + const clientSession = http2.connect("https://google.com"); + const req = clientSession.request({ + ":method": "GET", + ":path": "/", + }); + req.on("response", (headers) => { + assertEquals(headers[":status"], 200); + assert(Object.keys(headers).length > 0); + }); + req.on("data", (chunk) => { + assert(chunk.length > 0); + }); + req.on("end", () => { + clientSession.close(); + req.close(); + }); + req.end(); + }, +); From 6da73f0b55bfb91ae31520065d1297f7b62ccc40 Mon Sep 17 00:00:00 2001 From: Satya Rohith Date: Wed, 21 Feb 2024 13:10:43 +0530 Subject: [PATCH 3/4] fix test --- tests/unit_node/http2_test.ts | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/tests/unit_node/http2_test.ts b/tests/unit_node/http2_test.ts index 504efa0a37f53b..01658c83609691 100644 --- a/tests/unit_node/http2_test.ts +++ b/tests/unit_node/http2_test.ts @@ -145,23 +145,32 @@ Deno.test( // This is often caused by not awaiting the result of a `Deno.resolveDns` call sanitizeOps: false, }, - () => { + async () => { const clientSession = http2.connect("https://google.com"); const req = clientSession.request({ ":method": "GET", ":path": "/", }); - req.on("response", (headers) => { - assertEquals(headers[":status"], 200); - assert(Object.keys(headers).length > 0); + let headers = {}; + let status: number | undefined = 0; + let chunk = new Uint8Array(); + const endPromise = Promise.withResolvers(); + req.on("response", (h) => { + status = h[":status"]; + headers = h; }); - req.on("data", (chunk) => { - assert(chunk.length > 0); + req.on("data", (c) => { + chunk = c; }); req.on("end", () => { clientSession.close(); req.close(); + endPromise.resolve(); }); req.end(); + await endPromise.promise; + assert(Object.keys(headers).length > 0); + assertEquals(status, 200); + assert(chunk.length > 0); }, ); From 50d824ae3a7a8890373ac5f2456646564b391374 Mon Sep 17 00:00:00 2001 From: Satya Rohith Date: Wed, 21 Feb 2024 14:35:16 +0530 Subject: [PATCH 4/4] use example.com --- tests/unit_node/http2_test.ts | 65 +++++++++++++++-------------------- 1 file changed, 28 insertions(+), 37 deletions(-) diff --git a/tests/unit_node/http2_test.ts b/tests/unit_node/http2_test.ts index 01658c83609691..fd9cdd0ec8a091 100644 --- a/tests/unit_node/http2_test.ts +++ b/tests/unit_node/http2_test.ts @@ -137,40 +137,31 @@ Deno.test("[node/http2 server]", { sanitizeOps: false }, async () => { await new Promise((resolve) => server.close(resolve)); }); -Deno.test( - "[node/http2 client GET https://google.com]", - { - // TODO(satyarohith): re-enable sanitizers after fixing the leaks - // 2 async operations to resolve a DNS name were started in this test, but never completed. - // This is often caused by not awaiting the result of a `Deno.resolveDns` call - sanitizeOps: false, - }, - async () => { - const clientSession = http2.connect("https://google.com"); - const req = clientSession.request({ - ":method": "GET", - ":path": "/", - }); - let headers = {}; - let status: number | undefined = 0; - let chunk = new Uint8Array(); - const endPromise = Promise.withResolvers(); - req.on("response", (h) => { - status = h[":status"]; - headers = h; - }); - req.on("data", (c) => { - chunk = c; - }); - req.on("end", () => { - clientSession.close(); - req.close(); - endPromise.resolve(); - }); - req.end(); - await endPromise.promise; - assert(Object.keys(headers).length > 0); - assertEquals(status, 200); - assert(chunk.length > 0); - }, -); +Deno.test("[node/http2 client GET https://www.example.com]", async () => { + const clientSession = http2.connect("https://www.example.com"); + const req = clientSession.request({ + ":method": "GET", + ":path": "/", + }); + let headers = {}; + let status: number | undefined = 0; + let chunk = new Uint8Array(); + const endPromise = Promise.withResolvers(); + req.on("response", (h) => { + status = h[":status"]; + headers = h; + }); + req.on("data", (c) => { + chunk = c; + }); + req.on("end", () => { + clientSession.close(); + req.close(); + endPromise.resolve(); + }); + req.end(); + await endPromise.promise; + assert(Object.keys(headers).length > 0); + assertEquals(status, 200); + assert(chunk.length > 0); +});