feature: percent-decode before routing #2729
Open
+719
−297
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Note that this PR is built on top of #2645 so it also contains its changes. The only relevant change is the last commit.
Closes #2678
Motivation
Matching was happening before percent decoding. Therefore,
/a
and/%61
were two different paths although according to the spec they shouldn't be.We were also unable to construct routes with special characters that would have to be percent encoded by clients such as
?
or users would have to specify their paths already percent encoded when callingroute
.Solution
The paths are percent decoded before passing them to
matchit
. One exception is the forward slash/
, which must not be decoded as that could change the matching behavior. This is achieved by encoding the%
in%2f
which would otherwise be decoded to/
and interpreted as a path separator bymatchit::Router
. This way, thematchit::Router
still sees%2f
which gets decoded later on when inserting matched captures to request extensions.For example with a routes
/api/{resource}
and/api/car/{name}
, making a call such as/api/car%2flada
should match the first route, not the second one.One drawback of this is that if a user makes a request such as
/%252f_is_slash
, which would be captured by route/{capture}
, the value of the captured path should be%2f_is_slash
but because slashes are decoded after everything else, this will actually produce/_is_slash
. This should be very rare scenario though.Other characters work as intended, e.g. request to
/%2561_a
would result in a capture of%61_a
.