• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
LaunchEphemeralApp(const std::string & app_id,content::WebContents * source,const navigation_interception::NavigationParams & params)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*
MaybeCreateThrottleForLaunch(net::URLRequest * request,ProfileIOData * profile_io_data)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