async onBeforeRequest()

in src/js/background/assignManager.js [223:375]


  async onBeforeRequest(options) {
    if (options.frameId !== 0 || options.tabId === -1) {
      return {};
    }
    this.removeContextMenu();
    const [tab, siteSettings] = await Promise.all([
      browser.tabs.get(options.tabId),
      this.storageArea.get(options.url)
    ]);
    let container;
    try {
      container = await browser.contextualIdentities
        .get(backgroundLogic.cookieStoreId(siteSettings.userContextId));
    } catch (e) {
      container = false;
    }

    // The container we have in the assignment map isn't present any
    // more so lets remove it then continue the existing load
    if (siteSettings && !container) {
      this.deleteContainer(siteSettings.userContextId);
      return {};
    }
    const userContextId = this.getUserContextIdFromCookieStore(tab);

    // https://github.com/mozilla/multi-account-containers/issues/847
    //
    // Handle the case where this request's URL is not assigned to any particular
    // container. We must do the following check:
    //
    // If the current tab's container is "unlocked", we can just go ahead
    // and open the URL in the current tab, since an "unlocked" container accepts
    // any-and-all sites.
    //
    // But if the current tab's container has been "locked" by the user, then we must
    // re-open the page in the default container, because the user doesn't want random
    // sites polluting their locked container.
    //
    // For example:
    //   - the current tab's container is locked and only allows "www.google.com"
    //   - the incoming request is for "www.amazon.com", which has no specific container assignment
    //   - in this case, we must re-open "www.amazon.com" in a new tab in the default container
    const siteIsolatedReloadInDefault =
      await this._maybeSiteIsolatedReloadInDefault(siteSettings, tab);

    if (!siteIsolatedReloadInDefault) {
      if (!siteSettings
          || userContextId === siteSettings.userContextId
          || this.storageArea.isExempted(options.url, tab.id)) {
        return {};
      }
    }
    const replaceTabEnabled = await this.storageArea.getReplaceTabEnabled();
    const removeTab = backgroundLogic.NEW_TAB_PAGES.has(tab.url)
      || (messageHandler.lastCreatedTab
        && messageHandler.lastCreatedTab.id === tab.id)
      || replaceTabEnabled;
    const openTabId = removeTab ? tab.openerTabId : tab.id;

    if (!this.canceledRequests[tab.id]) {
      // we decided to cancel the request at this point, register
      // canceled request
      this.canceledRequests[tab.id] = {
        requestIds: {
          [options.requestId]: true
        },
        urls: {
          [options.url]: true
        }
      };

      // since webRequest onCompleted and onErrorOccurred are not 100%
      // reliable (see #1120)
      // we register a timer here to cleanup canceled requests, just to
      // make sure we don't
      // end up in a situation where certain urls in a tab.id stay canceled
      setTimeout(() => {
        if (this.canceledRequests[tab.id]) {
          delete this.canceledRequests[tab.id];
        }
      }, 2000);
    } else {
      let cancelEarly = false;
      if (this.canceledRequests[tab.id].requestIds[options.requestId] ||
          this.canceledRequests[tab.id].urls[options.url]) {
        // same requestId or url from the same tab
        // this is a redirect that we have to cancel early to prevent
        // opening two tabs
        cancelEarly = true;
      }
      // we decided to cancel the request at this point, register canceled
      // request
      this.canceledRequests[tab.id].requestIds[options.requestId] = true;
      this.canceledRequests[tab.id].urls[options.url] = true;
      if (cancelEarly) {
        return {
          cancel: true
        };
      }
    }

    if (siteIsolatedReloadInDefault) {
      this.reloadPageInDefaultContainer(
        options.url,
        tab.index + 1,
        tab.active,
        openTabId,
        tab.groupId
      );
    } else {
      this.reloadPageInContainer(
        options.url,
        userContextId,
        siteSettings.userContextId,
        tab.index + 1,
        tab.active,
        siteSettings.neverAsk,
        openTabId,
        tab.groupId
      );
    }
    this.calculateContextMenu(tab);

    /* Removal of existing tabs:
        We aim to open the new assigned container tab / warning prompt in
        it's own tab:
          - As the history won't span from one container to another it
            seems most sane to not try and reopen a tab on history.back()
          - When users open a new tab themselves we want to make sure we
            don't end up with three tabs as per:
            https://github.com/mozilla/testpilot-containers/issues/421
        If we are coming from an internal url that are used for the new
        tab page (NEW_TAB_PAGES), we can safely close as user is unlikely
        losing history
        Detecting redirects on "new tab" opening actions is pretty hard
        as we don't get tab history:
        - Redirects happen from Short URLs and tracking links that act as
          a gateway
        - Extensions don't provide a way to history crawl for tabs, we
          could inject content scripts to do this
            however they don't run on about:blank so this would likely be
            just as hacky.
        We capture the time the tab was created and close if it was within
        the timeout to try to capture pages which haven't had user
        interaction or history.
    */
    if (removeTab) {
      browser.tabs.remove(tab.id);
    }
    return {
      cancel: true,
    };
  },