From a65289c211d2179df8dd34d83ae9198c60d9bb7e Mon Sep 17 00:00:00 2001 From: Jacob Fletcher Date: Fri, 28 Feb 2025 12:26:38 -0500 Subject: [PATCH] fix: ensures req.origin includes port on localhost (#11454) The `req.origin` property on the `PayloadRequest` object does not include the port when running on localhost, a requirement of the [HTML Living Standard](https://html.spec.whatwg.org/#origin). This was because we were initializing the url with a fallback of `http://localhost` (no port). When constructed via `new URL()`, the port is unable to be extracted. This is fixed by using the `host` property off the headers object, if it exists, which includes the port. Partial fix for #11448. --- .../payload/src/utilities/createLocalReq.ts | 23 +++++++++++++------ tsconfig.base.json | 2 +- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/packages/payload/src/utilities/createLocalReq.ts b/packages/payload/src/utilities/createLocalReq.ts index 21931e6b49..b1de9c28c5 100644 --- a/packages/payload/src/utilities/createLocalReq.ts +++ b/packages/payload/src/utilities/createLocalReq.ts @@ -26,22 +26,26 @@ function getRequestContext( const attachFakeURLProperties = (req: Partial) => { /** * *NOTE* - * If no URL is provided, the local API was called directly outside + * If no URL is provided, the local API was called outside * the context of a request. Therefore we create a fake URL object. - * `ts-expect-error` is used below for properties that are 'read-only' - * since they do not exist yet we can safely ignore the error. + * `ts-expect-error` is used below for properties that are 'read-only'. + * Since they do not exist yet we can safely ignore the error. */ - let urlObject + let urlObject: undefined | URL function getURLObject() { if (urlObject) { return urlObject } - const urlToUse = req?.url || req.payload.config?.serverURL || 'http://localhost' + + const fallbackURL = `http://${req.host || 'localhost'}` + + const urlToUse = req?.url || req.payload.config?.serverURL || fallbackURL + try { urlObject = new URL(urlToUse) - } catch (error) { - urlObject = new URL('http://localhost') + } catch (_err) { + urlObject = new URL(fallbackURL) } return urlObject @@ -50,20 +54,25 @@ const attachFakeURLProperties = (req: Partial) => { if (!req.host) { req.host = getURLObject().host } + if (!req.protocol) { req.protocol = getURLObject().protocol } + if (!req.pathname) { req.pathname = getURLObject().pathname } + if (!req.searchParams) { // @ts-expect-error eslint-disable-next-line no-param-reassign req.searchParams = getURLObject().searchParams } + if (!req.origin) { // @ts-expect-error eslint-disable-next-line no-param-reassign req.origin = getURLObject().origin } + if (!req?.url) { // @ts-expect-error eslint-disable-next-line no-param-reassign req.url = getURLObject().href diff --git a/tsconfig.base.json b/tsconfig.base.json index 28020e04ad..26c3c9821e 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -31,7 +31,7 @@ } ], "paths": { - "@payload-config": ["./test/admin/config.ts"], + "@payload-config": ["./test/_community/config.ts"], "@payloadcms/live-preview": ["./packages/live-preview/src"], "@payloadcms/live-preview-react": ["./packages/live-preview-react/src/index.ts"], "@payloadcms/live-preview-vue": ["./packages/live-preview-vue/src/index.ts"],