From 1bd439cffdfc91044d088575d393062fe5746222 Mon Sep 17 00:00:00 2001 From: Steven Chim <655241+chimurai@users.noreply.github.com> Date: Tue, 19 May 2026 22:34:39 +0000 Subject: [PATCH] fix: preserve path when target includes path --- src/_utils.ts | 2 +- test/_utils.test.ts | 31 ++++++++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/_utils.ts b/src/_utils.ts index 97597a2..42b263e 100644 --- a/src/_utils.ts +++ b/src/_utils.ts @@ -194,7 +194,7 @@ export function joinURL(base: string | undefined, path: string | undefined): str if (!base || base === "/") { return path || "/"; } - if (!path) { + if (!path || path === "/") { return base; } // eslint-disable-next-line unicorn/prefer-at diff --git a/test/_utils.test.ts b/test/_utils.test.ts index ac5fe6d..0ceee0c 100644 --- a/test/_utils.test.ts +++ b/test/_utils.test.ts @@ -377,6 +377,19 @@ describe("lib/http-proxy/common.js", () => { expect(outgoing.path).to.eql("/?project=example&path="); }); + it("should not add trailing slash when target has base path and request path is root", () => { + const outgoing = createOutgoing(); + common.setupOutgoing( + outgoing, + { + target: URL.parse("http://localhost/api")!, + }, + stubIncomingMessage({ url: "/" }), + ); + + expect(outgoing.path).to.eql("/api"); + }); + it("should not modify the query string", () => { const outgoing = createOutgoing(); common.setupOutgoing( @@ -694,13 +707,25 @@ describe("lib/http-proxy/common.js", () => { expect(common.joinURL("/base/", "path")).to.eql("/base/path"); }); - it("should preserve trailing slash when path is exactly /", () => { - expect(common.joinURL("/maildev", "/")).to.eql("/maildev/"); + it("should return base when path is exactly /", () => { + expect(common.joinURL("/maildev", "/")).to.eql("/maildev"); }); - it("should keep a single trailing slash when both base ends and path is /", () => { + it("should return base when base ends with slash and path is /", () => { expect(common.joinURL("/maildev/", "/")).to.eql("/maildev/"); }); + + it("should return base when path is empty", () => { + expect(common.joinURL("/api", "")).to.eql("/api"); + }); + + it("should join base and nested path", () => { + expect(common.joinURL("/api", "/users")).to.eql("/api/users"); + }); + + it("should join base with trailing slash and nested path", () => { + expect(common.joinURL("/api/", "/users")).to.eql("/api/users"); + }); }); describe("#rewriteCookieProperty", () => {