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