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

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

Issue 2471783005: Modifies how Arc's throttle handles redirections (Closed)
Patch Set: Documenting differences on M-55 implementation. 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/arc_navigation_throttle.h" 5 #include "chrome/browser/chromeos/arc/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 "chrome/browser/chromeos/arc/page_transition_util.h" 13 #include "chrome/browser/chromeos/arc/page_transition_util.h"
14 #include "components/arc/arc_bridge_service.h" 14 #include "components/arc/arc_bridge_service.h"
15 #include "components/arc/arc_service_manager.h" 15 #include "components/arc/arc_service_manager.h"
16 #include "components/arc/intent_helper/arc_intent_helper_bridge.h" 16 #include "components/arc/intent_helper/arc_intent_helper_bridge.h"
17 #include "components/arc/intent_helper/local_activity_resolver.h" 17 #include "components/arc/intent_helper/local_activity_resolver.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 } // namespace 68 } // namespace
62 69
63 ArcNavigationThrottle::ArcNavigationThrottle( 70 ArcNavigationThrottle::ArcNavigationThrottle(
64 content::NavigationHandle* navigation_handle, 71 content::NavigationHandle* navigation_handle,
65 const ShowIntentPickerCallback& show_intent_picker_cb) 72 const ShowIntentPickerCallback& show_intent_picker_cb)
66 : content::NavigationThrottle(navigation_handle), 73 : content::NavigationThrottle(navigation_handle),
67 show_intent_picker_callback_(show_intent_picker_cb), 74 show_intent_picker_callback_(show_intent_picker_cb),
68 previous_user_action_(CloseReason::INVALID), 75 previous_user_action_(CloseReason::INVALID),
69 weak_ptr_factory_(this) {} 76 weak_ptr_factory_(this) {}
70 77
71 ArcNavigationThrottle::~ArcNavigationThrottle() = default; 78 ArcNavigationThrottle::~ArcNavigationThrottle() = default;
72 79
73 content::NavigationThrottle::ThrottleCheckResult 80 content::NavigationThrottle::ThrottleCheckResult
74 ArcNavigationThrottle::WillStartRequest() { 81 ArcNavigationThrottle::WillStartRequest() {
75 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 82 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
83 starting_gurl_ = GetStartingGURL();
76 return HandleRequest(); 84 return HandleRequest();
77 } 85 }
78 86
79 content::NavigationThrottle::ThrottleCheckResult 87 content::NavigationThrottle::ThrottleCheckResult
80 ArcNavigationThrottle::WillRedirectRequest() { 88 ArcNavigationThrottle::WillRedirectRequest() {
81 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 89 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
82 90
83 switch (previous_user_action_) { 91 switch (previous_user_action_) {
84 case CloseReason::ERROR: 92 case CloseReason::ERROR:
85 case CloseReason::DIALOG_DEACTIVATED: 93 case CloseReason::DIALOG_DEACTIVATED:
86 // User dismissed the dialog, or some error occurred before. Don't 94 // User dismissed the dialog, or some error occurred before. Don't
87 // repeatedly pop up the dialog. 95 // repeatedly pop up the dialog.
88 return content::NavigationThrottle::PROCEED; 96 return content::NavigationThrottle::PROCEED;
89 97
90 case CloseReason::ALWAYS_PRESSED: 98 case CloseReason::ALWAYS_PRESSED:
91 case CloseReason::JUST_ONCE_PRESSED: 99 case CloseReason::JUST_ONCE_PRESSED:
92 case CloseReason::PREFERRED_ACTIVITY_FOUND: 100 case CloseReason::PREFERRED_ACTIVITY_FOUND:
93 // Should never get here - if the user selected one of these previously, 101 // We must never show the intent picker for the same throttle more than
94 // Chrome should not see a redirect. 102 // once and we must considerate that we may have redirections within the
95 NOTREACHED(); 103 // same ArcNavigationThrottle even after seeing the UI and selecting an
104 // app to handle the navigation. This section can be reached iff the user
105 // selected Chrome to continue the navigation, since Resume() tells the
106 // throttle to continue with the chain of redirections.
107 //
108 // For example, by clicking a youtube link on gmail you can see the
109 // following URLs, assume our |starting_gurl_| is "http://www.google.com":
110 //
111 // 1) https://www.google.com/url?hl=en&q=https://youtube.com/watch?v=fake
112 // 2) https://youtube.com/watch?v=fake
113 // 3) https://www.youtube.com/watch?v=fake
114 //
115 // 1) was caught via WillStartRequest() and 2) and 3) are caught via
116 // WillRedirectRequest().Step 2) triggers the intent picker and step 3)
117 // will be seen iff the user picks Chrome, or if Chrome was marked as the
118 // preferred app for this kind of URL. This happens since after choosing
119 // Chrome we tell the throttle to Resume(), thus allowing for further
120 // redirections.
121 return content::NavigationThrottle::PROCEED;
96 122
97 case CloseReason::INVALID: 123 case CloseReason::INVALID:
98 // No picker has previously been popped up for this - continue. 124 // No picker has previously been popped up for this - continue.
99 break; 125 break;
100 } 126 }
101 return HandleRequest(); 127 return HandleRequest();
102 } 128 }
103 129
104 content::NavigationThrottle::ThrottleCheckResult 130 content::NavigationThrottle::ThrottleCheckResult
105 ArcNavigationThrottle::HandleRequest() { 131 ArcNavigationThrottle::HandleRequest() {
106 const GURL& url = navigation_handle()->GetURL(); 132 const GURL& url = navigation_handle()->GetURL();
107 133
108 // Always handle http(s) <form> submissions in Chrome for two reasons: 1) we 134 // Always handle http(s) <form> submissions in Chrome for two reasons: 1) we
109 // don't have a way to send POST data to ARC, and 2) intercepting http(s) form 135 // don't have a way to send POST data to ARC, and 2) intercepting http(s) form
110 // submissions is not very important because such submissions are usually 136 // submissions is not very important because such submissions are usually
111 // done within the same domain. ShouldOverrideUrlLoading() below filters out 137 // done within the same domain. ShouldOverrideUrlLoading() below filters out
112 // such submissions anyway. 138 // such submissions anyway.
113 constexpr bool kAllowFormSubmit = false; 139 constexpr bool kAllowFormSubmit = false;
114 140
115 // We must not handle navigations started from the context menu. 141 // We must not handle navigations started from the context menu.
116 if (navigation_handle()->WasStartedFromContextMenu()) 142 if (navigation_handle()->WasStartedFromContextMenu())
117 return content::NavigationThrottle::PROCEED; 143 return content::NavigationThrottle::PROCEED;
118 144
119 if (ShouldIgnoreNavigation(navigation_handle()->GetPageTransition(), 145 if (ShouldIgnoreNavigation(navigation_handle()->GetPageTransition(),
120 kAllowFormSubmit)) 146 kAllowFormSubmit))
121 return content::NavigationThrottle::PROCEED; 147 return content::NavigationThrottle::PROCEED;
122 148
123 const GURL referrer_url = navigation_handle()->GetReferrer().url; 149 if (!ShouldOverrideUrlLoading(starting_gurl_, url))
124 const GURL current_url = navigation_handle()->GetURL();
125 const GURL last_committed_url =
126 navigation_handle()->GetWebContents()->GetLastCommittedURL();
127
128 // For navigations from http to https we clean up the Referrer as part of the
129 // sanitization proccess, however we may still have access to the last
130 // committed URL. On the other hand, navigations started within a new tab
131 // (e.g. due to target="_blank") will keep no track of any previous entries
132 // and so GetLastCommittedURL() can be seen empty sometimes, this is why we
133 // use one or the other accordingly. Also we don't use GetVisibleURL() since
134 // it may contain a still non-committed URL (i.e. it can be the same as
135 // GetURL()).
136 const GURL previous_url =
137 referrer_url.is_empty() ? last_committed_url : referrer_url;
138
139 if (!ShouldOverrideUrlLoading(previous_url, current_url))
140 return content::NavigationThrottle::PROCEED; 150 return content::NavigationThrottle::PROCEED;
141 151
142 ArcServiceManager* arc_service_manager = ArcServiceManager::Get(); 152 ArcServiceManager* arc_service_manager = ArcServiceManager::Get();
143 DCHECK(arc_service_manager); 153 DCHECK(arc_service_manager);
144 scoped_refptr<LocalActivityResolver> local_resolver = 154 scoped_refptr<LocalActivityResolver> local_resolver =
145 arc_service_manager->activity_resolver(); 155 arc_service_manager->activity_resolver();
146 if (local_resolver->ShouldChromeHandleUrl(url)) { 156 if (local_resolver->ShouldChromeHandleUrl(url)) {
147 // Allow navigation to proceed if there isn't an android app that handles 157 // Allow navigation to proceed if there isn't an android app that handles
148 // the given URL. 158 // the given URL.
149 return content::NavigationThrottle::PROCEED; 159 return content::NavigationThrottle::PROCEED;
150 } 160 }
151 161
152 auto* instance = ArcIntentHelperBridge::GetIntentHelperInstance( 162 auto* instance = ArcIntentHelperBridge::GetIntentHelperInstance(
153 "RequestUrlHandlerList", kMinVersionForRequestUrlHandlerList); 163 "RequestUrlHandlerList", kMinVersionForRequestUrlHandlerList);
154 if (!instance) 164 if (!instance)
155 return content::NavigationThrottle::PROCEED; 165 return content::NavigationThrottle::PROCEED;
156 instance->RequestUrlHandlerList( 166 instance->RequestUrlHandlerList(
157 url.spec(), base::Bind(&ArcNavigationThrottle::OnAppCandidatesReceived, 167 url.spec(), base::Bind(&ArcNavigationThrottle::OnAppCandidatesReceived,
158 weak_ptr_factory_.GetWeakPtr())); 168 weak_ptr_factory_.GetWeakPtr()));
159 return content::NavigationThrottle::DEFER; 169 return content::NavigationThrottle::DEFER;
160 } 170 }
161 171
172 GURL ArcNavigationThrottle::GetStartingGURL() const {
173 // This helps us determine a reference GURL for the current NavigationHandle.
174 // This is the order or preferrence: Referrer > LastCommittedURL > SiteURL,
175 // GetSiteURL *should* only be used on very rare cases, e.g. when the
176 // navigation goes from https: to http: on a new tab, thus losing the other
177 // potential referrers.
178 const GURL referrer_url = navigation_handle()->GetReferrer().url;
179 if (referrer_url.is_valid() && !referrer_url.is_empty())
180 return referrer_url;
181
182 const GURL last_committed_url =
183 navigation_handle()->GetWebContents()->GetLastCommittedURL();
184 if (last_committed_url.is_valid() && !last_committed_url.is_empty())
185 return last_committed_url;
186
187 // Using |site_| from WebContents instead of NavigationHandle as a reference
188 // for |starting_gurl_|, this is a workaround required for [M-55] given the
189 // available interfaces at the classes mentioned.
190 return navigation_handle()->GetWebContents()->GetSiteInstance()->GetSiteURL();
191 }
192
162 // We received the array of app candidates to handle this URL (even the Chrome 193 // We received the array of app candidates to handle this URL (even the Chrome
163 // app is included). 194 // app is included).
164 void ArcNavigationThrottle::OnAppCandidatesReceived( 195 void ArcNavigationThrottle::OnAppCandidatesReceived(
165 mojo::Array<mojom::IntentHandlerInfoPtr> handlers) { 196 mojo::Array<mojom::IntentHandlerInfoPtr> handlers) {
166 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 197 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
167 if (handlers.empty() || 198 if (handlers.empty() ||
168 (handlers.size() == 1 && ArcIntentHelperBridge::IsIntentHelperPackage( 199 (handlers.size() == 1 && ArcIntentHelperBridge::IsIntentHelperPackage(
169 handlers[0]->package_name))) { 200 handlers[0]->package_name))) {
170 // This scenario shouldn't be accesed as ArcNavigationThrottle is created 201 // This scenario shouldn't be accesed as ArcNavigationThrottle is created
171 // iff there are ARC apps which can actually handle the given URL. 202 // iff there are ARC apps which can actually handle the given URL.
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after
324 } 355 }
325 356
326 // static 357 // static
327 bool ArcNavigationThrottle::ShouldOverrideUrlLoadingForTesting( 358 bool ArcNavigationThrottle::ShouldOverrideUrlLoadingForTesting(
328 const GURL& previous_url, 359 const GURL& previous_url,
329 const GURL& current_url) { 360 const GURL& current_url) {
330 return ShouldOverrideUrlLoading(previous_url, current_url); 361 return ShouldOverrideUrlLoading(previous_url, current_url);
331 } 362 }
332 363
333 } // namespace arc 364 } // namespace arc
OLDNEW
« no previous file with comments | « chrome/browser/chromeos/arc/arc_navigation_throttle.h ('k') | chrome/browser/chromeos/arc/arc_navigation_throttle_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698