Skip to content

[web] Stop percent-decoding URLs written to browser history - #189835

Merged
auto-submit[bot] merged 8 commits into
flutter:masterfrom
apinilabs-pascal:fix/web-history-url-percent-decoding
Oct 3, 2026
Merged

auto-submit[bot] merged 8 commits into
flutter:masterfrom
apinilabs-pascal:fix/web-history-url-percent-decoding

Conversation

@apinilabs-pascal

Copy link
Copy Markdown
Contributor

When the framework reports new route information via the routeInformationUpdated
navigation message, the web engine rebuilds the URL and runs Uri.decodeComponent
over the whole string before handing it to the browser history (introduced in
flutter-team-archive/engine#40250). This strips one level of percent-encoding from the address
bar on every report:

Framework reports Address bar before Address bar after this PR
/item/foo%2Fbar /item/foo/bar — refresh/share resolves to a different route /item/foo%2Fbar
?q=x%26y ?q=x&y — value splits into two query parameters ?q=x%26y
?color=%23ffffff ?color=#ffffff — rest of the URL becomes a fragment ?color=%23ffffff

Because routers decode path parameters exactly once, this also made
GoRouterState.pathParameters differ between in-app navigation and a subsequent
browser refresh of the same URL: each round trip through the engine silently
dropped one encoding level.

Fix

handleNavigationMessage keeps the scheme/authority stripping, but now reassembles
the URL from the raw (still encoded) path, query, and fragment components
instead of decoding the result. The browser's address bar now reflects exactly what
the framework reported.

This supersedes #176029, which was closed for inactivity (missing tests). Unlike
that attempt, this PR also avoids reconstructing the query via
Uri(queryParameters:), which re-encoded values differently than reported
(e.g. %20 in a query value came back as +), and it adds a regression test.

Tests

Adds a regression test to lib/web_ui/test/engine/routing_test.dart asserting
that %20, %2F, and %26 in path, query, and fragment survive the round trip
into browser history unchanged. The existing routeInformationUpdated can handle uri test (scheme/authority stripping) is unaffected and still passes.

Fixes #180373
Fixes #171757
Fixes #147857
Fixes #155992

cc @mdebbar (you triaged #176029 and invited a re-open — this picks that up with tests)

Pre-launch Checklist

If you need help, consider asking for advice on the #hackers-new channel on Discord.

If this change needs to override an active code freeze, provide a comment explaining why. The code freeze workflow can be overridden by code reviewers. See pinned issues for any active code freezes with guidance.

Note: The Flutter team is currently trialing the use of Gemini Code Assist for GitHub. Comments from the gemini-code-assist bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.

When the framework reports new route information via
`routeInformationUpdated`, the web engine rebuilt the URL and ran
`Uri.decodeComponent` over the whole string before handing it to the
browser history. This stripped one level of percent-encoding from the
address bar on every report:

- `/item/foo%2Fbar` became `/item/foo/bar`, so refreshing or sharing
  the link no longer resolved to the same route.
- Query values containing an encoded `&` (`?q=x%26y`) were corrupted
  into two separate parameters (`?q=x&y`), and encoded hashes
  (`%23`) turned into real fragment separators.
- Routers that decode path parameters once (e.g. go_router) saw
  different parameter values for deep links vs. in-app navigation,
  because each report through the engine dropped an encoding level.

Keep the scheme/authority stripping, but reassemble the URL from the
raw (still encoded) path, query, and fragment components so the
browser's address bar reflects exactly what the framework reported.
Unlike the earlier attempt in flutter#176029, this also avoids re-encoding
the query via `Uri(queryParameters:)`, which altered the reported
encoding (e.g. `%20` becoming `+`), and adds a regression test.

Fixes flutter#180373
Fixes flutter#171757
Fixes flutter#147857
Fixes flutter#155992
@github-actions github-actions Bot added engine flutter/engine related. See also e: labels. platform-web Web applications specifically team-web Owned by Web platform team labels Jul 22, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request modifies EngineFlutterWindow to preserve the percent-encoding of the path, query, and fragment when extracting the path from a URI string, and adds a corresponding regression test. Feedback on the changes points out that Dart's Uri properties (path, query, and fragment) return decoded strings, which would fail to preserve the percent-encoding and cause the new test to fail. It is suggested to extract these components directly from the original URI string instead.

Comment thread engine/src/flutter/lib/web_ui/lib/src/engine/window.dart
@flutter-zl
flutter-zl requested a review from mdebbar August 5, 2026 18:27

@mdebbar mdebbar left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for the contribution!

@mdebbar mdebbar added the CICD Run CI/CD label Aug 13, 2026

@yjbanov yjbanov left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

lgtm

@flutter-dashboard flutter-dashboard Bot removed the CICD Run CI/CD label Aug 14, 2026
@mdebbar mdebbar added the CICD Run CI/CD label Aug 21, 2026
@flutter-zl flutter-zl added the autosubmit Merge PR when tree becomes green via auto submit App label Sep 23, 2026
@flutter-dashboard flutter-dashboard Bot removed the CICD Run CI/CD label Sep 23, 2026
@flutter-zl flutter-zl added the CICD Run CI/CD label Sep 23, 2026
@auto-submit auto-submit Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Sep 24, 2026
@auto-submit

auto-submit Bot commented Sep 24, 2026

Copy link
Copy Markdown
Contributor

autosubmit label was removed for flutter/flutter/189835, because - The status or check suite Google testing has failed. Please fix the issues identified (or deflake) before re-applying this label.

@flutter-dashboard flutter-dashboard Bot removed the CICD Run CI/CD label Oct 1, 2026
@mdebbar mdebbar added CICD Run CI/CD autosubmit Merge PR when tree becomes green via auto submit App labels Oct 1, 2026
@mdebbar

mdebbar commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

I had to fix something in internal Google Testing. It should be mergeable now. Thanks again for contributing this fix!

@auto-submit
auto-submit Bot added this pull request to the merge queue Oct 2, 2026
Merged via the queue into flutter:master with commit 513aea6 Oct 3, 2026
30 checks passed
@flutter-dashboard flutter-dashboard Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Oct 3, 2026
@apinilabs-pascal
apinilabs-pascal deleted the fix/web-history-url-percent-decoding branch October 6, 2026 07:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CICD Run CI/CD engine flutter/engine related. See also e: labels. platform-web Web applications specifically team-web Owned by Web platform team

Projects

None yet

4 participants