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 "chrome/common/extensions/extension_constants.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 "net/url_request/url_request.h" 21 22 using content::BrowserThread; 23 using content::WebContents; 24 using extensions::Extension; 25 26 namespace { 27 28 bool LaunchEphemeralApp( 29 const std::string& app_id, 30 content::WebContents* source, 31 const navigation_interception::NavigationParams& params) { 32 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 33 34 // Redirect top-level navigations only. 35 if (source->IsSubframe()) 36 return false; 37 38 Profile* profile = 39 Profile::FromBrowserContext(source->GetBrowserContext()); 40 if (!profile) 41 return false; 42 43 ExtensionService* service = 44 extensions::ExtensionSystem::Get(profile)->extension_service(); 45 DCHECK(service); 46 const Extension* extension = service->GetInstalledExtension(app_id); 47 48 // Only launch apps. 49 if (extension && !extension->is_app()) 50 return false; 51 52 // The EphemeralAppLauncher will handle launching of an existing app or 53 // installing and launching a new ephemeral app. 54 scoped_refptr<EphemeralAppLauncher> installer = 55 EphemeralAppLauncher::CreateForLink(app_id, source); 56 installer->Start(); 57 return true; 58 } 59 60 } // namespace 61 62 // static 63 content::ResourceThrottle* 64 EphemeralAppThrottle::MaybeCreateThrottleForLaunch( 65 net::URLRequest* request, 66 ProfileIOData* profile_io_data) { 67 if (!CommandLine::ForCurrentProcess()->HasSwitch( 68 switches::kEnableLinkableEphemeralApps)) 69 return NULL; 70 71 if (request->method() != "GET" || !request->url().SchemeIsHTTPOrHTTPS()) 72 return NULL; 73 74 // Not supported for incognito profiles. 75 if (profile_io_data->IsOffTheRecord()) 76 return NULL; 77 78 // Only watch for links in Google search results. 79 if (request->referrer().find("https://www.google.com") == std::string::npos) 80 return NULL; 81 82 // Crudely watch for links to Chrome Web Store detail pages and assume that 83 // the app ID will be after the last slash of the URL. We cannot even 84 // differentiate between apps and extensions, so attempt to launch both. 85 // This is obviously for demonstration purposes only and will be implemented 86 // properly in production code - for example, links to ephemeral apps could 87 // have a new scheme. 88 if (request->url().spec().find( 89 extension_urls::GetWebstoreItemDetailURLPrefix()) != 0) 90 return NULL; 91 92 std::string app_id(request->url().ExtractFileName()); 93 if (!Extension::IdIsValid(app_id)) 94 return NULL; 95 96 return new navigation_interception::InterceptNavigationResourceThrottle( 97 request, 98 base::Bind(&LaunchEphemeralApp, app_id)); 99 } 100