blob: c0fbd7105426c05df83a46829b93d27cdccd539c [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/browser_switcher/browser_switcher_navigation_throttle.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/task/post_task.h"
#include "chrome/browser/browser_switcher/alternative_browser_launcher.h"
#include "chrome/browser/browser_switcher/browser_switcher_service.h"
#include "chrome/browser/browser_switcher/browser_switcher_service_factory.h"
#include "chrome/browser/browser_switcher/browser_switcher_sitelist.h"
#include "chrome/browser/prerender/prerender_contents.h"
#include "chrome/browser/profiles/profile.h"
#include "components/navigation_interception/intercept_navigation_throttle.h"
#include "components/navigation_interception/navigation_params.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/guest_mode.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/web_contents.h"
namespace browser_switcher {
namespace {
bool MaybeLaunchAlternativeBrowser(
content::WebContents* web_contents,
const navigation_interception::NavigationParams& params) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
BrowserSwitcherService* service =
BrowserSwitcherServiceFactory::GetForBrowserContext(
web_contents->GetBrowserContext());
const GURL& url = params.url();
if (!service->sitelist()->ShouldSwitch(url))
return false;
// Redirect top-level navigations only. This excludes iframes and webviews
// in particular.
if (content::GuestMode::IsCrossProcessFrameGuest(web_contents))
return false;
// If prerendering, don't launch the alternative browser but abort the
// navigation.
prerender::PrerenderContents* prerender_contents =
prerender::PrerenderContents::FromWebContents(web_contents);
if (prerender_contents) {
prerender_contents->Destroy(prerender::FINAL_STATUS_BROWSER_SWITCH);
return true;
}
// TODO(nicolaso): Once the chrome://browserswitch page is implemented, open
// that instead of immediately launching the browser/closing the tab.
bool success = service->launcher()->Launch(url);
if (success) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(&content::WebContents::ClosePage,
base::Unretained(web_contents)));
return true;
}
// Launching the browser failed, fall back to loading the page normally.
//
// TODO(nicolaso): Show an error page instead.
return false;
}
} // namespace
// static
std::unique_ptr<content::NavigationThrottle>
BrowserSwitcherNavigationThrottle::MaybeCreateThrottleFor(
content::NavigationHandle* navigation) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
content::BrowserContext* browser_context =
navigation->GetWebContents()->GetBrowserContext();
if (browser_context->IsOffTheRecord())
return nullptr;
if (!navigation->IsInMainFrame())
return nullptr;
return std::make_unique<navigation_interception::InterceptNavigationThrottle>(
navigation, base::BindRepeating(&MaybeLaunchAlternativeBrowser));
}
} // namespace browser_switcher