-
-
Notifications
You must be signed in to change notification settings - Fork 229
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
✨ Adds consistent redirects handling for cf workers. #3895
Conversation
This stack of pull requests is managed by Graphite. Learn more about stacking. |
484bd0d
to
6aa79a3
Compare
afa702d
to
9b7ba3d
Compare
6aa79a3
to
7a9ac89
Compare
9b7ba3d
to
af2f857
Compare
Quick links (staging server):
Login:
SVG tester:Number of differences (default views): 0 ✅ Edited: 2024-09-10 08:28:01 UTC |
7a9ac89
to
797db83
Compare
af2f857
to
08a9354
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nicely done!
I did find a bunch more cases that we need to cover, or may want to cover in a nicer way.
functions/grapher/[slug].ts
Outdated
"Access-Control-Allow-Origin": "*", | ||
}, | ||
}) | ||
} | ||
|
||
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() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should really try to keep this in as the first line of business.
It allows us that if any unhandled exception happens in this handler, we're still failing open and are sending over the unmodified /grapher/...
response as-is from the origin server. Which is a good fallback (and will work for graphers unless there's a redirect - but never for .json
, .png
and .svg
, obviously.)
See https://developers.cloudflare.com/workers/runtime-apis/context/#passthroughonexception.
const allExtensions = Object.values(extensions) | ||
.map((ext) => ext.replace(".", "\\.")) // for the regex make sure we match only a single dot, not any character | ||
.join("|") | ||
const regexForKnownExtensions = new RegExp( | ||
`^(?<slug>.*?)(?<extension>${allExtensions})?$` | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this code will be simpler by assuming that a slug can't contain a dot, i.e. something like /^(?<slug>[^\s\.]+)(?<extension>\.\S+)?$/
.
In theory we could then check after the fact that the extension is valid (and throw a fitting error), but it's also fine if we're not doing that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah true but I think I like the idea of using a list of known extensions as a communication device that is added to further up in the stack. I'm inclined to leave it as is for now.
const matchResult = fullslug.match(regexForKnownExtensions) | ||
const slug = matchResult?.groups?.slug ?? fullslug | ||
const extension = matchResult?.groups?.extension ?? "" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, what this code doesn't currently seem to handle is non-lowercase slugs.
Our rule is that a slug needs to be all-lowercase, and if it isn't we want to redirect it.
In the old code, I tried to be clever about it so we never need to run through two redirects, avoiding the scenario REDIR-SOURCE -> redir-source -> redir-target
. I don't think we need to take care of that again, which means we would just do:
if (slug.toLowerCase() !== slug)
return redir(302, slug.toLowerCase())
functions/_common/grapherRenderer.ts
Outdated
@@ -215,6 +217,13 @@ export async function fetchGrapherConfig( | |||
): Promise<FetchGrapherConfigResult> { | |||
const fetchResponse = await fetchUnparsedGrapherConfig(slug, env, etag) | |||
|
|||
if (fetchResponse.status === 404) { | |||
// we throw 404 errors instad of returning a 404 response so that the router |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// we throw 404 errors instad of returning a 404 response so that the router | |
// we throw 404 errors instead of returning a 404 response so that the router |
797db83
to
7b3ec48
Compare
08a9354
to
f080612
Compare
7b3ec48
to
2b3e22c
Compare
f080612
to
61f8b29
Compare
2b3e22c
to
2c10fea
Compare
61f8b29
to
e6c9b7c
Compare
2c10fea
to
1d38e5c
Compare
e6c9b7c
to
d5326c5
Compare
1d38e5c
to
d07caed
Compare
d5326c5
to
9b79ac8
Compare
d07caed
to
38489b5
Compare
546f675
to
ecffac1
Compare
bc65d56
to
ba14771
Compare
ecffac1
to
2b761ca
Compare
ba14771
to
ff124a9
Compare
2b761ca
to
ade6496
Compare
ff124a9
to
909e78d
Compare
ade6496
to
a8553c5
Compare
909e78d
to
fc689f5
Compare
a8553c5
to
563e74b
Compare
fc689f5
to
6d2c969
Compare
563e74b
to
275fa56
Compare
6d2c969
to
8abfd52
Compare
275fa56
to
c902103
Compare
8abfd52
to
48bd302
Compare
c902103
to
b0cd9d5
Compare
48bd302
to
29ecc72
Compare
b0cd9d5
to
2f44d84
Compare
29ecc72
to
5fdd975
Compare
2f44d84
to
3589dce
Compare
This means that both request for the html pages at /grapher/[slug] and requests for /grapher/[slug].config.json will be redirected according to the _grapherRedirects.json file. This is done as a catch handler that checks for 404 pages so that the common, happy path does not have to fetch the redirects file.
3589dce
to
d25b1ef
Compare
Cloudflare has support for redirects but only up to a limited number (I think 2000?). We have a lot of chart redirects in the chart_redirects table (about 1600 or so). Because everything under the /grapher/ route on our website has to run through a CF function anyways (to update the thumbnail image to include the correct query string), we decided to bake these redirects into a json file and do custom redirects handling in the CF function.
We did this for html pages already but not for thumbnails, but now that we also have
.config.json
requests to worry about and would like to have consistent redirects handling that doesn't overly complicate the logic of our handlers.This PR makes it so that both requests for the html pages at
/grapher/[slug]
and requests for/grapher/[slug].config.json
will be redirected according to the _grapherRedirects.json file using a catch error handler. This is done as a catch handler that checks for 404 pages so that the common, happy path does not have to fetch the redirects file.