Skip to content
Draft
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
61 changes: 46 additions & 15 deletions lib/http-proxy/common.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import type { NormalizedServerOptions, ProxyTargetDetailed, ServerOptions } from "./index";
import type {
NormalizedServerOptions,
ProxyTargetDetailed,
ServerOptions,
} from "./index";
import { type IncomingMessage as Request } from "node:http";
import { TLSSocket } from "node:tls";
import type { Socket } from "node:net";
Expand All @@ -17,6 +21,7 @@ export interface Outgoing extends Outgoing0 {
headers: { [header: string]: string | string[] | undefined } & {
overwritten?: boolean;
};
url: string;
}

// If we allow this header and a user sends it with a request,
Expand All @@ -28,11 +33,13 @@ export interface Outgoing extends Outgoing0 {
const HEADER_BLACKLIST = "trailer";

const HTTP2_HEADER_BLACKLIST = [
':method',
':path',
':scheme',
':authority',
]
":method",
":path",
":scheme",
":authority",
"connection",
"keep-alive",
];

// setupOutgoing -- Copies the right headers from `options` and `req` to
// `outgoing` which is then used to fire the proxied request by calling
Expand All @@ -51,8 +58,10 @@ export function setupOutgoing(
// the final path is target path + relative path requested by user:
const target = options[forward || "target"]!;

outgoing.port =
+(target.port ?? (target.protocol !== undefined && isSSL.test(target.protocol) ? 443 : 80));
outgoing.port = +(
target.port ??
(target.protocol !== undefined && isSSL.test(target.protocol) ? 443 : 80)
);

for (const e of [
"host",
Expand Down Expand Up @@ -125,7 +134,9 @@ export function setupOutgoing(

// target if defined is a URL object so has attribute "pathname", not "path".
const targetPath =
target && options.prependPath !== false && 'pathname' in target ? getPath(`${target.pathname}${target.search ?? ""}`) : "/";
target && options.prependPath !== false && "pathname" in target
? getPath(`${target.pathname}${target.search ?? ""}`)
: "/";

let outgoingPath = options.toProxy ? req.url : getPath(req.url);

Expand All @@ -139,11 +150,25 @@ export function setupOutgoing(
if (options.changeOrigin) {
outgoing.headers.host =
target.protocol !== undefined &&
required(outgoing.port, target.protocol) &&
!hasPort(outgoing.host)
required(outgoing.port, target.protocol) &&
!hasPort(outgoing.host)
? outgoing.host + ":" + outgoing.port
: outgoing.host;
}

outgoing.url = ("href" in target &&
target.href) ||
(target.protocol === "https" ? "https" : "http") +
"://" +
outgoing.host +
(outgoing.port ? ":" + outgoing.port : "");

if (req.httpVersionMajor > 1) {
for (const header of HTTP2_HEADER_BLACKLIST) {
delete outgoing.headers[header];
}
}

return outgoing;
}

Expand Down Expand Up @@ -281,17 +306,23 @@ function hasPort(host: string): boolean {
}

function getPath(url?: string): string {
if (url === '' || url?.startsWith('?')) {
return url
if (url === "" || url?.startsWith("?")) {
return url;
}
const u = toURL(url);
return `${u.pathname ?? ""}${u.search ?? ""}`;
}

export function toURL(url: URL | urllib.Url | ProxyTargetDetailed | string | undefined): URL {
export function toURL(
url: URL | urllib.Url | ProxyTargetDetailed | string | undefined,
): URL {
if (url instanceof URL) {
return url;
} else if (typeof url === "object" && 'href' in url && typeof url.href === "string") {
} else if (
typeof url === "object" &&
"href" in url &&
typeof url.href === "string"
) {
url = url.href;
}
if (!url) {
Expand Down
Loading