1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/apps/ephemeral_app_throttle.h" 6 7 #include "base/command_line.h" 8 #include "chrome/browser/apps/ephemeral_app_launcher.h" 9 #include "chrome/browser/extensions/extension_service.h" 10 #include "chrome/browser/profiles/profile.h" 11 #include "chrome/browser/profiles/profile_io_data.h" 12 #include "chrome/common/chrome_switches.h" 13 #include "components/crx_file/id_util.h" 14 #include "components/navigation_interception/intercept_navigation_resource_throttle.h" 15 #include "components/navigation_interception/navigation_params.h" 16 #include "content/public/browser/browser_thread.h" 17 #include "content/public/browser/resource_throttle.h" 18 #include "content/public/browser/web_contents.h" 19 #include "extensions/browser/extension_system.h" 20 #include "extensions/common/extension_urls.h" 21 #include "net/url_request/url_request.h" 22 23 using content::BrowserThread; 24 using content::WebContents; 25 using extensions::Extension; 26 27 namespace { 28 29 bool LaunchEphemeralApp( 30 const std::string& app_id, 31 content::WebContents* source, 32 const navigation_interception::NavigationParams& params) { 33 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 34 35 // Redirect top-level navigations only. 36 if (source->IsSubframe()) 37 return false; 38 39 Profile* profile = 40 Profile::FromBrowserContext(source->GetBrowserContext()); 41 if (!profile) 42 return false; 43 44 ExtensionService* service = 45 extensions::ExtensionSystem::Get(profile)->extension_service(); 46 DCHECK(service); 47 const Extension* extension = service->GetInstalledExtension(app_id); 48 49 // Only launch apps. 50 if (extension && !extension->is_app()) 51 return false; 52 53 // The EphemeralAppLauncher will handle launching of an existing app or 54 // installing and launching a new ephemeral app. 55 scoped_refptr<EphemeralAppLauncher> installer = 56 EphemeralAppLauncher::CreateForWebContents( 57 app_id, source, EphemeralAppLauncher::LaunchCallback()); 58 installer->Start(); 59 return true; 60 } 61 62 } // namespace 63 64 // static 65 content::ResourceThrottle* 66 EphemeralAppThrottle::MaybeCreateThrottleForLaunch( 67 net::URLRequest* request, 68 ProfileIOData* profile_io_data) { 69 if (!CommandLine::ForCurrentProcess()->HasSwitch( 70 switches::kEnableLinkableEphemeralApps)) 71 return NULL; 72 73 if (request->method() != "GET" || !request->url().SchemeIsHTTPOrHTTPS()) 74 return NULL; 75 76 // Not supported for incognito profiles. 77 if (profile_io_data->IsOffTheRecord()) 78 return NULL; 79 80 // Only watch for links in Google search results. 81 if (request->referrer().find("https://www.google.com") == std::string::npos) 82 return NULL; 83 84 // Crudely watch for links to Chrome Web Store detail pages and assume that 85 // the app ID will be after the last slash of the URL. We cannot even 86 // differentiate between apps and extensions, so attempt to launch both. 87 // This is obviously for demonstration purposes only and will be implemented 88 // properly in production code - for example, links to ephemeral apps could 89 // have a new scheme. 90 if (request->url().spec().find( 91 extension_urls::GetWebstoreItemDetailURLPrefix()) != 0) 92 return NULL; 93 94 std::string app_id(request->url().ExtractFileName()); 95 if (!crx_file::id_util::IdIsValid(app_id)) 96 return NULL; 97 98 return new navigation_interception::InterceptNavigationResourceThrottle( 99 request, 100 base::Bind(&LaunchEphemeralApp, app_id)); 101 } 102