From 44d5e5e61f8a5dc885279c0c2c2fc7c0a37d71fd Mon Sep 17 00:00:00 2001
From: Alexei Boronine <alexei@boronine.com>
Date: Sun, 3 Nov 2024 23:00:36 +0100
Subject: [PATCH] wip

---
 src/h2tunnel.test.ts |  8 +++++---
 src/h2tunnel.ts      | 23 ++++++++++-------------
 2 files changed, 15 insertions(+), 16 deletions(-)

diff --git a/src/h2tunnel.test.ts b/src/h2tunnel.test.ts
index 9b2a386..400ef89 100644
--- a/src/h2tunnel.test.ts
+++ b/src/h2tunnel.test.ts
@@ -6,6 +6,7 @@ import {
   TunnelServer,
 } from "./h2tunnel.js";
 import net from "node:net";
+import * as http2 from "node:http2";
 
 // localhost HTTP1 server "python3 -m http.server"
 const LOCAL_PORT = 14000;
@@ -372,7 +373,7 @@ class EchoServer {
   }
 }
 
-await test(
+await test.only(
   "basic connection and termination",
   { timeout: 10000 },
   async (t) => {
@@ -391,9 +392,10 @@ await test(
         | "localhost"
       )[]) {
         for (const proxyPort of [LOCAL_PORT, PROXY_TEST_PORT, PROXY_PORT]) {
-          // if (term !== "FIN" || by !== "client") {
+          // if (term !== "RST" || by !== "browser" || proxyPort !== PROXY_PORT) {
           //   continue;
           // }
+          // clean termination by browser RST on 14004
           console.log(`clean termination by ${by} ${term} on ${proxyPort}`);
           const echoServer = new EchoServer(LOCAL_PORT, proxyPort);
           await echoServer.startAndWaitUntilReady();
@@ -422,7 +424,7 @@ await test(
   },
 );
 
-await test.only("happy-path", { timeout: 5000 }, async (t) => {
+await test("happy-path", { timeout: 5000 }, async (t) => {
   const echo = new EchoServer(LOCAL_PORT, PROXY_PORT);
   await echo.startAndWaitUntilReady();
 
diff --git a/src/h2tunnel.ts b/src/h2tunnel.ts
index 3d9c2bd..feb35c4 100644
--- a/src/h2tunnel.ts
+++ b/src/h2tunnel.ts
@@ -162,28 +162,25 @@ export abstract class AbstractTunnel<
       });
       let endTimeout: NodeJS.Timeout | null = null;
       duplex1.on("end", () => {
-        log({ [tag]: "end" });
-        // 'end' comes before 'error', so we need to wait make sure 'error' doesn't come it before processing 'end'
-        // https://github.com/nodejs/node/issues/39400
-        endTimeout = setTimeout(() => {
-          if (!duplex2.writableEnded) {
-            log({ [tag]: "closing opposite" });
-            duplex2.end();
-          }
-        }, 50);
+        log({ [tag]: "end", ts: new Date().getTime() });
+        if (!duplex2.writableEnded) {
+          log({ [tag]: "closing opposite" });
+          duplex2.end();
+        }
       });
 
       duplex1.on("close", () => {
-        log({ [tag]: "close" });
-        if (duplex1.errored && !duplex2.destroyed) {
+        log({ [tag]: "close", ts: new Date().getTime() });
+        if (duplex1.errored && !duplex2.closed) {
           if (endTimeout) {
             clearTimeout(endTimeout);
           }
-          log({ [tag]: "destroying opposite" });
           if (isStream) {
+            log({ [tag]: "destroying socket" });
             socket.resetAndDestroy();
           } else {
-            stream.close(http2.constants.NGHTTP2_INTERNAL_ERROR);
+            log({ [tag]: "destroying stream" });
+            stream.destroy(new Error());
           }
         }
       });