Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(409)

Side by Side Diff: chrome/browser/chromeos/arc/intent_helper/arc_navigation_throttle.cc

Issue 2458073003: Modifies how Arc's throttle handles redirections (Closed)
Patch Set: Rebasing Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/chromeos/arc/intent_helper/arc_navigation_throttle.h" 5 #include "chrome/browser/chromeos/arc/intent_helper/arc_navigation_throttle.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/memory/ref_counted.h" 11 #include "base/memory/ref_counted.h"
12 #include "base/metrics/histogram_macros.h" 12 #include "base/metrics/histogram_macros.h"
13 #include "components/arc/arc_bridge_service.h" 13 #include "components/arc/arc_bridge_service.h"
14 #include "components/arc/arc_service_manager.h" 14 #include "components/arc/arc_service_manager.h"
15 #include "components/arc/intent_helper/arc_intent_helper_bridge.h" 15 #include "components/arc/intent_helper/arc_intent_helper_bridge.h"
16 #include "components/arc/intent_helper/local_activity_resolver.h" 16 #include "components/arc/intent_helper/local_activity_resolver.h"
17 #include "components/arc/intent_helper/page_transition_util.h" 17 #include "components/arc/intent_helper/page_transition_util.h"
18 #include "content/public/browser/browser_thread.h" 18 #include "content/public/browser/browser_thread.h"
19 #include "content/public/browser/navigation_controller.h" 19 #include "content/public/browser/navigation_controller.h"
20 #include "content/public/browser/navigation_handle.h" 20 #include "content/public/browser/navigation_handle.h"
21 #include "content/public/browser/site_instance.h"
21 #include "content/public/browser/web_contents.h" 22 #include "content/public/browser/web_contents.h"
22 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" 23 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
23 #include "ui/base/page_transition_types.h" 24 #include "ui/base/page_transition_types.h"
24 #include "url/gurl.h"
25 25
26 namespace arc { 26 namespace arc {
27 27
28 namespace { 28 namespace {
29 29
30 constexpr uint32_t kMinVersionForHandleUrl = 2; 30 constexpr uint32_t kMinVersionForHandleUrl = 2;
31 constexpr uint32_t kMinVersionForRequestUrlHandlerList = 2; 31 constexpr uint32_t kMinVersionForRequestUrlHandlerList = 2;
32 constexpr uint32_t kMinVersionForAddPreferredPackage = 7; 32 constexpr uint32_t kMinVersionForAddPreferredPackage = 7;
33 33
34 scoped_refptr<ActivityIconLoader> GetIconLoader() { 34 scoped_refptr<ActivityIconLoader> GetIconLoader() {
(...skipping 11 matching lines...) Expand all
46 // it in the desktop browser. 46 // it in the desktop browser.
47 if (!previous_url.is_valid() || previous_url.is_empty()) 47 if (!previous_url.is_valid() || previous_url.is_empty())
48 return false; 48 return false;
49 49
50 // Also check |current_url| just in case. 50 // Also check |current_url| just in case.
51 if (!current_url.is_valid() || current_url.is_empty()) { 51 if (!current_url.is_valid() || current_url.is_empty()) {
52 DVLOG(1) << "Unexpected URL: " << current_url << ", opening it in Chrome."; 52 DVLOG(1) << "Unexpected URL: " << current_url << ", opening it in Chrome.";
53 return false; 53 return false;
54 } 54 }
55 55
56 // Check the scheme for both |previous_url| and |current_url| since an
57 // extension could have referred us (e.g. Google Docs).
58 if (!current_url.SchemeIsHTTPOrHTTPS() ||
59 !previous_url.SchemeIsHTTPOrHTTPS()) {
60 return false;
61 }
62
56 return !net::registry_controlled_domains::SameDomainOrHost( 63 return !net::registry_controlled_domains::SameDomainOrHost(
57 current_url, previous_url, 64 current_url, previous_url,
58 net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES); 65 net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
59 } 66 }
60 67
61 // Returns true if |handlers| contain one or more apps. When this function is 68 // Returns true if |handlers| contain one or more apps. When this function is
62 // called from OnAppCandidatesReceived, |handlers| always contain Chrome (aka 69 // called from OnAppCandidatesReceived, |handlers| always contain Chrome (aka
63 // intent_helper), but the function doesn't treat it as an app. 70 // intent_helper), but the function doesn't treat it as an app.
64 bool IsAppAvailable(const mojo::Array<mojom::IntentHandlerInfoPtr>& handlers) { 71 bool IsAppAvailable(const mojo::Array<mojom::IntentHandlerInfoPtr>& handlers) {
65 return handlers.size() > 1 || (handlers.size() == 1 && 72 return handlers.size() > 1 || (handlers.size() == 1 &&
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
119 : content::NavigationThrottle(navigation_handle), 126 : content::NavigationThrottle(navigation_handle),
120 show_intent_picker_callback_(show_intent_picker_cb), 127 show_intent_picker_callback_(show_intent_picker_cb),
121 previous_user_action_(CloseReason::INVALID), 128 previous_user_action_(CloseReason::INVALID),
122 weak_ptr_factory_(this) {} 129 weak_ptr_factory_(this) {}
123 130
124 ArcNavigationThrottle::~ArcNavigationThrottle() = default; 131 ArcNavigationThrottle::~ArcNavigationThrottle() = default;
125 132
126 content::NavigationThrottle::ThrottleCheckResult 133 content::NavigationThrottle::ThrottleCheckResult
127 ArcNavigationThrottle::WillStartRequest() { 134 ArcNavigationThrottle::WillStartRequest() {
128 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 135 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
136 starting_gurl_ = GetStartingGURL();
129 return HandleRequest(); 137 return HandleRequest();
130 } 138 }
131 139
132 content::NavigationThrottle::ThrottleCheckResult 140 content::NavigationThrottle::ThrottleCheckResult
133 ArcNavigationThrottle::WillRedirectRequest() { 141 ArcNavigationThrottle::WillRedirectRequest() {
134 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 142 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
135
136 switch (previous_user_action_) { 143 switch (previous_user_action_) {
137 case CloseReason::ERROR: 144 case CloseReason::ERROR:
138 case CloseReason::DIALOG_DEACTIVATED: 145 case CloseReason::DIALOG_DEACTIVATED:
139 // User dismissed the dialog, or some error occurred before. Don't 146 // User dismissed the dialog, or some error occurred before. Don't
140 // repeatedly pop up the dialog. 147 // repeatedly pop up the dialog.
141 return content::NavigationThrottle::PROCEED; 148 return content::NavigationThrottle::PROCEED;
142 149
143 case CloseReason::ALWAYS_PRESSED: 150 case CloseReason::ALWAYS_PRESSED:
144 case CloseReason::JUST_ONCE_PRESSED: 151 case CloseReason::JUST_ONCE_PRESSED:
145 case CloseReason::PREFERRED_ACTIVITY_FOUND: 152 case CloseReason::PREFERRED_ACTIVITY_FOUND:
146 // Should never get here - if the user selected one of these previously, 153 // We must never show the intent picker for the same throttle more than
147 // Chrome should not see a redirect. 154 // once and we must considerate that we may have redirections within the
148 NOTREACHED(); 155 // same ArcNavigationThrottle even after seeing the UI and selecting an
156 // app to handle the navigation. This section can be reached iff the user
157 // selected Chrome to continue the navigation, since Resume() tells the
158 // throttle to continue with the chain of redirections.
159 //
160 // For example, by clicking a youtube link on gmail you can see the
161 // following URLs, assume our |starting_gurl_| is "http://www.google.com":
162 //
163 // 1) https://www.google.com/url?hl=en&q=https://youtube.com/watch?v=fake
164 // 2) https://youtube.com/watch?v=fake
165 // 3) https://www.youtube.com/watch?v=fake
166 //
167 // 1) was caught via WillStartRequest() and 2) and 3) are caught via
168 // WillRedirectRequest().Step 2) triggers the intent picker and step 3)
169 // will be seen iff the user picks Chrome, or if Chrome was marked as the
170 // preferred app for this kind of URL. This happens since after choosing
171 // Chrome we tell the throttle to Resume(), thus allowing for further
172 // redirections.
173 return content::NavigationThrottle::PROCEED;
149 174
150 case CloseReason::INVALID: 175 case CloseReason::INVALID:
151 // No picker has previously been popped up for this - continue. 176 // No picker has previously been popped up for this - continue.
152 break; 177 break;
153 } 178 }
154 return HandleRequest(); 179 return HandleRequest();
155 } 180 }
156 181
157 content::NavigationThrottle::ThrottleCheckResult 182 content::NavigationThrottle::ThrottleCheckResult
158 ArcNavigationThrottle::HandleRequest() { 183 ArcNavigationThrottle::HandleRequest() {
159 const GURL& url = navigation_handle()->GetURL(); 184 const GURL& url = navigation_handle()->GetURL();
160 185
161 // Always handle http(s) <form> submissions in Chrome for two reasons: 1) we 186 // Always handle http(s) <form> submissions in Chrome for two reasons: 1) we
162 // don't have a way to send POST data to ARC, and 2) intercepting http(s) form 187 // don't have a way to send POST data to ARC, and 2) intercepting http(s) form
163 // submissions is not very important because such submissions are usually 188 // submissions is not very important because such submissions are usually
164 // done within the same domain. ShouldOverrideUrlLoading() below filters out 189 // done within the same domain. ShouldOverrideUrlLoading() below filters out
165 // such submissions anyway. 190 // such submissions anyway.
166 constexpr bool kAllowFormSubmit = false; 191 constexpr bool kAllowFormSubmit = false;
167 192
168 // We must never handle navigations started within a context menu. 193 // We must never handle navigations started within a context menu.
169 if (navigation_handle()->WasStartedFromContextMenu()) 194 if (navigation_handle()->WasStartedFromContextMenu())
170 return content::NavigationThrottle::PROCEED; 195 return content::NavigationThrottle::PROCEED;
171 196
172 if (ShouldIgnoreNavigation(navigation_handle()->GetPageTransition(), 197 if (ShouldIgnoreNavigation(navigation_handle()->GetPageTransition(),
173 kAllowFormSubmit)) 198 kAllowFormSubmit))
174 return content::NavigationThrottle::PROCEED; 199 return content::NavigationThrottle::PROCEED;
175 200
176 const GURL referrer_url = navigation_handle()->GetReferrer().url; 201 if (!ShouldOverrideUrlLoading(starting_gurl_, url))
177 const GURL current_url = navigation_handle()->GetURL();
178 const GURL last_committed_url =
179 navigation_handle()->GetWebContents()->GetLastCommittedURL();
180
181 // For navigations from http to https we clean up the Referrer as part of the
182 // sanitization proccess, however we may still have access to the last
183 // committed URL. On the other hand, navigations started within a new tab
184 // (e.g. due to target="_blank") will keep no track of any previous entries
185 // and so GetLastCommittedURL() can be seen empty sometimes, this is why we
186 // use one or the other accordingly. Also we don't use GetVisibleURL() since
187 // it may contain a still non-committed URL (i.e. it can be the same as
188 // GetURL()).
189 const GURL previous_url =
190 referrer_url.is_empty() ? last_committed_url : referrer_url;
191
192 if (!ShouldOverrideUrlLoading(previous_url, current_url))
193 return content::NavigationThrottle::PROCEED; 202 return content::NavigationThrottle::PROCEED;
194 203
195 ArcServiceManager* arc_service_manager = ArcServiceManager::Get(); 204 ArcServiceManager* arc_service_manager = ArcServiceManager::Get();
196 DCHECK(arc_service_manager); 205 DCHECK(arc_service_manager);
197 scoped_refptr<LocalActivityResolver> local_resolver = 206 scoped_refptr<LocalActivityResolver> local_resolver =
198 arc_service_manager->activity_resolver(); 207 arc_service_manager->activity_resolver();
199 if (local_resolver->ShouldChromeHandleUrl(url)) { 208 if (local_resolver->ShouldChromeHandleUrl(url)) {
200 // Allow navigation to proceed if there isn't an android app that handles 209 // Allow navigation to proceed if there isn't an android app that handles
201 // the given URL. 210 // the given URL.
202 return content::NavigationThrottle::PROCEED; 211 return content::NavigationThrottle::PROCEED;
203 } 212 }
204 213
205 auto* instance = ArcIntentHelperBridge::GetIntentHelperInstance( 214 auto* instance = ArcIntentHelperBridge::GetIntentHelperInstance(
206 "RequestUrlHandlerList", kMinVersionForRequestUrlHandlerList); 215 "RequestUrlHandlerList", kMinVersionForRequestUrlHandlerList);
207 if (!instance) 216 if (!instance)
208 return content::NavigationThrottle::PROCEED; 217 return content::NavigationThrottle::PROCEED;
209 instance->RequestUrlHandlerList( 218 instance->RequestUrlHandlerList(
210 url.spec(), base::Bind(&ArcNavigationThrottle::OnAppCandidatesReceived, 219 url.spec(), base::Bind(&ArcNavigationThrottle::OnAppCandidatesReceived,
211 weak_ptr_factory_.GetWeakPtr())); 220 weak_ptr_factory_.GetWeakPtr()));
212 return content::NavigationThrottle::DEFER; 221 return content::NavigationThrottle::DEFER;
213 } 222 }
214 223
224 GURL ArcNavigationThrottle::GetStartingGURL() const {
225 // This helps us determine a reference GURL for the current NavigationHandle.
226 // This is the order or preferrence: Referrer > LastCommittedURL > SiteURL,
227 // GetSiteURL *should* only be used on very rare cases, e.g. when the
228 // navigation goes from https: to http: on a new tab, thus losing the other
229 // potential referrers.
230 const GURL referrer_url = navigation_handle()->GetReferrer().url;
231 if (referrer_url.is_valid() && !referrer_url.is_empty())
232 return referrer_url;
233
234 const GURL last_committed_url =
235 navigation_handle()->GetWebContents()->GetLastCommittedURL();
236 if (last_committed_url.is_valid() && !last_committed_url.is_empty())
237 return last_committed_url;
238
239 return navigation_handle()->GetStartingSiteInstance()->GetSiteURL();
240 }
241
215 // We received the array of app candidates to handle this URL (even the Chrome 242 // We received the array of app candidates to handle this URL (even the Chrome
216 // app is included). 243 // app is included).
217 void ArcNavigationThrottle::OnAppCandidatesReceived( 244 void ArcNavigationThrottle::OnAppCandidatesReceived(
218 mojo::Array<mojom::IntentHandlerInfoPtr> handlers) { 245 mojo::Array<mojom::IntentHandlerInfoPtr> handlers) {
219 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 246 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
220 if (!IsAppAvailable(handlers)) { 247 if (!IsAppAvailable(handlers)) {
221 // This scenario shouldn't be accesed as ArcNavigationThrottle is created 248 // This scenario shouldn't be accesed as ArcNavigationThrottle is created
222 // iff there are ARC apps which can actually handle the given URL. 249 // iff there are ARC apps which can actually handle the given URL.
223 DVLOG(1) << "There are no app candidates for this URL: " 250 DVLOG(1) << "There are no app candidates for this URL: "
224 << navigation_handle()->GetURL(); 251 << navigation_handle()->GetURL();
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
379 } 406 }
380 407
381 // static 408 // static
382 bool ArcNavigationThrottle::IsSwapElementsNeededForTesting( 409 bool ArcNavigationThrottle::IsSwapElementsNeededForTesting(
383 const mojo::Array<mojom::IntentHandlerInfoPtr>& handlers, 410 const mojo::Array<mojom::IntentHandlerInfoPtr>& handlers,
384 std::pair<size_t, size_t>* out_indices) { 411 std::pair<size_t, size_t>* out_indices) {
385 return IsSwapElementsNeeded(handlers, out_indices); 412 return IsSwapElementsNeeded(handlers, out_indices);
386 } 413 }
387 414
388 } // namespace arc 415 } // namespace arc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698