Repository: flutter
Issue: Routing unencodes encoded hashes in the URL, producing in an incorrect URL
Labels: framework,f: routes,has reproducible steps,P2,team-framework,triaged-framework,found in release: 3.24,found in release: 3.26

### Steps to reproduce

I'm trying to track down a bug in DevTools where values on the querystring get lost. It happens when a value is a hex colour (`#ffffff`) that contains a hash. The hash is correctly encoded initially, but Flutter seems to update the URL with an unencoded version in a way that results in `window.location.href` being incorrect (because the string after the hash is treated as a client-side fragement and not part of the querystring value).

While it might be better if DevTools could avoid reading `window.location` directly, this feels like incorrect behaviour (for example trying to bookmark the URL or similar would use an incorrect URL).

To reproduce:

- Navigate to an app that has an encoded hash in a querystring value (for example `http://localhost:49774/home?a=ccc%23ddd`)
- Print the value of `window.location.href` (or check it in the browser address bar) as the app is loading before routing is initialized
- Print the value of `window.location.href` (or check it in the browser address bar) after the app has loaded/routing has initialized

### Expected results

The value of `window.location.href` should not change to unescape the hash. This changes the meaning of the URL:

```
/home?a=b%23c // This means "a" has the value of "b#c"
/home?a=b#c // This means "a" has the value of "b" and there is a client-side fragment "#c"
```

### Actual results

The hash in the URL is unescaped, resulting in a different (incorrect) URL. Bookmarking this, or reading the value with `window.location.href` will produce invalid results.

### Code sample

<details open><summary>Code sample</summary>

```dart
import 'dart:html';
import 'dart:async';
import 'dart:collection';

import 'package:flutter_web_plugins/url_strategy.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

void main() {
  usePathUrlStrategy();
  runApp(const MainApp());
}

final routerDelegate = MyRouterDelegate();
final routeInfromationParser = MyRouteInformationParser();

class MainApp extends StatelessWidget {
  const MainApp({super.key});

  void printCurrentUrlInfo() {
    print('The current window.location.href is ${window.location.href}');
    var paramValue = Uri.parse(window.location.href).queryParameters['a'];
    print('The current query parameter "a" is ${paramValue}');
  }

  @override
  Widget build(BuildContext context) {
    printCurrentUrlInfo();
    Future.delayed(const Duration(seconds: 1))
        .then((_) => printCurrentUrlInfo());
    return MaterialApp.router(
      builder: (context, child) => child!,
      routerDelegate: routerDelegate,
      routeInformationParser: routeInfromationParser,
    );
  }
}

class MyRouteConfiguration {
  MyRouteConfiguration(this.page, this.params);

  final String page;
  final Map<String, String?> params;
}

class MyRouteInformationParser
    extends RouteInformationParser<MyRouteConfiguration> {
  @override
  Future<MyRouteConfiguration> parseRouteInformation(
    RouteInformation routeInformation,
  ) async {
    var uri = routeInformation.uri;

    // Paths start with /
    final page = uri.path.isNotEmpty ? uri.path.substring(1) : '';
    final configuration = MyRouteConfiguration(page, uri.queryParameters);
    return SynchronousFuture<MyRouteConfiguration>(configuration);
  }

  @override
  RouteInformation restoreRouteInformation(
    MyRouteConfiguration configuration,
  ) {
    return RouteInformation(
        uri: Uri(
      // Paths must always start with /
      path: '/${configuration.page}',
      queryParameters: configuration.params,
    ));
  }
}

class MyRouterDelegate extends RouterDelegate<MyRouteConfiguration>
    with ChangeNotifier, PopNavigatorRouterDelegateMixin<MyRouteConfiguration> {
  MyRouterDelegate() : navigatorKey = GlobalKey<NavigatorState>();

  static MyRouterDelegate of(BuildContext context) =>
      Router.of(context).routerDelegate as MyRouterDelegate;

  @override
  final GlobalKey<NavigatorState> navigatorKey;

  final _routes = ListQueue<MyRouteConfiguration>();

  @override
  MyRouteConfiguration? get currentConfiguration => _routes.lastOrNull;

  @override
  Widget build(BuildContext context) {
    final uri1 = Uri(path: '/home', queryParameters: {'a': 'bbb'});
    final uri2 = Uri(path: '/home', queryParameters: {'a': 'ccc#ddd'});

    return Navigator(
      key: navigatorKey,
      pages: [
        MaterialPage(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text('Open DevTools console!'),
              for (var uri in [uri1, uri2])
                TextButton(
                  onPressed: () => window.location.href = uri.toString(),
                  child: Text('Load page as $uri'),
                ),
            ],
          ),
        ),
      ],
      onDidRemovePage: (_) {
        if (_routes.length <= 1) return;
        _routes.removeLast();
        notifyListeners();
      },
    );
  }

  @override
  Future<void> setNewRoutePath(MyRouteConfiguration configuration) async {
    _routes
      ..clear()
      ..add(configuration);

    notifyListeners();
    return SynchronousFuture<void>(null);
  }
}
```

</details>


### Screenshots or Video

<details open>
<summary>Screenshots / Video demonstration</summary>

![image](https://github.com/user-attachments/assets/f2361dc3-cdd3-4f9a-be15-3504ca74a60a)

https://github.com/user-attachments/assets/2268bd45-361c-4736-b5f0-a742b31f4e5e

</details>


### Logs

<details open><summary>Logs</summary>

```console
[Paste your logs here]
```

</details>


### Flutter Doctor output

<details open><summary>Doctor output</summary>

```console
[!] Flutter (Channel master, 3.26.0-1.0.pre.232, on Microsoft Windows [Version 10.0.22631.4169], locale en-GB)
    • Flutter version 3.26.0-1.0.pre.232 on channel master at D:\Dev\Google\Flutter\Flutter main
    ! Warning: `dart` on your path resolves to D:\Tools\Dart\Stable\bin\dart.exe, which is not inside your current Flutter SDK checkout at
      D:\Dev\Google\Flutter\Flutter main. Consider adding D:\Dev\Google\Flutter\Flutter main\bin to the front of your path.
    • Upstream repository git@github.com:DanTup/flutter.git
    • FLUTTER_GIT_URL = git@github.com:DanTup/flutter.git
    • Framework revision f7b363929d (5 days ago), 2024-09-26 08:04:29 -0400
    • Engine revision 6328a0597b
    • Dart version 3.6.0 (build 3.6.0-279.0.dev)
    • DevTools version 2.40.0-dev.1
    • If those were intentional, you can disregard the above warnings; however it is recommended to use "git" directly to perform update checks and
      upgrades.

[✓] Windows Version (Installed version of Windows is version 10 or higher)

[✓] Android toolchain - develop for Android devices (Android SDK version 35.0.0-rc3)
    • Android SDK at C:\Users\danny\AppData\Local\Android\sdk
    • Platform android-35, build-tools 35.0.0-rc3
    • Java binary at: C:\Program Files\Android\Android Studio\jbr\bin\java
    • Java version OpenJDK Runtime Environment (build 17.0.9+0--11185874)
    • All Android licenses accepted.

[✓] Chrome - develop for the web
    • Chrome at C:\Program Files\Google\Chrome\Application\chrome.exe

[✓] Visual Studio - develop Windows apps (Visual Studio Community 2022 17.10.5)
    • Visual Studio at C:\Program Files\Microsoft Visual Studio\2022\Community
    • Visual Studio Community 2022 version 17.10.35122.118
    • Windows 10 SDK version 10.0.22621.0

[✓] Android Studio (version 2023.2)
    • Android Studio at C:\Program Files\Android\Android Studio
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 17.0.9+0--11185874)

[✓] VS Code (version 1.93.1)
    • VS Code at C:\Users\danny\AppData\Local\Programs\Microsoft VS Code
    • Flutter extension version 3.99.20240930

[✓] VS Code (version 1.93.0-insider)
    • VS Code at C:\Users\danny\AppData\Local\Programs\Microsoft VS Code Insiders
    • Flutter extension version 3.95.20240801

[✓] Connected device (3 available)
    • Windows (desktop) • windows • windows-x64    • Microsoft Windows [Version 10.0.22631.4169]
    • Chrome (web)      • chrome  • web-javascript • Google Chrome 129.0.6668.70
    • Edge (web)        • edge    • web-javascript • Microsoft Edge 127.0.2651.86

[✓] Network resources
    • All expected network resources are available.

! Doctor found issues in 1 category.
```

</details>