Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions src/middleware/web-outgoing.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { rewriteCookieProperty } from "../_utils.ts";
import type { ProxyTarget, ProxyTargetDetailed } from "../types.ts";
import { type ProxyOutgoingMiddleware, defineProxyOutgoingMiddleware } from "./_utils.ts";

const redirectRegex = /^201|30([1278])$/;
Expand Down Expand Up @@ -37,8 +38,7 @@ export const setRedirectHostRewrite = defineProxyOutgoingMiddleware(
proxyRes.headers.location &&
redirectRegex.test(String(proxyRes.statusCode))
) {
const target =
options.target instanceof URL ? options.target : new URL(options.target as string | URL);
const target = _toURL(options.target!);
const u = new URL(proxyRes.headers.location, target);

// Make sure the redirected host matches the target host before rewriting
Expand Down Expand Up @@ -146,3 +146,19 @@ export const webOutgoingMiddleware: readonly ProxyOutgoingMiddleware[] = [
writeHeaders,
writeStatusCode,
] as const;

// --- Internal ---

function _toURL(target: ProxyTarget): URL {
if (target instanceof URL) {
return target;
}
if (typeof target === "string") {
return new URL(target);
}
const protocol = (target as ProxyTargetDetailed).protocol || "http:";
const host =
(target as ProxyTargetDetailed).host || (target as ProxyTargetDetailed).hostname || "localhost";
const port = (target as ProxyTargetDetailed).port;
return new URL(`${protocol}//${host}${port ? ":" + port : ""}`);
}
30 changes: 30 additions & 0 deletions test/middleware/web-outgoing.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,36 @@ describe("middleware:web-outgoing", () => {
});
});

describe("handles object target (ProxyTargetDetailed)", () => {
it("rewrites location when target is an object with hostRewrite", () => {
ctx.options.target = {
protocol: "http:",
host: "backend.com",
hostname: "backend.com",
};
ctx.options.hostRewrite = "ext-manual.com";
webOutgoing.setRedirectHostRewrite(
ctx.req,
stubServerResponse(),
ctx.proxyRes,
ctx.options,
);
expect(ctx.proxyRes.headers.location).to.eql("http://ext-manual.com/");
});

it("rewrites location when target is a URL instance", () => {
ctx.options.target = new URL("http://backend.com");
ctx.options.hostRewrite = "ext-manual.com";
webOutgoing.setRedirectHostRewrite(
ctx.req,
stubServerResponse(),
ctx.proxyRes,
ctx.options,
);
expect(ctx.proxyRes.headers.location).to.eql("http://ext-manual.com/");
});
});

describe("rewrites location protocol with protocolRewrite", () => {
beforeEach(() => {
ctx.options.protocolRewrite = "https";
Expand Down
Loading