| // 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 |