Home | History | Annotate | Download | only in apps
      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