fix(https): defer CORS param resolution until runtime#1887
Conversation
There was a problem hiding this comment.
Code Review
This pull request refactors CORS origin resolution for onRequest and onCall by introducing normalizeCorsOrigin and resolveCorsOrigin helper functions. It also adds support for resolving CORS origins from Expression objects at runtime using a middleware callback. Feedback suggests wrapping the runtime resolution of Expression values in a try-catch block to ensure that any errors encountered while retrieving the value are properly propagated to the Express error handler.
| return ( | ||
| _requestOrigin: string | undefined, | ||
| callback: (err: Error | null, origin?: ResolvedCorsOrigin) => void | ||
| ): void => { | ||
| callback(null, normalizeCorsOrigin(corsOption.value())); | ||
| }; |
There was a problem hiding this comment.
When corsOption is an Expression, its value is resolved at runtime within the CORS middleware callback. Since corsOption.value() can throw an error (e.g., if a required parameter is missing or invalid at runtime), it is safer to wrap this call in a try-catch block and pass any error to the callback. This ensures the cors middleware can handle the error gracefully by propagating it to the Express error handler via next(err).
return (
_requestOrigin: string | undefined,
callback: (err: Error | null, origin?: ResolvedCorsOrigin) => void
): void => {
try {
callback(null, normalizeCorsOrigin(corsOption.value()));
} catch (err) {
callback(err instanceof Error ? err : new Error(String(err)));
}
};8a3f9a3 to
20505bc
Compare
…or better readability
What This PR Solves
Fixes #1773.
CORS options can be backed by params such as
defineList, but v2 HTTPS handlers were resolving those params while the Functions control API was analyzing source code. At that point runtime env values may not exist yet, which can trigger deploy-time warnings or failures like parsingundefined.This PR keeps the param-backed CORS option unresolved during function definition and resolves it from the CORS middleware at request time instead. It preserves debug CORS behavior and the existing single-origin normalization.
Testing Details
onRequest({ cors: defineList(...) })so function analysis can run withFUNCTIONS_CONTROL_API=truebefore the param value exists, then runtime request handling resolvesORIGINS.onCall({ cors: defineList(...) })with the same deploy-time/runtime split.test-project/functionsapp exporting bothcorsParamOnRequestandcorsParamOnCall, each usingcors: defineList("ALLOWED_ORIGINS").FUNCTIONS_CONTROL_API=trueandALLOWED_ORIGINSwas unset, confirming module analysis no longer resolves/parses the param during deploy-time loading.ALLOWED_ORIGINS=["https://app.example.com","https://admin.example.com"]and verified CORS preflight behavior: allowed origins returned the matchingAccess-Control-Allow-Originheader, andhttps://evil.example.comdid not.