diff --git a/spec/v2/providers/https.spec.ts b/spec/v2/providers/https.spec.ts index a62dfea5a..85251ebfc 100644 --- a/spec/v2/providers/https.spec.ts +++ b/spec/v2/providers/https.spec.ts @@ -68,6 +68,7 @@ describe("onRequest", () => { afterEach(() => { options.setGlobalOptions({}); delete process.env.GCLOUD_PROJECT; + delete process.env.FUNCTIONS_CONTROL_API; }); it("should return a minimal trigger/endpoint with appropriate values", () => { @@ -232,7 +233,7 @@ describe("onRequest", () => { const origins = defineList("ORIGINS"); try { - process.env.ORIGINS = '["example.com","example2.com"]'; + process.env.FUNCTIONS_CONTROL_API = "true"; const func = https.onRequest( { cors: origins, @@ -241,6 +242,8 @@ describe("onRequest", () => { res.send("42"); } ); + delete process.env.FUNCTIONS_CONTROL_API; + process.env.ORIGINS = '["example.com","example2.com"]'; const req = request({ headers: { referrer: "example.com", @@ -261,6 +264,7 @@ describe("onRequest", () => { }); } finally { delete process.env.ORIGINS; + delete process.env.FUNCTIONS_CONTROL_API; clearParams(); } }); @@ -351,6 +355,7 @@ describe("onCall", () => { afterEach(() => { delete process.env.GCLOUD_PROJECT; delete process.env.ORIGINS; + delete process.env.FUNCTIONS_CONTROL_API; clearParams(); }); @@ -486,7 +491,11 @@ describe("onCall", () => { }); it("should allow cors params", async () => { + delete process.env.ORIGINS; + process.env.FUNCTIONS_CONTROL_API = "true"; const func = https.onCall({ cors: origins }, () => 42); + delete process.env.FUNCTIONS_CONTROL_API; + process.env.ORIGINS = '["example.com","example2.com"]'; const req = request({ headers: { referrer: "example.com", diff --git a/src/v2/providers/https.ts b/src/v2/providers/https.ts index cfb3cfee3..17c4e3c67 100644 --- a/src/v2/providers/https.ts +++ b/src/v2/providers/https.ts @@ -255,6 +255,42 @@ export const hasClaim = return !value || auth.token[claim] === value; }; +type ResolvedCorsOrigin = boolean | string | RegExp | Array; + +function normalizeCorsOrigin( + origin: ResolvedCorsOrigin | undefined +): ResolvedCorsOrigin | undefined { + // Arrays cause the access-control-allow-origin header to be dynamic based + // on the origin header of the request. If there is only one element in the + // array, this is unnecessary. + if (Array.isArray(origin) && origin.length === 1) { + return origin[0]; + } + + return origin; +} + +function resolveCorsOrigin( + corsOption: HttpsOptions["cors"], + isCorsDebugEnabled: boolean +): cors.CorsOptions["origin"] { + if (isCorsDebugEnabled) { + // Respect `cors: false` to turn off cors even if debug feature is enabled. + return corsOption === false ? false : true; + } + + if (corsOption instanceof Expression) { + return ( + _requestOrigin: string | undefined, + callback: (err: Error | null, origin?: ResolvedCorsOrigin) => void + ): void => { + callback(null, normalizeCorsOrigin(corsOption.value())); + }; + } + + return normalizeCorsOrigin(corsOption); +} + /** * Handles HTTPS requests. */ @@ -323,18 +359,9 @@ export function onRequest( handler = withErrorHandler(handler); - if (isDebugFeatureEnabled("enableCors") || "cors" in opts) { - let origin = opts.cors instanceof Expression ? opts.cors.value() : opts.cors; - if (isDebugFeatureEnabled("enableCors")) { - // Respect `cors: false` to turn off cors even if debug feature is enabled. - origin = opts.cors === false ? false : true; - } - // Arrays cause the access-control-allow-origin header to be dynamic based - // on the origin header of the request. If there is only one element in the - // array, this is unnecessary. - if (Array.isArray(origin) && origin.length === 1) { - origin = origin[0]; - } + const isCorsDebugEnabled = isDebugFeatureEnabled("enableCors"); + if (isCorsDebugEnabled || "cors" in opts) { + const origin = resolveCorsOrigin(opts.cors, isCorsDebugEnabled); const middleware = cors({ origin }); const userProvidedHandler = handler; @@ -434,24 +461,14 @@ export function onCall, Stream = unknown>( opts = optsOrHandler as CallableOptions; } - let cors: string | boolean | RegExp | Array | undefined; + let cors: HttpsOptions["cors"]; if ("cors" in opts) { - if (opts.cors instanceof Expression) { - cors = opts.cors.value(); - } else { - cors = opts.cors; - } + cors = opts.cors; } else { cors = true; } - let origin = isDebugFeatureEnabled("enableCors") ? true : cors; - // Arrays cause the access-control-allow-origin header to be dynamic based - // on the origin header of the request. If there is only one element in the - // array, this is unnecessary. - if (Array.isArray(origin) && origin.length === 1) { - origin = origin[0]; - } + const origin = resolveCorsOrigin(cors, isDebugFeatureEnabled("enableCors")); // fix the length of handler to make the call to handler consistent const fixedLen = (req: CallableRequest, resp?: CallableResponse) => handler(req, resp);