From 968dbf9dc8e228e1ae9b22f9f0804278722bf188 Mon Sep 17 00:00:00 2001 From: Del Reed Date: Wed, 21 Feb 2024 16:47:02 +0000 Subject: [PATCH 1/4] feat: plumb app_protocol for forwarded http_endpoint --- examples/ngrok-http2.js | 2 +- index.d.ts | 2 +- src/config.rs | 1 + src/connect.rs | 1 + 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/ngrok-http2.js b/examples/ngrok-http2.js index 5fe0a25..4f452db 100644 --- a/examples/ngrok-http2.js +++ b/examples/ngrok-http2.js @@ -1,5 +1,5 @@ -const ngrok = require("../index.js"); const http2 = require("node:http2"); +const ngrok = require("@ngrok/ngrok"); const server = http2.createServer(); server.on("error", (err) => console.error(err)); diff --git a/index.d.ts b/index.d.ts index 92b0360..c93d2e0 100644 --- a/index.d.ts +++ b/index.d.ts @@ -15,7 +15,7 @@ export interface Config { */ addr?: number|string /** The L7 application protocol to use for this edge, e.g. "http2" or "http1". */ - appProtocol?: string + app_protocol?: string auth?: string|Array /** * Configures the session to authenticate with the provided authtoken. You diff --git a/src/config.rs b/src/config.rs index a050ac9..d0ad3e3 100644 --- a/src/config.rs +++ b/src/config.rs @@ -11,6 +11,7 @@ pub struct Config { #[napi(ts_type = "number|string")] pub addr: Option, /// The L7 application protocol to use for this edge, e.g. "http2" or "http1". + #[napi(js_name = "app_protocol")] pub app_protocol: Option, // Synonym for basic_auth #[napi(ts_type = "string|Array")] diff --git a/src/connect.rs b/src/connect.rs index bcab23f..f877862 100644 --- a/src/connect.rs +++ b/src/connect.rs @@ -196,6 +196,7 @@ async fn http_endpoint(session: &Session, cfg: &Config) -> Result { plumb_vec!(bld, cfg, scheme, schemes); plumb!(bld, cfg, domain, hostname); // synonym for domain plumb!(bld, cfg, domain); + plumb!(bld, cfg, app_protocol); plumb_vec!(bld, cfg, mutual_tlsca, mutual_tls_cas, vecu8); plumb_bool!(bld, cfg, compression); plumb_bool!(bld, cfg, websocket_tcp_conversion, websocket_tcp_converter); From fb9918366a2d5e81e5e2974beeadd7956346043f Mon Sep 17 00:00:00 2001 From: Del Reed Date: Wed, 21 Feb 2024 16:50:42 +0000 Subject: [PATCH 2/4] chore: update forward example --- examples/ngrok-forward-full.js | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/ngrok-forward-full.js b/examples/ngrok-forward-full.js index a056ada..a7b75dd 100644 --- a/examples/ngrok-forward-full.js +++ b/examples/ngrok-forward-full.js @@ -24,6 +24,7 @@ ngrok.consoleLog("INFO"); // turn on info logging // session configuration addr: `unix:${UNIX_SOCKET}`, // addr: `localhost:8080`, + // app_protocol: "http1", // authtoken: "", authtoken_from_env: true, on_status_change: (addr, error) => { From 1833adc25d330408d5405ec471b1a0002f43ebcc Mon Sep 17 00:00:00 2001 From: Del Reed Date: Wed, 21 Feb 2024 18:52:00 +0000 Subject: [PATCH 3/4] feat: add testing on http2 forwarding --- __test__/connect.spec.mjs | 45 +++++++++++++++++++++++++++++++--- examples/ngrok-forward-full.js | 2 +- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/__test__/connect.spec.mjs b/__test__/connect.spec.mjs index 01e8bf7..a4e1554 100644 --- a/__test__/connect.spec.mjs +++ b/__test__/connect.spec.mjs @@ -6,13 +6,19 @@ import axios, { AxiosError } from "axios"; import axiosRetry from "axios-retry"; import * as fs from "fs"; import * as http from "http"; +import * as http2 from "http2"; import * as retry from "./retry-config.mjs"; import * as path from "path"; +import exp from "constants"; axiosRetry(axios, retry.retryConfig); const expected = "Hello"; -function createHttpServer() { +function createHttpServer({ protocol }) { + if (protocol === "http2") { + return createHttp2Server(); + } + return http.createServer(function (req, res) { res.writeHead(200); res.write(expected); @@ -20,8 +26,22 @@ function createHttpServer() { }); } -async function makeHttp(useUnixSocket) { - const server = createHttpServer(); +function createHttp2Server() { + const server = http2.createServer(); + + server.on("stream", (stream, headers) => { + stream.respond({ + ":status": 200, + }); + stream.end(expected); + }); + + return server; +} + +async function makeHttp(options = {}) { + const { useUnixSocket = false, useHttp2 = false } = options; + const server = createHttpServer({ protocol: useHttp2 ? "http2" : "http" }); const listenTo = useUnixSocket ? "tun-" + Math.floor(Math.random() * 1000000) : 0; const socket = await server.listen(listenTo); server.socket = socket; @@ -60,6 +80,25 @@ test("forward https", async (t) => { await validateShutdown(t, httpServer, url); }); +test("forward http2", async (t) => { + const httpServer = await makeHttp(false, true); + const listener = await ngrok.forward({ + // numeric port + addr: parseInt(httpServer.listenTo.split(":")[1], 10), + // authtoken from env + authtoken: process.env["NGROK_AUTHTOKEN"], + // The L7 app_protocol + app_protocol: "http2", + }); + + const url = listener.url(); + t.truthy(url.startsWith("https://"), url); + const res = await validateShutdown(t, httpServer, url); + + t.assert(res.status === 200); + t.assert(res.data.includes(expected)); +}); + test("connect number", async (t) => { const httpServer = await makeHttp(); ngrok.authtoken(process.env["NGROK_AUTHTOKEN"]); diff --git a/examples/ngrok-forward-full.js b/examples/ngrok-forward-full.js index a7b75dd..bf57a21 100644 --- a/examples/ngrok-forward-full.js +++ b/examples/ngrok-forward-full.js @@ -24,7 +24,7 @@ ngrok.consoleLog("INFO"); // turn on info logging // session configuration addr: `unix:${UNIX_SOCKET}`, // addr: `localhost:8080`, - // app_protocol: "http1", + // app_protocol: "http2", // authtoken: "", authtoken_from_env: true, on_status_change: (addr, error) => { From df7af05e111dda2c892ae4a4ca310b4d68bb9211 Mon Sep 17 00:00:00 2001 From: Del Reed Date: Thu, 22 Feb 2024 15:40:46 +0000 Subject: [PATCH 4/4] fix: use makeHttp options in test/forward-http2 --- __test__/connect.spec.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__test__/connect.spec.mjs b/__test__/connect.spec.mjs index a4e1554..3cc56f4 100644 --- a/__test__/connect.spec.mjs +++ b/__test__/connect.spec.mjs @@ -81,7 +81,7 @@ test("forward https", async (t) => { }); test("forward http2", async (t) => { - const httpServer = await makeHttp(false, true); + const httpServer = await makeHttp({useHttp2: true}); const listener = await ngrok.forward({ // numeric port addr: parseInt(httpServer.listenTo.split(":")[1], 10),