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

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: Improving the WillRedirectRequest() code comments 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 // We must not handle navigations started from the context menu. 137 // We must not handle navigations started from the context menu.
130 if (navigation_handle()->WasStartedFromContextMenu()) 138 if (navigation_handle()->WasStartedFromContextMenu())
131 return content::NavigationThrottle::PROCEED; 139 return content::NavigationThrottle::PROCEED;
132 return HandleRequest(); 140 return HandleRequest();
133 } 141 }
134 142
135 content::NavigationThrottle::ThrottleCheckResult 143 content::NavigationThrottle::ThrottleCheckResult
136 ArcNavigationThrottle::WillRedirectRequest() { 144 ArcNavigationThrottle::WillRedirectRequest() {
137 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 145 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
138
139 switch (previous_user_action_) { 146 switch (previous_user_action_) {
140 case CloseReason::ERROR: 147 case CloseReason::ERROR:
141 case CloseReason::DIALOG_DEACTIVATED: 148 case CloseReason::DIALOG_DEACTIVATED:
142 // User dismissed the dialog, or some error occurred before. Don't 149 // User dismissed the dialog, or some error occurred before. Don't
143 // repeatedly pop up the dialog. 150 // repeatedly pop up the dialog.
144 return content::NavigationThrottle::PROCEED; 151 return content::NavigationThrottle::PROCEED;
145 152
146 case CloseReason::ALWAYS_PRESSED: 153 case CloseReason::ALWAYS_PRESSED:
147 case CloseReason::JUST_ONCE_PRESSED: 154 case CloseReason::JUST_ONCE_PRESSED:
148 case CloseReason::PREFERRED_ACTIVITY_FOUND: 155 case CloseReason::PREFERRED_ACTIVITY_FOUND:
149 // Should never get here - if the user selected one of these previously, 156 // We must never show the intent picker for the same throttle more than
150 // Chrome should not see a redirect. 157 // once and we must considerate that we may have redirections within the
151 NOTREACHED(); 158 // same ArcNavigationThrottle even after seeing the UI and selecting an
159 // app to handle the navigation. This section can be reached iff the user
160 // selected Chrome to continue the navigation, since Resume() tells the
161 // throttle to continue with the chain of redirections.
162 //
163 // For example, by clicking a youtube link on gmail you can see the
164 // following URLs, assume our |starting_gurl_| is "http://www.google.com":
165 //
166 // 1) https://www.google.com/url?hl=en&q=https://youtube.com/watch?v=fake
167 // 2) https://youtube.com/watch?v=fake
168 // 3) https://www.youtube.com/watch?v=fake
169 //
170 // 1) Was caught via WillStartRequest() and 2) and 3) are caught via
Yusuke Sato 2016/10/31 21:27:09 was (lower case)
djacobo_ 2016/10/31 21:56:38 Done.
171 // WillRedirectRequest().Step 2) triggers the intent picker and step 3)
172 // will be seen iff the user picks Chrome, or if Chrome was marked as the
173 // preferred app for this kind of URL. This happens since after choosing
174 // Chrome we tell the throttle to Resume(), thus allowing for further
175 // redirections.
176 return content::NavigationThrottle::PROCEED;
152 177
153 case CloseReason::INVALID: 178 case CloseReason::INVALID:
154 // No picker has previously been popped up for this - continue. 179 // No picker has previously been popped up for this - continue.
155 break; 180 break;
156 } 181 }
157 return HandleRequest(); 182 return HandleRequest();
158 } 183 }
159 184
160 content::NavigationThrottle::ThrottleCheckResult 185 content::NavigationThrottle::ThrottleCheckResult
161 ArcNavigationThrottle::HandleRequest() { 186 ArcNavigationThrottle::HandleRequest() {
162 const GURL& url = navigation_handle()->GetURL(); 187 const GURL& url = navigation_handle()->GetURL();
163 188
164 // Always handle http(s) <form> submissions in Chrome for two reasons: 1) we 189 // Always handle http(s) <form> submissions in Chrome for two reasons: 1) we
165 // don't have a way to send POST data to ARC, and 2) intercepting http(s) form 190 // don't have a way to send POST data to ARC, and 2) intercepting http(s) form
166 // submissions is not very important because such submissions are usually 191 // submissions is not very important because such submissions are usually
167 // done within the same domain. ShouldOverrideUrlLoading() below filters out 192 // done within the same domain. ShouldOverrideUrlLoading() below filters out
168 // such submissions anyway. 193 // such submissions anyway.
169 constexpr bool kAllowFormSubmit = false; 194 constexpr bool kAllowFormSubmit = false;
170 195
171 if (ShouldIgnoreNavigation(navigation_handle()->GetPageTransition(), 196 if (ShouldIgnoreNavigation(navigation_handle()->GetPageTransition(),
172 kAllowFormSubmit)) 197 kAllowFormSubmit))
173 return content::NavigationThrottle::PROCEED; 198 return content::NavigationThrottle::PROCEED;
174 199
175 const GURL referrer_url = navigation_handle()->GetReferrer().url; 200 if (!ShouldOverrideUrlLoading(starting_gurl_, url))
176 const GURL current_url = navigation_handle()->GetURL();
177 const GURL last_committed_url =
178 navigation_handle()->GetWebContents()->GetLastCommittedURL();
179
180 // For navigations from http to https we clean up the Referrer as part of the
181 // sanitization proccess, however we may still have access to the last
182 // committed URL. On the other hand, navigations started within a new tab
183 // (e.g. due to target="_blank") will keep no track of any previous entries
184 // and so GetLastCommittedURL() can be seen empty sometimes, this is why we
185 // use one or the other accordingly. Also we don't use GetVisibleURL() since
186 // it may contain a still non-committed URL (i.e. it can be the same as
187 // GetURL()).
188 const GURL previous_url =
189 referrer_url.is_empty() ? last_committed_url : referrer_url;
190
191 if (!ShouldOverrideUrlLoading(previous_url, current_url))
192 return content::NavigationThrottle::PROCEED; 201 return content::NavigationThrottle::PROCEED;
193 202
194 ArcServiceManager* arc_service_manager = ArcServiceManager::Get(); 203 ArcServiceManager* arc_service_manager = ArcServiceManager::Get();
195 DCHECK(arc_service_manager); 204 DCHECK(arc_service_manager);
196 scoped_refptr<LocalActivityResolver> local_resolver = 205 scoped_refptr<LocalActivityResolver> local_resolver =
197 arc_service_manager->activity_resolver(); 206 arc_service_manager->activity_resolver();
198 if (local_resolver->ShouldChromeHandleUrl(url)) { 207 if (local_resolver->ShouldChromeHandleUrl(url)) {
199 // Allow navigation to proceed if there isn't an android app that handles 208 // Allow navigation to proceed if there isn't an android app that handles
200 // the given URL. 209 // the given URL.
201 return content::NavigationThrottle::PROCEED; 210 return content::NavigationThrottle::PROCEED;
202 } 211 }
203 212
204 auto* instance = ArcIntentHelperBridge::GetIntentHelperInstance( 213 auto* instance = ArcIntentHelperBridge::GetIntentHelperInstance(
205 "RequestUrlHandlerList", kMinVersionForRequestUrlHandlerList); 214 "RequestUrlHandlerList", kMinVersionForRequestUrlHandlerList);
206 if (!instance) 215 if (!instance)
207 return content::NavigationThrottle::PROCEED; 216 return content::NavigationThrottle::PROCEED;
208 instance->RequestUrlHandlerList( 217 instance->RequestUrlHandlerList(
209 url.spec(), base::Bind(&ArcNavigationThrottle::OnAppCandidatesReceived, 218 url.spec(), base::Bind(&ArcNavigationThrottle::OnAppCandidatesReceived,
210 weak_ptr_factory_.GetWeakPtr())); 219 weak_ptr_factory_.GetWeakPtr()));
211 return content::NavigationThrottle::DEFER; 220 return content::NavigationThrottle::DEFER;
212 } 221 }
213 222
223 GURL ArcNavigationThrottle::GetStartingGURL() const {
224 // This helps us determine a reference GURL for the current NavigationHandle.
225 // This is the order or preferrence: Referrer > LastCommittedURL > SiteURL,
226 // GetSiteURL *should* only be used on very rare cases, e.g. when the
227 // navigation goes from https: to http: on a new tab, thus losing the other
228 // potential referrers.
229 const GURL referrer_url = navigation_handle()->GetReferrer().url;
230 if (referrer_url.is_valid() && !referrer_url.is_empty())
231 return referrer_url;
232
233 const GURL last_committed_url =
234 navigation_handle()->GetWebContents()->GetLastCommittedURL();
235 if (last_committed_url.is_valid() && !last_committed_url.is_empty())
236 return last_committed_url;
237
238 return navigation_handle()->GetStartingSiteInstance()->GetSiteURL();
239 }
240
214 // We received the array of app candidates to handle this URL (even the Chrome 241 // We received the array of app candidates to handle this URL (even the Chrome
215 // app is included). 242 // app is included).
216 void ArcNavigationThrottle::OnAppCandidatesReceived( 243 void ArcNavigationThrottle::OnAppCandidatesReceived(
217 mojo::Array<mojom::IntentHandlerInfoPtr> handlers) { 244 mojo::Array<mojom::IntentHandlerInfoPtr> handlers) {
218 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 245 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
219 if (!IsAppAvailable(handlers)) { 246 if (!IsAppAvailable(handlers)) {
220 // This scenario shouldn't be accesed as ArcNavigationThrottle is created 247 // This scenario shouldn't be accesed as ArcNavigationThrottle is created
221 // iff there are ARC apps which can actually handle the given URL. 248 // iff there are ARC apps which can actually handle the given URL.
222 DVLOG(1) << "There are no app candidates for this URL: " 249 DVLOG(1) << "There are no app candidates for this URL: "
223 << navigation_handle()->GetURL(); 250 << navigation_handle()->GetURL();
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
378 } 405 }
379 406
380 // static 407 // static
381 bool ArcNavigationThrottle::IsSwapElementsNeededForTesting( 408 bool ArcNavigationThrottle::IsSwapElementsNeededForTesting(
382 const mojo::Array<mojom::IntentHandlerInfoPtr>& handlers, 409 const mojo::Array<mojom::IntentHandlerInfoPtr>& handlers,
383 std::pair<size_t, size_t>* out_indices) { 410 std::pair<size_t, size_t>* out_indices) {
384 return IsSwapElementsNeeded(handlers, out_indices); 411 return IsSwapElementsNeeded(handlers, out_indices);
385 } 412 }
386 413
387 } // namespace arc 414 } // namespace arc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698