| // Copyright 2013 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/apps/ephemeral_app_throttle.h" |
| |
| #include "base/command_line.h" |
| #include "chrome/browser/apps/ephemeral_app_launcher.h" |
| #include "chrome/browser/extensions/extension_service.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/profiles/profile_io_data.h" |
| #include "chrome/common/chrome_switches.h" |
| #include "chrome/common/extensions/extension_constants.h" |
| #include "components/navigation_interception/intercept_navigation_resource_throttle.h" |
| #include "components/navigation_interception/navigation_params.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/resource_throttle.h" |
| #include "content/public/browser/web_contents.h" |
| #include "extensions/browser/extension_system.h" |
| #include "net/url_request/url_request.h" |
| |
| using content::BrowserThread; |
| using content::WebContents; |
| using extensions::Extension; |
| |
| namespace { |
| |
| bool LaunchEphemeralApp( |
| const std::string& app_id, |
| content::WebContents* source, |
| const navigation_interception::NavigationParams& params) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| |
| // Redirect top-level navigations only. |
| if (source->IsSubframe()) |
| return false; |
| |
| Profile* profile = |
| Profile::FromBrowserContext(source->GetBrowserContext()); |
| if (!profile) |
| return false; |
| |
| ExtensionService* service = |
| extensions::ExtensionSystem::Get(profile)->extension_service(); |
| DCHECK(service); |
| const Extension* extension = service->GetInstalledExtension(app_id); |
| |
| // Only launch apps. |
| if (extension && !extension->is_app()) |
| return false; |
| |
| // The EphemeralAppLauncher will handle launching of an existing app or |
| // installing and launching a new ephemeral app. |
| scoped_refptr<EphemeralAppLauncher> installer = |
| EphemeralAppLauncher::CreateForLink(app_id, source); |
| installer->Start(); |
| return true; |
| } |
| |
| } // namespace |
| |
| // static |
| content::ResourceThrottle* |
| EphemeralAppThrottle::MaybeCreateThrottleForLaunch( |
| net::URLRequest* request, |
| ProfileIOData* profile_io_data) { |
| if (!CommandLine::ForCurrentProcess()->HasSwitch( |
| switches::kEnableLinkableEphemeralApps)) |
| return NULL; |
| |
| if (request->method() != "GET" || !request->url().SchemeIsHTTPOrHTTPS()) |
| return NULL; |
| |
| // Not supported for incognito profiles. |
| if (profile_io_data->IsOffTheRecord()) |
| return NULL; |
| |
| // Only watch for links in Google search results. |
| if (request->referrer().find("https://www.google.com") == std::string::npos) |
| return NULL; |
| |
| // Crudely watch for links to Chrome Web Store detail pages and assume that |
| // the app ID will be after the last slash of the URL. We cannot even |
| // differentiate between apps and extensions, so attempt to launch both. |
| // This is obviously for demonstration purposes only and will be implemented |
| // properly in production code - for example, links to ephemeral apps could |
| // have a new scheme. |
| if (request->url().spec().find( |
| extension_urls::GetWebstoreItemDetailURLPrefix()) != 0) |
| return NULL; |
| |
| std::string app_id(request->url().ExtractFileName()); |
| if (!Extension::IdIsValid(app_id)) |
| return NULL; |
| |
| return new navigation_interception::InterceptNavigationResourceThrottle( |
| request, |
| base::Bind(&LaunchEphemeralApp, app_id)); |
| } |