diff --git a/functions/_common/grapherRenderer.ts b/functions/_common/grapherRenderer.ts index 7417455e8af..0f40b4adbbf 100644 --- a/functions/_common/grapherRenderer.ts +++ b/functions/_common/grapherRenderer.ts @@ -171,6 +171,11 @@ export async function fetchGrapherConfig({ // The top level directory is either the bucket path (should be set in dev environments and production) // or the branch name on preview staging environments console.log("branch", env.CF_PAGES_BRANCH) + + // Sanity check that the slug is really only the slug of a grapher config and not a substring of the url with paths or queries + if (slug.includes("/") || slug.includes(".") || slug.includes("?")) + throw new Error(`Invalid slug: ${slug}`) + const topLevelDirectory = env.GRAPHER_CONFIG_R2_BUCKET_PATH ? [env.GRAPHER_CONFIG_R2_BUCKET_PATH] : ["by-branch", env.CF_PAGES_BRANCH] @@ -204,13 +209,28 @@ export async function fetchGrapherConfig({ } // Fetch grapher config - const fetchResponse = await fetchFromR2(requestUrl, etag, fallbackUrl) + const fetchResponse = await env.r2ChartConfigs.get(key) + let grapherConfig: GrapherInterface + + if (fetchResponse) { + grapherConfig = await fetchResponse.json() + } else { + // If we don't find the grapher config, we try to fall back to ourworldindata.org + // If we're already on ourworldindata.org, don't attempt a recursive fetch but return null + if (env.url.hostname === "ourworldindata.org") return null + else { + // If we are on a different host, try to see if the grapher config is available on ourworldindata.org + console.log( + "Could not find grapher config, falling back to ourworldindata.org for slug", + slug + ) + const url = `https://ourworldindata.org/grapher/${slug}.config.json` - if (fetchResponse.status !== 200) { - console.log("Failed to fetch grapher config", fetchResponse.status) - return null + const fallbackResponse = await fetch(url.toString()) + if (!fallbackResponse.ok) return null + grapherConfig = await fallbackResponse.json() + } } - const grapherConfig: GrapherInterface = await fetchResponse.json() console.log("grapher title", grapherConfig.title) return grapherConfig } diff --git a/functions/grapher/[slug].ts b/functions/grapher/[slug].ts index 61f3733ac96..3274a86faaf 100644 --- a/functions/grapher/[slug].ts +++ b/functions/grapher/[slug].ts @@ -10,12 +10,12 @@ const router = Router() router .get( "/grapher/:slug.config.json", - async ({ params: { slug } }, { searchParams }, env) => + async ({ params: { slug } }, { searchParams }, env: Env) => handleConfigRequest(slug, searchParams, env) ) .get( "/grapher/:slug", - async ({ params: { slug } }, { searchParams }, env) => + async ({ params: { slug } }, { searchParams }, env: Env) => handleHtmlPageRequest(slug, searchParams, env) ) .all("*", () => error(404, "Route not defined")) @@ -24,13 +24,13 @@ export const onRequestGet: PagesFunction = async (context) => { // Makes it so that if there's an error, we will just deliver the original page before the HTML rewrite. // Only caveat is that redirects will not be taken into account for some reason; but on the other hand the worker is so simple that it's unlikely to fail. context.passThroughOnException() + console.log("handlings request", context.request.url) const { request, env, params } = context const url = new URL(request.url) - const originalSlug = params.slug as string return ( router - .fetch(request, url, { ...env, url, originalSlug }, context) + .fetch(request, url, { ...env, url }, context) // .then((resp: Response) => { // if (shouldCache) { // resp.headers.set( @@ -55,6 +55,7 @@ async function handleHtmlPageRequest( env: Env ) { const url = env.url + console.log("processing", url) // Redirects handling is performed by the worker, and is done by fetching the (baked) _grapherRedirects.json file. // That file is a mapping from old slug to new slug.