• 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/app_url_redirector.h"
6 
7 #include "apps/launcher.h"
8 #include "base/bind.h"
9 #include "base/logging.h"
10 #include "chrome/browser/prerender/prerender_contents.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/browser/profiles/profile_io_data.h"
13 #include "chrome/common/extensions/api/url_handlers/url_handlers_parser.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/render_view_host.h"
18 #include "content/public/browser/resource_request_info.h"
19 #include "content/public/browser/resource_throttle.h"
20 #include "content/public/browser/web_contents.h"
21 #include "extensions/browser/info_map.h"
22 #include "extensions/common/extension.h"
23 #include "extensions/common/extension_messages.h"
24 #include "extensions/common/extension_set.h"
25 #include "net/url_request/url_request.h"
26 
27 using content::BrowserThread;
28 using content::ResourceRequestInfo;
29 using content::WebContents;
30 using extensions::Extension;
31 using extensions::UrlHandlers;
32 using extensions::UrlHandlerInfo;
33 
34 namespace {
35 
LaunchAppWithUrl(const scoped_refptr<const Extension> app,const std::string & handler_id,content::WebContents * source,const navigation_interception::NavigationParams & params)36 bool LaunchAppWithUrl(
37     const scoped_refptr<const Extension> app,
38     const std::string& handler_id,
39     content::WebContents* source,
40     const navigation_interception::NavigationParams& params) {
41   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
42 
43   // Redirect top-level navigations only. This excludes iframes and webviews
44   // in particular.
45   if (source->IsSubframe()) {
46     DVLOG(1) << "Cancel redirection: source is a subframe";
47     return false;
48   }
49 
50   // If prerendering, don't launch the app but abort the navigation.
51   prerender::PrerenderContents* prerender_contents =
52       prerender::PrerenderContents::FromWebContents(source);
53   if (prerender_contents) {
54     prerender_contents->Destroy(prerender::FINAL_STATUS_NAVIGATION_INTERCEPTED);
55     return true;
56   }
57 
58   // These are guaranteed by CreateThrottleFor below.
59   DCHECK(!params.is_post());
60   DCHECK(UrlHandlers::CanExtensionHandleUrl(app, params.url()));
61 
62   Profile* profile =
63       Profile::FromBrowserContext(source->GetBrowserContext());
64 
65   DVLOG(1) << "Launching app handler with URL: "
66            << params.url().spec() << " -> "
67            << app->name() << "(" << app->id() << "):" << handler_id;
68   apps::LaunchPlatformAppWithUrl(
69       profile, app, handler_id, params.url(), params.referrer().url);
70 
71   return true;
72 }
73 
74 }  // namespace
75 
76 // static
77 content::ResourceThrottle*
MaybeCreateThrottleFor(net::URLRequest * request,ProfileIOData * profile_io_data)78 AppUrlRedirector::MaybeCreateThrottleFor(net::URLRequest* request,
79                                          ProfileIOData* profile_io_data) {
80   DVLOG(1) << "Considering URL for redirection: "
81            << request->method() << " " << request->url().spec();
82 
83   // Support only GET for now.
84   if (request->method() != "GET") {
85     DVLOG(1) << "Skip redirection: method is not GET";
86     return NULL;
87   }
88 
89   if (!request->url().SchemeIsHTTPOrHTTPS()) {
90     DVLOG(1) << "Skip redirection: scheme is not HTTP or HTTPS";
91     return NULL;
92   }
93 
94   // The user has indicated that a URL should be force downloaded. Turn off
95   // URL redirection in this case.
96   if (ResourceRequestInfo::ForRequest(request)->IsDownload()) {
97     DVLOG(1) << "Skip redirection: request is a forced download";
98     return NULL;
99   }
100 
101   // Never redirect URLs to apps in incognito. Technically, apps are not
102   // supported in incognito, but that may change in future.
103   // See crbug.com/240879, which tracks incognito support for v2 apps.
104   if (profile_io_data->IsOffTheRecord()) {
105     DVLOG(1) << "Skip redirection: unsupported in incognito";
106     return NULL;
107   }
108 
109   const extensions::ExtensionSet& extensions =
110       profile_io_data->GetExtensionInfoMap()->extensions();
111   for (extensions::ExtensionSet::const_iterator iter = extensions.begin();
112        iter != extensions.end();
113        ++iter) {
114     const UrlHandlerInfo* handler =
115         UrlHandlers::FindMatchingUrlHandler(*iter, request->url());
116     if (handler) {
117       DVLOG(1) << "Found matching app handler for redirection: "
118                << (*iter)->name() << "(" << (*iter)->id() << "):"
119                << handler->id;
120       return new navigation_interception::InterceptNavigationResourceThrottle(
121           request,
122           base::Bind(&LaunchAppWithUrl,
123                      scoped_refptr<const Extension>(*iter),
124                      handler->id));
125     }
126   }
127 
128   DVLOG(1) << "Skipping redirection: no matching app handler found";
129   return NULL;
130 }
131