Skip to content

chore: refactor for clarity #99

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

Merged
merged 6 commits into from
Nov 22, 2020
Merged

chore: refactor for clarity #99

merged 6 commits into from
Nov 22, 2020

Conversation

codyzu
Copy link
Contributor

@codyzu codyzu commented Nov 16, 2020

Checklist

Refactored implementation for readability.

These important changes were made:

  1. I updated the readme to reflect the actual behavior for the value returned when the origin option is a function. The docs simply stated it should return true or false to allow the origin, but the implementation actually use the return value to process to the origin (i.e. it could be a string). This aligns fastify-cors express-cors.
  2. If the origin option is a function and returns a falsy value other than false, for example undefined, the hook generates an error. The previous implementation treated this as * origin which does not seem intuitive and is not the way that express-cors works.
  3. If the origin option is a function and throws an error, the error is caught and passed into the hook callback (generating an error).

@codyzu
Copy link
Contributor Author

codyzu commented Nov 16, 2020

* All tests reporting 97.5% req / sec results.

test run 1 run 2 run 3
before normal request GET 33311 33471 33183
before preflight request OPTIONS 37727 37343 37375
after normal request GET 34687 33503 32927
after preflight request OPTIONS 36863 37247 36767

@mcollina Here are my performance indicators comparing the previous implementation (before) to my current changes (after). Big picture, the change seems relatively small. Interestingly, the test results before my changes have less variation between test runs. Not sure what causes that... might just be a coincidence related to the load on my machine 🤷‍♀️

@codyzu codyzu changed the title WIP: chore: refactor for clarity chore: refactor for clarity Nov 17, 2020
@codyzu codyzu marked this pull request as ready for review November 17, 2020 16:58
@codyzu codyzu requested a review from mcollina November 18, 2020 16:44
Copy link
Member

@mcollina mcollina left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

Copy link
Member

@Ethan-Arrowood Ethan-Arrowood left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lgtm

index.js Outdated
if (err !== null) return next(err)
// Falsy values are invalid
if (!resolvedOriginOption) {
return next(new Error('Invalid CORS origin option'))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is new behavior? In past code, we are setting req.corsOriginAllowed = false on falsy values.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If is an intentional behavior, should be tested as well.

Copy link
Contributor Author

@codyzu codyzu Nov 18, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are correct that this is a functional change. Before, if the origin option was a falsy value, CORS would just be disabled. If the origin option was a function that returned a falsy value (other than false), the accept origin header would be *.

This was an attempt to make the behavior from the origin option predictable in the following ways:

  1. The same behavior if the origin option is a value OR a function
  2. If the option is an invalid value (defined as any value not defined in the documentation), an error is thrown.

Clearly there is some risk to a change like this. However I would argue that it will actual make the module more understandable because the behavior is consistent. I welcome any discussion on this point 😄

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If your goal is to "refactor for clarity" then you should not also be introducing new functionality. Doing so makes the PR way more difficult to evaluate.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with @jsumners. I would like to see this change, but it's better in another PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with your point.

The challenge is that the old behavior was a bit tricky (and possibly unintentional):

  • if the origin option is falsy, CORS is disabled ☑️
  • if the origin option is a function that returns false, CORS is disabled ☑️
  • if the origin option is a function that returns a falsy value other than false, the allowed origin is *. (Note this behavior was never documented or tested) 😱

☝️ Handling the last case will add a lot of noise, but should be possible... I'll see if I can separate it into 2 PRs...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may not be ideal to replicate weird behavior. But consider that you have reviewers who probably know less about the code than you do at this point and they need to read the original code to understand the new code in order to properly review it. Any functionality change will be a radical change in this respect, thus making it prohibitively more difficult to review. For this case, I would note the change I want to make and then submit a follow up PR after the refactor PR is accepted.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RafaelGSS @jsumners I removed this change. I'll put it into another PR.

const fastify = Fastify()
const origin = (header, cb) => {
t.strictEqual(header, 'example.com')
cb(null, undefined)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RafaelGSS this test covers falsy values. The test is in the context of an origin function that returns a falsy value, but covers that case. Is ok for you?

index.js Outdated
_configureOrigin(origin)
function preflightHandler (req, reply) {
// Do not handle preflight requests if the origin was not allowed
if (!req.corsOriginAllowed) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a new behaviour. Also technically the 404 code is not fitting the spec as the ressource is here but the CORS is not allowed. I'd rather use 400. Returning a 404 would be handled in a custom function.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Glad to see an observant eye. This was changed in my last PR #96 .

This is due to the fact that I moved the preflight logic into the OPTIONS * route handler. There was some certain motivation for that (discussed in #96 ) but the general points were to:

  1. allow overriding of OPTIONS routes (seems to be the motivation behind The plugin treats every OPTIONS request as a preflight request #88 )
  2. make fastify-cors fit better into the fastify plugin paradigm. The previous implementation seemed to be a fairly strict port of express-cors, where middleware can either handle a request or pass it long to the next middleware in the chain. That model doesn't fit with plugins, hooks, and a "static" routing table that fasitfy uses.

Back to the question. This line is to allow for the case when the origin option is false or is a function that returns false. According to the docs, this should disable CORS (and the preflight handler). With middleware, this can just be checked when the middleware executes. With a static route, the route will always exist. 404 is to "simulate" the route not being there.

From a client perspective, if CORS is disabled, shouldn't the OPTIONS routes added by fastify-cors be "not found"?

Let me know if I didn't understand your point. Maybe the name of the field is misleading... perhaps it should be corsEnabled similar???

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I renamed this to corsPreflightEnabled which better describes the flag.

@codyzu codyzu requested review from RafaelGSS and jsumners November 20, 2020 12:40
@codyzu
Copy link
Contributor Author

codyzu commented Nov 20, 2020

I removed any possible functional changes. This included:

  1. throwing an error if the origin option is a falsy non-false value
  2. disabling the preflight logic when the origin option only resolves to false (it will now be disabled for any falsy value, as was the case before).

I'll move those into another PR

Copy link
Member

@jsumners jsumners left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's been so long since I have implemented the CORS spec, I can't really speak to the implementation. But the code looks sane to me.

Copy link
Member

@RafaelGSS RafaelGSS left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Good work!

@mcollina
Copy link
Member

@zekth you approve?

Copy link
Member

@zekth zekth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM . Thanks for making it clearer

@mcollina mcollina merged commit f50bf95 into fastify:master Nov 22, 2020
@codyzu codyzu mentioned this pull request Nov 23, 2020
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants