Skip to content

Conversation

@kforjan
Copy link
Contributor

@kforjan kforjan commented Apr 1, 2024

This PR addresses an issue where root deep links did not correctly navigate to '/'. The problem originated from the assumption that only paths (like '/', '/details', etc.) would be passed to the canonicalUri method in path_utils.dart. However, in the case of deep links, the full URL (including the scheme and domain) would be passed, causing the trailing slash to be incorrectly removed for root URLs.

The first part of the fix modifies the canonicalUri method to check the actual path using uri.path. This ensures that the trailing slash is preserved for root URLs, even when the full URL is passed to the method. Importantly, even if '/' or '/details' is passed as a URI to canonicalUri, uri.path will still return '/' or '/details', ensuring consistent behavior.

The second part of the fix modifies the parseRouteInformationWithDependencies function in parser.dart to correctly handle URLs with query parameters or fragments. Previously, the trailing slash was added after the query parameters or fragments, which is incorrect. The fix ensures that the trailing slash is added immediately after the base URL, before any query parameters or fragments.

Preserving the trailing slash for root URLs is crucial because the _matchByNavigatorKey method in match.dart uses uri.path as the remainingLocation parameter. (why is that method relevant? because parseRouteInformationWithDependencies uses findMatch, which calls _getLocRouteMatches, which calls match and it calls _matchByNavigatorKey). If the trailing slash is removed from the root deep link URL, uri.path will not return '/', and the URL will not match any routes in the Go router.

To validate these changes, new tests have been added. In path_utils_test.dart, tests have been added to verify that the trailing slash is not removed from a URL that is not just the path. In parser_test.dart, a new test has been added to verify that a URI with an empty path is correctly parsed. This test covers the case where routeInformation.uri.hasEmptyPath is true, which was not previously tested.

Issues fixed:

Pre-launch Checklist

@kforjan
Copy link
Contributor Author

kforjan commented Apr 1, 2024

@Hangyujin @johnpryan I have noticed that the code owner who is added as a reviewer hasn't been active for some time. Could you take a look at this, or do you know who could provide some feedback? Thank you!

@hannah-hyj
Copy link
Member

@kforjan I will take a look

Copy link
Member

@hannah-hyj hannah-hyj left a comment

Choose a reason for hiding this comment

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

Thanks for your contribution. This looks great to me, the fix looks clean and also thank you for your detailed description and tests.

throw GoException('Location cannot be empty.');
}
String canon = Uri.parse(loc).toString();
final Uri uri = Uri.parse(canon);
Copy link
Member

Choose a reason for hiding this comment

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

line128 should be after line 129

I can think of a corner test case /profile/?

// / => /
// /login?from=/ => login?from=/
canon = canon.endsWith('/') && canon != '/' && !canon.contains('?')
canon = uri.path.endsWith('/') && uri.path != '/' && !uri.hasQuery
Copy link
Member

Choose a reason for hiding this comment

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

add && !uri.hasFragment

initialMatches = configuration.findMatch(newUri, extra: state.extra);
} else {
initialMatches = configuration.findMatch(routeInformation.uri.toString(),
extra: state.extra);
Copy link
Member

Choose a reason for hiding this comment

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

nit: add comma

@hannah-hyj hannah-hyj requested a review from johnpryan April 4, 2024 22:56
@kforjan
Copy link
Contributor Author

kforjan commented Apr 4, 2024

@Hangyujin Thank you for the feedback! I appreciate it very much and I am really glad you find it helpful. I made all the changes you proposed and added a few more tests for canonicalUri - now all edge cases should be covered.

Copy link
Contributor

@chunhtai chunhtai left a comment

Choose a reason for hiding this comment

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

LGTM

@chunhtai chunhtai added the autosubmit Merge PR when tree becomes green via auto submit App label Apr 8, 2024
@auto-submit auto-submit bot merged commit fef7ac6 into flutter:main Apr 8, 2024
@DennisKragekjaer
Copy link

image

@DennisKragekjaer
Copy link

So I still see an issue, also after update to new version 13.2.3

@chunhtai
Copy link
Contributor

chunhtai commented Apr 8, 2024

Since this is merged, please file a new issue with repro.

@kforjan
Copy link
Contributor Author

kforjan commented Apr 9, 2024

Hello @DennisKragekjaer! I have just tried using the exact same url with a same custom scheme setup like the one in your example. It worked for me and I couldn't reproduce your problem. Please note that /link is the path which you're trying to open in your example, so you have to include a GoRoute with the path /link in the routes parameter which you provide to your GoRouter instance. If this doesn't help - please open an issue with reproduction steps.

Note for @chunhtai: while I investigated this, I noticed an edge case that I missed in my original implementation. When using custom schemes uri.origin cannot be used. After parsing a custom scheme with Uri.parse() calling uri.origin will produce the following Exception:

Bad state: Origin is only applicable to schemes http and https: customScheme://example

It doesn't break the flow or affect the app launch in any way, rather it just produces this error message in the debug console. It happens only with custom schemes with no path, for example:
customScheme://example will have an exception in the console while customScheme://example/ won't have it.
It isn't breaking for those cases, but it should be fixed anyway. One way to do it is to use uri.schema and uri.host to construct the uri, since both are available for custom schemas and http/https, but I am not sure if there are any other cases which I am missing where schema and host wont be in the same format as schema://host

@DennisKragekjaer
Copy link

@kforjan Thanks for looking into this. The thing is I have no idea where this "dk.kragekjaer.mille...." comes from.

auto-submit bot pushed a commit to flutter/flutter that referenced this pull request Apr 9, 2024
flutter/packages@6b4d8b6...17f55d3

2024-04-09 [email protected] Release compileSdk changes (flutter/packages#6491)
2024-04-08 [email protected] [camera_android] Remove `TestUtils.java` (flutter/packages#6490)
2024-04-08 [email protected] Roll Flutter from 98d23f7 to 533d04d (12 revisions) (flutter/packages#6488)
2024-04-08 [email protected] [go_router_builder] Add `restorationScopeId` to `ShellRouteData` (flutter/packages#6238)
2024-04-08 [email protected] [go_router] Fixes deep links with no path (flutter/packages#6447)
2024-04-08 [email protected] [in_app_purchase] Convert Android data objects to Pigeon (flutter/packages#6453)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages-flutter-autoroll
Please CC [email protected],[email protected] on the revert to ensure that a human
is aware of the problem.

To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
gilnobrega pushed a commit to gilnobrega/flutter that referenced this pull request Apr 22, 2024
flutter/packages@6b4d8b6...17f55d3

2024-04-09 [email protected] Release compileSdk changes (flutter/packages#6491)
2024-04-08 [email protected] [camera_android] Remove `TestUtils.java` (flutter/packages#6490)
2024-04-08 [email protected] Roll Flutter from 98d23f7 to 533d04d (12 revisions) (flutter/packages#6488)
2024-04-08 [email protected] [go_router_builder] Add `restorationScopeId` to `ShellRouteData` (flutter/packages#6238)
2024-04-08 [email protected] [go_router] Fixes deep links with no path (flutter/packages#6447)
2024-04-08 [email protected] [in_app_purchase] Convert Android data objects to Pigeon (flutter/packages#6453)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages-flutter-autoroll
Please CC [email protected],[email protected] on the revert to ensure that a human
is aware of the problem.

To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
TecHaxter pushed a commit to TecHaxter/flutter_packages that referenced this pull request May 22, 2024
This PR addresses an issue where root deep links did not correctly navigate to '/'. The problem originated from the assumption that only paths (like '/', '/details', etc.) would be passed to the `canonicalUri` method in `path_utils.dart`. However, in the case of deep links, the full URL (including the scheme and domain) would be passed, causing the trailing slash to be incorrectly removed for root URLs.

The first part of the fix modifies the `canonicalUri` method to check the actual path using `uri.path`. This ensures that the trailing slash is preserved for root URLs, even when the full URL is passed to the method. Importantly, even if '/' or '/details' is passed as a URI to `canonicalUri`, `uri.path` will still return '/' or '/details', ensuring consistent behavior.

The second part of the fix modifies the `parseRouteInformationWithDependencies` function in `parser.dart` to correctly handle URLs with query parameters or fragments. Previously, the trailing slash was added after the query parameters or fragments, which is incorrect. The fix ensures that the trailing slash is added immediately after the base URL, before any query parameters or fragments.

Preserving the trailing slash for root URLs is crucial because the `_matchByNavigatorKey` method in `match.dart` uses `uri.path` as the `remainingLocation` parameter. (why is that method relevant? because `parseRouteInformationWithDependencies` uses `findMatch`, which calls `_getLocRouteMatches`, which calls `match` and it calls `_matchByNavigatorKey`). If the trailing slash is removed from the root deep link URL, `uri.path` will not return '/', and the URL will not match any routes in the Go router.

To validate these changes, new tests have been added. In `path_utils_test.dart`, tests have been added to verify that the trailing slash is not removed from a URL that is not just the path. In `parser_test.dart`, a new test has been added to verify that a URI with an empty path is correctly parsed. This test covers the case where `routeInformation.uri.hasEmptyPath` is true, which was not previously tested.

Issues fixed:
 - flutter/flutter#133928
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

autosubmit Merge PR when tree becomes green via auto submit App p: go_router

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants