From c04a2d1dfc6daa64e4e45175ae69f1659669e6a5 Mon Sep 17 00:00:00 2001 From: Ciro Spaciari Date: Fri, 22 Nov 2024 20:22:35 -0300 Subject: [PATCH] fix regression on http2-wrapper caused by node.js compatibility improvements on net (#15318) --- src/js/node/tls.ts | 49 +++++----- test/bun.lockb | Bin 374338 -> 375426 bytes test/js/node/test/parallel/http2-pipe.test.js | 50 +++++----- test/js/node/tls/node-tls-connect.test.ts | 12 ++- .../http2-wrapper/http2-wrapper.test.ts | 89 ++++++++++++++++++ .../js/third_party/http2-wrapper/package.json | 7 ++ test/package.json | 1 + 7 files changed, 160 insertions(+), 48 deletions(-) create mode 100644 test/js/third_party/http2-wrapper/http2-wrapper.test.ts create mode 100644 test/js/third_party/http2-wrapper/package.json diff --git a/src/js/node/tls.ts b/src/js/node/tls.ts index 09408fa9c0..46d0fa1113 100644 --- a/src/js/node/tls.ts +++ b/src/js/node/tls.ts @@ -2,6 +2,8 @@ const { isArrayBufferView, isTypedArray } = require("node:util/types"); const { addServerName } = require("../internal/net"); const net = require("node:net"); +const { Duplex } = require("node:stream"); + const { Server: NetServer, [Symbol.for("::bunternal::")]: InternalTCPSocket } = net; const { rootCertificates, canonicalizeIP } = $cpp("NodeTLS.cpp", "createNodeTLSBinding"); @@ -326,21 +328,22 @@ const TLSSocket = (function (InternalTLSSocket) { class TLSSocket extends InternalTCPSocket { #secureContext; ALPNProtocols; - #socket; #checkServerIdentity; #session; alpnProtocol = null; constructor(socket, options) { - super(socket instanceof InternalTCPSocket ? options : options || socket); + super(socket instanceof InternalTCPSocket || socket instanceof Duplex ? options : options || socket); options = options || socket || {}; if (typeof options === "object") { const { ALPNProtocols } = options; if (ALPNProtocols) { convertALPNProtocols(ALPNProtocols, this); } - if (socket instanceof InternalTCPSocket) { - this.#socket = socket; + if (socket instanceof InternalTCPSocket || socket instanceof Duplex) { + this._handle = socket; + // keep compatibility with http2-wrapper or other places that try to grab JSStreamSocket in node.js, with here is just the TLSSocket + this._handle._parentWrap = this; } } @@ -373,31 +376,31 @@ const TLSSocket = (function (InternalTLSSocket) { } getSession() { - return this._handle?.getSession(); + return this._handle?.getSession?.(); } getEphemeralKeyInfo() { - return this._handle?.getEphemeralKeyInfo(); + return this._handle?.getEphemeralKeyInfo?.(); } getCipher() { - return this._handle?.getCipher(); + return this._handle?.getCipher?.(); } getSharedSigalgs() { - return this._handle?.getSharedSigalgs(); + return this._handle?.getSharedSigalgs?.(); } getProtocol() { - return this._handle?.getTLSVersion(); + return this._handle?.getTLSVersion?.(); } getFinished() { - return this._handle?.getTLSFinishedMessage() || undefined; + return this._handle?.getTLSFinishedMessage?.() || undefined; } getPeerFinished() { - return this._handle?.getTLSPeerFinishedMessage() || undefined; + return this._handle?.getTLSPeerFinishedMessage?.() || undefined; } isSessionReused() { return !!this.#session; @@ -424,13 +427,13 @@ const TLSSocket = (function (InternalTLSSocket) { if (options.rejectUnauthorized !== undefined) rejectUnauthorized = !!options.rejectUnauthorized; if (requestCert !== this._requestCert || rejectUnauthorized !== this._rejectUnauthorized) { - socket.setVerifyMode(requestCert, rejectUnauthorized); + socket.setVerifyMode?.(requestCert, rejectUnauthorized); this._requestCert = requestCert; this._rejectUnauthorized = rejectUnauthorized; } } try { - socket.renegotiate(); + socket.renegotiate?.(); // if renegotiate is successful should emit secure event when done typeof callback === "function" && this.once("secure", () => callback(null)); return true; @@ -444,21 +447,21 @@ const TLSSocket = (function (InternalTLSSocket) { disableRenegotiation() { this.#renegotiationDisabled = true; // disable renegotiation on the socket - return this._handle?.disableRenegotiation(); + return this._handle?.disableRenegotiation?.(); } getTLSTicket() { - return this._handle?.getTLSTicket(); + return this._handle?.getTLSTicket?.(); } exportKeyingMaterial(length, label, context) { if (context) { - return this._handle?.exportKeyingMaterial(length, label, context); + return this._handle?.exportKeyingMaterial?.(length, label, context); } - return this._handle?.exportKeyingMaterial(length, label); + return this._handle?.exportKeyingMaterial?.(length, label); } setMaxSendFragment(size) { - return this._handle?.setMaxSendFragment(size) || false; + return this._handle?.setMaxSendFragment?.(size) || false; } // only for debug purposes so we just mock for now @@ -472,23 +475,23 @@ const TLSSocket = (function (InternalTLSSocket) { } // if the socket is detached we can't set the servername but we set this property so when open will auto set to it this.servername = name; - this._handle?.setServername(name); + this._handle?.setServername?.(name); } setSession(session) { this.#session = session; if (typeof session === "string") session = Buffer.from(session, "latin1"); - return this._handle?.setSession(session); + return this._handle?.setSession?.(session); } getPeerCertificate(abbreviated) { const cert = - arguments.length < 1 ? this._handle?.getPeerCertificate() : this._handle?.getPeerCertificate(abbreviated); + arguments.length < 1 ? this._handle?.getPeerCertificate?.() : this._handle?.getPeerCertificate?.(abbreviated); if (cert) { return translatePeerCertificate(cert); } } getCertificate() { // need to implement certificate on socket.zig - const cert = this._handle?.getCertificate(); + const cert = this._handle?.getCertificate?.(); if (cert) { // It's not a peer cert, but the formatting is identical. return translatePeerCertificate(cert); @@ -503,7 +506,7 @@ const TLSSocket = (function (InternalTLSSocket) { [buntls](port, host) { return { - socket: this.#socket, + socket: this._handle, ALPNProtocols: this.ALPNProtocols, serverName: this.servername || host || "localhost", checkServerIdentity: this.#checkServerIdentity, diff --git a/test/bun.lockb b/test/bun.lockb index 13caab649147e2c3f097ca8a0534289c5b204c98..6a1061e911b76ab6b2492a1669ec0bb3ba2fb9ed 100755 GIT binary patch delta 57870 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

    l%y#)Kiu_M;<}!L< z)X2!ep+oBoi-?TqKPqh4nErM83=5|;2SZ!=lNTe<{?kXQVr*Eg(#NK#{rG>JiW^o- uzdOpXeUmb)_8~Qke;fCa?`}h91V8g0T)AOA@5rJnYR#YfC}Owa*?$2hAE0mm delta 57295 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 JZklP*{{SpaR9FB2 diff --git a/test/js/node/test/parallel/http2-pipe.test.js b/test/js/node/test/parallel/http2-pipe.test.js index 02e6e8f212..0f852cef61 100644 --- a/test/js/node/test/parallel/http2-pipe.test.js +++ b/test/js/node/test/parallel/http2-pipe.test.js @@ -1,17 +1,19 @@ //#FILE: test-http2-pipe.js //#SHA1: bb970b612d495580b8c216a1b202037e5eb0721e //----------------- -'use strict'; +"use strict"; -const http2 = require('http2'); -const fs = require('fs'); -const path = require('path'); -const os = require('os'); +import { afterEach, beforeEach, test, expect, describe, mock } from "bun:test"; + +const http2 = require("http2"); +const fs = require("fs"); +const path = require("path"); +const os = require("os"); // Skip the test if crypto is not available let hasCrypto; try { - require('crypto'); + require("crypto"); hasCrypto = true; } catch (err) { hasCrypto = false; @@ -19,30 +21,30 @@ try { const testIfCrypto = hasCrypto ? test : test.skip; -describe('HTTP2 Pipe', () => { +describe("HTTP2 Pipe", () => { let server; let serverPort; let tmpdir; - const fixturesDir = path.join(__dirname, '..', 'fixtures'); - const loc = path.join(fixturesDir, 'person-large.jpg'); + const fixturesDir = path.join(__dirname, "..", "fixtures"); + const loc = path.join(fixturesDir, "person-large.jpg"); let fn; - beforeAll(async () => { - tmpdir = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'http2-test-')); - fn = path.join(tmpdir, 'http2-url-tests.js'); + beforeEach(() => { + tmpdir = fs.mkdtempSync(path.join(os.tmpdir(), "http2-test-")); + fn = path.join(tmpdir, "http2-url-tests.js"); }); - afterAll(async () => { - await fs.promises.rm(tmpdir, { recursive: true, force: true }); + afterEach(() => { + fs.rmSync(tmpdir, { recursive: true, force: true }); }); - testIfCrypto('Piping should work as expected with createWriteStream', (done) => { + testIfCrypto("Piping should work as expected with createWriteStream", done => { server = http2.createServer(); - server.on('stream', (stream) => { + server.on("stream", stream => { const dest = stream.pipe(fs.createWriteStream(fn)); - dest.on('finish', () => { + dest.on("finish", () => { expect(fs.readFileSync(loc).length).toBe(fs.readFileSync(fn).length); }); stream.respond(); @@ -53,13 +55,13 @@ describe('HTTP2 Pipe', () => { serverPort = server.address().port; const client = http2.connect(`http://localhost:${serverPort}`); - const req = client.request({ ':method': 'POST' }); + const req = client.request({ ":method": "POST" }); - const responseHandler = jest.fn(); - req.on('response', responseHandler); + const responseHandler = mock(() => {}); + req.on("response", responseHandler); req.resume(); - req.on('close', () => { + req.on("close", () => { expect(responseHandler).toHaveBeenCalled(); server.close(); client.close(); @@ -67,11 +69,11 @@ describe('HTTP2 Pipe', () => { }); const str = fs.createReadStream(loc); - const strEndHandler = jest.fn(); - str.on('end', strEndHandler); + const strEndHandler = mock(() => {}); + str.on("end", strEndHandler); str.pipe(req); - req.on('finish', () => { + req.on("finish", () => { expect(strEndHandler).toHaveBeenCalled(); }); }); diff --git a/test/js/node/tls/node-tls-connect.test.ts b/test/js/node/tls/node-tls-connect.test.ts index bb8168e00a..8ecbb11bb6 100644 --- a/test/js/node/tls/node-tls-connect.test.ts +++ b/test/js/node/tls/node-tls-connect.test.ts @@ -3,6 +3,7 @@ import { tls as COMMON_CERT_ } from "harness"; import net from "net"; import { join } from "path"; import tls, { checkServerIdentity, connect as tlsConnect, TLSSocket } from "tls"; +import stream from "stream"; import { Duplex } from "node:stream"; @@ -116,7 +117,16 @@ it("should have checkServerIdentity", async () => { expect(checkServerIdentity).toBeFunction(); expect(tls.checkServerIdentity).toBeFunction(); }); - +it("should be able to grab the JSStreamSocket constructor", () => { + // this keep http2-wrapper compatibility with node.js + const socket = new tls.TLSSocket(new stream.PassThrough()); + //@ts-ignore + expect(socket._handle).not.toBeNull(); + //@ts-ignore + expect(socket._handle._parentWrap).not.toBeNull(); + //@ts-ignore + expect(socket._handle._parentWrap.constructor).toBeFunction(); +}); for (const { name, connect } of tests) { describe(name, () => { it("should work with alpnProtocols", done => { diff --git a/test/js/third_party/http2-wrapper/http2-wrapper.test.ts b/test/js/third_party/http2-wrapper/http2-wrapper.test.ts new file mode 100644 index 0000000000..7faad0efb2 --- /dev/null +++ b/test/js/third_party/http2-wrapper/http2-wrapper.test.ts @@ -0,0 +1,89 @@ +import { test, expect } from "bun:test"; +import { tls } from "harness"; +import http2Wrapper from "http2-wrapper"; +import type { AutoRequestOptions } from "http2-wrapper"; +import http from "http"; + +async function doRequest(options: AutoRequestOptions) { + const { promise, resolve, reject } = Promise.withResolvers(); + const request = await http2Wrapper.auto(options, (response: http.IncomingMessage) => { + if (response.statusCode !== 200) { + return reject(new Error(`expected status code 200 rejected: ${response.statusCode}`)); + } + + const body: Array = []; + response.on("error", reject); + response.on("data", (chunk: Buffer) => body.push(chunk)); + response.on("end", () => { + resolve(Buffer.concat(body).toString()); + }); + }); + + request.on("error", reject); + + request.end("123456"); + const body = (await promise) as string; + expect(body).toBeString(); + const parsed = JSON.parse(body); + expect(parsed.data).toBe("123456"); +} + +test("should allow http/1.1 when using http2-wrapper", async () => { + { + using server = Bun.serve({ + async fetch(req) { + return new Response( + JSON.stringify({ + data: await req.text(), + }), + { + headers: { + "content-type": "application/json", + }, + }, + ); + }, + }); + + await doRequest({ + host: "localhost", + port: server.port, + protocol: "http:", + path: "/post", + method: "POST", + headers: { + "content-length": 6, + }, + }); + } + + { + using server = Bun.serve({ + tls, + hostname: "localhost", + async fetch(req) { + return new Response( + JSON.stringify({ + data: await req.text(), + }), + { + headers: { + "content-type": "application/json", + }, + }, + ); + }, + }); + await doRequest({ + host: "localhost", + port: server.port, + protocol: "https:", + path: "/post", + method: "POST", + ca: tls.cert, + headers: { + "content-length": 6, + }, + }); + } +}); diff --git a/test/js/third_party/http2-wrapper/package.json b/test/js/third_party/http2-wrapper/package.json new file mode 100644 index 0000000000..d2205f27e3 --- /dev/null +++ b/test/js/third_party/http2-wrapper/package.json @@ -0,0 +1,7 @@ +{ + "name": "http2-wrapper-test", + "version": "1.0.0", + "dependencies": { + "http2-wrapper": "2.2.1" + } +} diff --git a/test/package.json b/test/package.json index b360be82bb..03a8717ce3 100644 --- a/test/package.json +++ b/test/package.json @@ -26,6 +26,7 @@ "express": "4.18.2", "fast-glob": "3.3.1", "filenamify": "6.0.0", + "http2-wrapper": "2.2.1", "https-proxy-agent": "7.0.5", "iconv-lite": "0.6.3", "isbot": "5.1.13",