From 339bc44c58635f5a4b8b7410ae9fd256c13fe134 Mon Sep 17 00:00:00 2001 From: Yoshiya Hinosawa Date: Fri, 17 Jan 2025 12:30:00 +0900 Subject: [PATCH] fix(ext/node): propagate socket error to client request object (#27678) Co-authored-by: Satya Rohith --- ext/node/polyfills/http.ts | 15 +++++++++++++-- tests/unit_node/http_test.ts | 11 +++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/ext/node/polyfills/http.ts b/ext/node/polyfills/http.ts index f698ca01b3..ff85a61531 100644 --- a/ext/node/polyfills/http.ts +++ b/ext/node/polyfills/http.ts @@ -455,8 +455,13 @@ class ClientRequest extends OutgoingMessage { (async () => { try { const parsedUrl = new URL(url); - let baseConnRid = - this.socket._handle[kStreamBaseField][internalRidSymbol]; + const handle = this.socket._handle; + if (!handle) { + // Using non-standard socket. There's no way to handle this type of socket. + // This should be only happening in artificial test cases + return; + } + let baseConnRid = handle[kStreamBaseField][internalRidSymbol]; if (this._encrypted) { [baseConnRid] = op_tls_start({ rid: baseConnRid, @@ -637,6 +642,12 @@ class ClientRequest extends OutgoingMessage { }; this.socket = socket; this.emit("socket", socket); + socket.once("error", (err) => { + // This callback loosely follow `socketErrorListener` in Node.js + // https://github.com/nodejs/node/blob/f16cd10946ca9ad272f42b94f00cf960571c9181/lib/_http_client.js#L509 + emitErrorEvent(this, err); + socket.destroy(err); + }); if (socket.readyState === "opening") { socket.on("connect", onConnect); } else { diff --git a/tests/unit_node/http_test.ts b/tests/unit_node/http_test.ts index 7478546617..b4f0d260aa 100644 --- a/tests/unit_node/http_test.ts +++ b/tests/unit_node/http_test.ts @@ -1881,3 +1881,14 @@ Deno.test("[node/http] decompress brotli response", { "localhost:3000", ], ["user-agent", "Deno/2.1.1"]]); }); + +Deno.test("[node/http] an error with DNS propagates to request object", async () => { + const { resolve, promise } = Promise.withResolvers(); + const req = http.request("http://invalid-hostname.test", () => {}); + req.on("error", (err) => { + assertEquals(err.name, "Error"); + assertEquals(err.message, "getaddrinfo ENOTFOUND invalid-hostname.test"); + resolve(); + }); + await promise; +});