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

Fixes encoded values on Blazor Router #53470

Merged
merged 1 commit into from
Jan 22, 2024
Merged

Fixes encoded values on Blazor Router #53470

merged 1 commit into from
Jan 22, 2024

Conversation

javiercn
Copy link
Member

@javiercn javiercn commented Jan 18, 2024

Fix handling of encoded / in URLs within the Blazor router.

Fixes #52808, #53138, #53262

In .NET 8.0 we unified the routing system for ASP.NET Core and Blazor in order to bridge the functionality gaps and provide a consistent experience for SSR and interactive routing.
As part of such, we had to make adjustments to account for some of the quirks of the Blazor router (where it would behave slightly different than the ASP.NET Core router).
As part of this, we were decoding the entire URL before passing it to the Blazor router instead of (as it did before), splitting each segment and decoding each segment individually.

This introduced a regression when using URLs that contained encoded segments with / in them, as the router would then treat the / as a path separator instead of part of the segment and we would not be able to route correctly.

To fix this, we now decode each segment individually inside the router when the code runs as part of Blazor. In addition to that, when the routing happens server side, we now post-process the resulting values to URL decode them so that they match the behavior of the Blazor router.

To summarize, here is the before and after behavior:

Before:

Framework version and router pattern request result
7.0 interactive /some/{parameter} /some/encoded%2Fvalue parameter = "encoded/value"
8.0 SSR /some/{parameter} /some/encoded%2Fvalue parameter = "encoded%2Fvalue"
8.0 interactive /some/{parameter} /some/encoded%2Fvalue Not Found (URI got decoded as /some/encoded/value)

After:

Framework version and router pattern request result
7.0 interactive /some/{parameter} /some/encoded%2Fvalue parameter = "encoded/value"
8.0 SSR /some/{parameter} /some/encoded%2Fvalue parameter = "encoded/value"
8.0 interactive /some/{parameter} /some/encoded%2Fvalue parameter = "encoded/value"

@dotnet-issue-labeler dotnet-issue-labeler bot added the area-blazor Includes: Blazor, Razor Components label Jan 18, 2024
@javiercn javiercn force-pushed the javiercn/issue53138 branch 3 times, most recently from a67e10b to ace334c Compare January 19, 2024 11:56
@javiercn javiercn marked this pull request as ready for review January 19, 2024 12:00
@javiercn javiercn requested a review from a team as a code owner January 19, 2024 12:00
@javiercn javiercn force-pushed the javiercn/issue53138 branch from ace334c to a12be23 Compare January 19, 2024 12:43
Copy link
Member

@SteveSandersonMS SteveSandersonMS left a comment

Choose a reason for hiding this comment

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

Great!

@@ -112,9 +113,11 @@ private static string[] GetTemplates(Type componentType)
[UnconditionalSuppressMessage("Trimming", "IL2067", Justification = "Application code does not get trimmed, and the framework does not define routable components.")]
internal static RouteTable Create(Dictionary<Type, string[]> templatesByHandler, IServiceProvider serviceProvider)
{
var routeOptions = Options.Create(new RouteOptions());
routeOptions.Value.SetParameterPolicy("regex", typeof(RegexInlineRouteConstraint));
Copy link
Member

Choose a reason for hiding this comment

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

I'm unsure if this is part of dealing with encoding or if it's addressing a separate issue. Could you clarify?

Copy link
Member Author

Choose a reason for hiding this comment

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

This is addressing a separate issue, we weren't wiring up the regex, which was needed to test this fully, as it doesn't affect other constraints that the Blazor router supports and we don't have support for authoring custom constraints either.

Copy link
Member

Choose a reason for hiding this comment

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

Have we effectively added a whole new feature with this line of code then? I'm totally fine with this being added, assuming it doesn't appreciably impact the default bundle size for a Blazor WebAssembly app.

Could you confirm if that's the case?

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm in the process of confirming the bundle size, it's not a feature, it's a bug fix IMO. It works on SSR routing but won't work once it becomes interactive.

Copy link
Member

Choose a reason for hiding this comment

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

Thanks, please do confirm! I think we still have a choice of whether to include that feature for interactive mode, given that it's never worked on interactive mode in the past.

Copy link
Member Author

Choose a reason for hiding this comment

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

It turns out that this regressed the size, so I'm going to take it out into its own separate PR that enables this conditionally on WebAssembly behind a feature flag. The feature flag will also need a change in the Blazor SDK to control it, but for the purposes of this repo, we'll keep it enabled.

image

Copy link
Member Author

Choose a reason for hiding this comment

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

I've taken out the regex bit and will put it on a separate commit.

@@ -0,0 +1,24 @@
@page "/🙂/routing/constrained-catch-all/{*parameter:regex(http:%2F%2Fwww\\.example\\.com%2Flogin%2Fcallback\\/another)}"
Copy link
Member

Choose a reason for hiding this comment

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

My eyes

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, this is a bit extreme, but I wanted to make sure we cover all the edge cases correctly, as this is very tricky.

As part of the routing unification process we switched the way we were
decoding the URL prior to feeding it to routing and that introduced a
small regression in interactive routing compared to .NET 7.0.

This commit fixes that regression by using the same logic for decoding
the URL in the client that is used on the server.

In addition to that, the Blazor router now post processes the URL to
replace instances of `%2F` with `/` when providing values to maintain
the behavior in 7.0 where it used UnescapeDataString.

This also makes the routing on the server and on the client consistent
in their handling of encoded `/` characters.
@javiercn javiercn force-pushed the javiercn/issue53138 branch from a12be23 to 11b7c57 Compare January 22, 2024 16:14
@javiercn javiercn merged commit 52c7ee5 into main Jan 22, 2024
@javiercn javiercn deleted the javiercn/issue53138 branch January 22, 2024 18:56
@javiercn
Copy link
Member Author

/backport to release/8.0

Copy link
Contributor

Started backporting to release/8.0: https://github.com/dotnet/aspnetcore/actions/runs/7616006018

Copy link
Contributor

@javiercn backporting to release/8.0 failed, the patch most likely resulted in conflicts:

$ git am --3way --ignore-whitespace --keep-non-patch changes.patch

Applying: [Blazor] Fixed encoded values on Blazor Router
Using index info to reconstruct a base tree...
M	src/Components/Components/src/Microsoft.AspNetCore.Components.csproj
Falling back to patching base and 3-way merge...
Auto-merging src/Components/Components/src/Microsoft.AspNetCore.Components.csproj
CONFLICT (content): Merge conflict in src/Components/Components/src/Microsoft.AspNetCore.Components.csproj
error: Failed to merge in the changes.
hint: Use 'git am --show-current-patch=diff' to see the failed patch
Patch failed at 0001 [Blazor] Fixed encoded values on Blazor Router
When you have resolved this problem, run "git am --continue".
If you prefer to skip this patch, run "git am --skip" instead.
To restore the original branch and stop patching, run "git am --abort".
Error: The process '/usr/bin/git' failed with exit code 128

Please backport manually!

Copy link
Contributor

@javiercn an error occurred while backporting to release/8.0, please check the run log for details!

Error: git am failed, most likely due to a merge conflict.

javiercn added a commit that referenced this pull request Jan 22, 2024
As part of the routing unification process we switched the way we were
decoding the URL prior to feeding it to routing and that introduced a
small regression in interactive routing compared to .NET 7.0.

This commit fixes that regression by using the same logic for decoding
the URL in the client that is used on the server.

In addition to that, the Blazor router now post processes the URL to
replace instances of `%2F` with `/` when providing values to maintain
the behavior in 7.0 where it used UnescapeDataString.

This also makes the routing on the server and on the client consistent
in their handling of encoded `/` characters.
@javiercn
Copy link
Member Author

#53668

wtgodbe pushed a commit that referenced this pull request Feb 6, 2024
As part of the routing unification process we switched the way we were
decoding the URL prior to feeding it to routing and that introduced a
small regression in interactive routing compared to .NET 7.0.

This commit fixes that regression by using the same logic for decoding
the URL in the client that is used on the server.

In addition to that, the Blazor router now post processes the URL to
replace instances of `%2F` with `/` when providing values to maintain
the behavior in 7.0 where it used UnescapeDataString.

This also makes the routing on the server and on the client consistent
in their handling of encoded `/` characters.
@danroth27 danroth27 added this to the 9.0-preview1 milestone Apr 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-blazor Includes: Blazor, Razor Components
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Blazor NavigationManager redirect to NotFound if route parameter contains encoded /
3 participants