blob: 8e16165062cb42e3eddeb7bd898f22f8b5876879 [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 <memory>
#include "base/bind.h"
#include "base/callback.h"
#include "base/task/post_task.h"
#include "chrome/browser/browser_switcher/alternative_browser_driver.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 "chrome/common/webui_url_constants.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"
#include "net/base/url_util.h"
namespace browser_switcher {
namespace {
// Open 'chrome://browser-switch/?url=...' in the current tab.
void OpenBrowserSwitchPage(content::WebContents* web_contents,
const GURL& url,
ui::PageTransition transition_type) {
GURL about_url(chrome::kChromeUIBrowserSwitchURL);
about_url = net::AppendQueryParameter(about_url, "url", url.spec());
content::OpenURLParams params(about_url, content::Referrer(),
WindowOpenDisposition::CURRENT_TAB,
transition_type, false);
web_contents->OpenURL(params);
}
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();
bool should_switch = service->sitelist()->ShouldSwitch(url);
if (!should_switch)
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;
}
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(&OpenBrowserSwitchPage, base::Unretained(web_contents),
url, params.transition_type()));
return true;
}
} // 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