Skip to content
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

feat: disable semicolon separator by default #336

Merged
merged 3 commits into from
Dec 26, 2023

Conversation

levensta
Copy link
Contributor

This PR comes from the discussion in the issue (fastify/fastify#5050). I've added a new parameter that allows the ; character to be used to separate path and query as before, but its default value is false to be fully compliant with the RFC

Copy link
Collaborator

@ivan-tymoshenko ivan-tymoshenko left a comment

Choose a reason for hiding this comment

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

This is really weird, but it looks like it's correct. Can you provide a bench results?
@mcollina This is a major for find-my-way.

@@ -88,6 +88,7 @@ function Router (opts) {
this.maxParamLength = opts.maxParamLength || 100
this.allowUnsafeRegex = opts.allowUnsafeRegex || false
this.constrainer = new Constrainer(opts.constraints)
this.useSemicolonDelimiter = opts.useSemicolonDelimiter || false
Copy link
Collaborator

Choose a reason for hiding this comment

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

Don't forget to set it true in the Fastify.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ideally this option should be disabled in Fastify as well, but I don't know the best way to do it: leave the default false here and open issue/PR to update dependencies in Fastify, or make it true here and send PR to Fastify with the option disabled

Copy link
Collaborator

Choose a reason for hiding this comment

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

I would leave the false here, because it's a correct behavior and we can release a new major of fmw at any moment. In current version of Fastify it should be set to true by default, because otherwise it's a breaking change.

About changing it to false in the fastify in a future release. It's better to open an issue about this in fastify, but IMHO it never would be set to true by defauld in the Fastify, because it will break too many apps. It just doesn't worth it even if it's true according to the spec.

// Thus, we need to split on `;` as well as `?` and `#`.
} else if (charCode === 63 || charCode === 59 || charCode === 35) {
// Thus, we need to split on `;` as well as `?` and `#` if the useSemicolonDelimiter option is enabled.
} else if (charCode === 63 || charCode === 35 || (useSemicolonDelimiter && charCode === 59)) {
querystring = path.slice(i + 1)
Copy link
Collaborator

Choose a reason for hiding this comment

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

If there is any perf difference (I doubt), you can move the useSemicolonDelimiteradditional check under the charCode checking if. That would remove it from a hot path.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, given that the ; symbol is rare, that's correct. I fixed

@levensta
Copy link
Contributor Author

Can you provide a bench results?

I made a simple example in the sandbox
https://codesandbox.io/p/sandbox/find-my-way-semicolon-g29hw7

btw, it works the same way for the # character, but I also don't understand for which situation this is necessary. At the same time in Fastify the hash from request does not get into query object

Copy link
Collaborator

@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

@mcollina
Copy link
Collaborator

@levensta did you run the benchmarks by any chance?

@levensta
Copy link
Contributor Author

@levensta did you run the benchmarks by any chance?

I run bench:cmp and got these results 🤔

screenshot

Снимок экрана 2023-09-26 в 17 57 18

Copy link
Collaborator

@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.

Can you document the new option?

@levensta
Copy link
Contributor Author

levensta commented Oct 6, 2023

@mcollina I've updated the README. But I am still confused by the fact that there is still a # character, which also separates path and query. It is not a problem in Fastify, but is it needed here? Maybe I should remove it too?

@mcollina
Copy link
Collaborator

mcollina commented Oct 7, 2023

I'm lost. can you make an example?

@levensta
Copy link
Contributor Author

levensta commented Oct 9, 2023

I'm lost. can you make an example?

In this example, you can see that both ; and # work as delimiters
https://codesandbox.io/p/sandbox/find-my-way-semicolon-g29hw7?file=%2Findex.js%3A7%2C1

@mcollina
Copy link
Collaborator

That does not look correct, what does the rfc say?

@levensta
Copy link
Contributor Author

Sorry for the long response time. The RFC explicitly says that the "#" character is used as the beginning of a separate segment called a fragment

3. Syntax Components

URI         = scheme ":" hier-part [ "?" query ] [ "#" fragment ]

3.3. Path
The path is terminated by the first question mark ("?") or number sign ("#") character, or by the end of the URI.

The problem with the current code is that it truncates the path to the delimiter character, but does not check which one is a query string and which one is a fragment and writes everything into one querystring variable. Judging by the history, this behaviour was originally a1cc69a
It's just that nothing was written to a separate querystring variable before.

A fix could look like this
image

Should this behaviour be hidden behind the same parameter as useSemicolonDelimiter (renamed in this case) or a other parameter? Or maybe we shouldn't hide this behaviour at all? It would be strange if any of the library's consumers were intentionally targeting this behaviour

@Uzlopak
Copy link
Contributor

Uzlopak commented Dec 9, 2023

It is correct that # should split. It is the "anker" in browser url, where you jump to the specific position.

The correct behavior is to ignore everything after a #.

So in conclusion: everything after the first occurence of ? and the first occurence of # is a querystring.

Copy link
Collaborator

@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

@mcollina mcollina merged commit 0b44ecc into delvedor:main Dec 26, 2023
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.

4 participants