slovnicki / beamer

A routing package built on top of Router and Navigator's pages API, supporting arbitrary nested navigation, guards and more.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Wrong URL shown in browser after redirecting to the same page in BeamGuard

BarashkovaElena opened this issue · comments

Describe the bug
When BeamGuard is applied, BeamerDelegate configuration is left incorrect if BeamGuard redirects on the same page we are currently on. A visible result of this is wrong URL in the browser address field in the web application.

Beamer version: 1.5.5

To Reproduce
Let's assume that there is an application that have two screens, auth and main. The navigation between them is set through BeamerDelegate with a single location that handles two pages with the following routes: /auth and /main. To forbid navigation to /auth after user had authorized, BeamGuard is added.
The simplified version of it looks like this:

      BeamGuard(
        pathPatterns: [
          '/auth',
        ],
        check: (context, location) => userIsNotAuthorized(),
        beamToNamed: (origin, target) {
          return '/main';
        },

So basically it redirects back to /main.
The steps to reproduce are:

  1. Open auth page in the web application
  2. Go to the main page
  3. Press back button in the browser of manually edit the URL so that it ends with /auth
  4. The application stays on the same page (that is correct) but the URL in the browser shows /auth

Expected behavior
the URL in the browser shows /main

As I can see in the code, this happens because configuration is changed before applying BeamGuards in the update method:

    this.configuration = configuration != null
        ? Utils.createNewConfiguration(this.configuration, configuration)
        : currentBeamLocation.state.routeInformation.copyWith();

and then the method exits in the middle without restoring the configuration

    // run guards on _beamLocationCandidate
    final context = _context;
    if (context != null) {
      final didApply = _runGuards(context, _beamLocationCandidate);
      _didRunGuards = true;
      if (didApply) {
        return;
      } else {
        // TODO revert configuration if guard just blocked navigation
      }
    }

If _runGuards method redirects to another page, this issue doesn't happen, because update is called again and updates the configuration. For example, if beamToNamed is set, update method is called either from beamToReplacementNamed or from beamToNamed. But if it detects that redirect is the current route, it exits.

    if (beamToNamed != null) {
      final redirectNamed = beamToNamed!(origin, target);
      if (redirectNamed == target.state.routeInformation.location) {
        // just block if this will produce an immediate infinite loop
        return true;
      }
      if (redirectNamed == origin.state.routeInformation.location) {
        // just block if redirect is the current route
        return true;
      }
      if (replaceCurrentStack) {
        delegate.beamToReplacementNamed(redirectNamed);
      } else {
        delegate.beamToNamed(redirectNamed);
      }
      return true;
    }