diff --git a/packages/core/src/utils/http.ts b/packages/core/src/utils/http.ts index f63d93ed..d0756bb6 100644 --- a/packages/core/src/utils/http.ts +++ b/packages/core/src/utils/http.ts @@ -82,11 +82,36 @@ export function setHeaders(res: http.ServerResponse, headers: Headers = {}): voi } export function getBaseUrl(req: http.IncomingMessage): string { - const proto = getHeader(req, 'x-forwarded-proto'); - const host = getHeader(req, 'host') || getHeader(req, 'x-forwarded-host'); + let { proto, host } = extractForwarded(req); + host ||= extractHost(req); + proto ||= extractProto(req); if (!host) return ''; - if (!proto) return `//${host}`; - return `${proto}://${host}`; + return proto ? `${proto}://${host}` : `//${host}`; +} + +function extractProto(req: http.IncomingMessage): string { + return getHeader(req, 'x-forwarded-proto'); +} + +function extractHost(req: http.IncomingMessage): string { + return getHeader(req, 'host') || getHeader(req, 'x-forwarded-host'); +} + +function extractForwarded(req: http.IncomingMessage): { proto: string; host: string } { + // Forwarded: by=;for=;host=;proto= + let proto = ''; + let host = ''; + const header = getHeader(req, 'forwarded'); + if (header) { + const kvPairs = header.split(';'); + for (const kv of kvPairs) { + const [token, value] = kv.split('='); + if (token === 'proto') proto = value; + if (token === 'host') host = value; + } + } + + return { proto, host }; } export function responseToTuple(response: UploadxResponse | ResponseTuple): ResponseTuple { diff --git a/test/util.spec.ts b/test/util.spec.ts index 74eadf6a..33256da0 100644 --- a/test/util.spec.ts +++ b/test/util.spec.ts @@ -138,6 +138,11 @@ describe('utils', () => { req.headers = { ...req.headers, 'x-forwarded-proto': 'http' }; expect(utils.getBaseUrl(req)).toBe('http://example'); }); + + it('getBaseUrl(forwarded)', () => { + req.headers = { ...req.headers, forwarded: 'by=by;for=for;host=example;proto=https' }; + expect(utils.getBaseUrl(req)).toBe('https://example'); + }); }); describe('primitives', () => {