Chromium Code Reviews| OLD | NEW |
|---|---|
| 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/android/offline_pages/offline_page_tab_helper.h" | 5 #include "chrome/browser/android/offline_pages/offline_page_tab_helper.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/memory/ptr_util.h" | 9 #include "base/memory/ptr_util.h" |
| 10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 79 weak_ptr_factory_.InvalidateWeakPtrs(); | 79 weak_ptr_factory_.InvalidateWeakPtrs(); |
| 80 | 80 |
| 81 // Since this is a new navigation, we will reset the cached offline page, | 81 // Since this is a new navigation, we will reset the cached offline page, |
| 82 // unless we are currently looking at an offline page. | 82 // unless we are currently looking at an offline page. |
| 83 GURL navigated_url = navigation_handle->GetURL(); | 83 GURL navigated_url = navigation_handle->GetURL(); |
| 84 if (offline_page_ && navigated_url != offline_page_->GetOfflineURL()) | 84 if (offline_page_ && navigated_url != offline_page_->GetOfflineURL()) |
| 85 offline_page_ = nullptr; | 85 offline_page_ = nullptr; |
| 86 | 86 |
| 87 // Ignore navigations that are forward or back transitions in the nav stack | 87 // Ignore navigations that are forward or back transitions in the nav stack |
| 88 // which are not at the head of the stack. | 88 // which are not at the head of the stack. |
| 89 // TODO(dimich): Not sure this is needed. Clarify and remove. | |
|
dewittj
2016/06/29 00:16:31
maybe add a tracking bug reference here?
Dmitry Titov
2016/06/29 01:51:31
Done.
| |
| 89 const content::NavigationController& controller = | 90 const content::NavigationController& controller = |
| 90 web_contents()->GetController(); | 91 web_contents()->GetController(); |
| 91 if (controller.GetEntryCount() > 0 && | 92 if (controller.GetEntryCount() > 0 && |
| 92 controller.GetCurrentEntryIndex() != -1 && | 93 controller.GetCurrentEntryIndex() != -1 && |
| 93 controller.GetCurrentEntryIndex() < controller.GetEntryCount() - 1) { | 94 controller.GetCurrentEntryIndex() < controller.GetEntryCount() - 1) { |
| 94 return; | 95 return; |
| 95 } | 96 } |
| 96 | 97 |
| 97 content::BrowserContext* context = web_contents()->GetBrowserContext(); | 98 content::BrowserContext* context = web_contents()->GetBrowserContext(); |
| 98 if (net::NetworkChangeNotifier::IsOffline()) { | 99 if (net::NetworkChangeNotifier::IsOffline()) { |
| 99 GetPagesForRedirectToOffline(navigated_url, | 100 GetPagesForRedirectToOffline(navigated_url, |
| 100 RedirectReason::DISCONNECTED_NETWORK); | 101 RedirectResult::DISCONNECTED_NETWORK); |
|
dewittj
2016/06/29 00:16:31
It feels like there are actually two enums here: o
Dmitry Titov
2016/06/29 01:51:31
I removed that switch but still want to have a den
dewittj
2016/06/29 17:36:06
I was actually requesting two enums in code: one f
| |
| 101 return; | 102 return; |
| 102 } | 103 } |
| 103 | 104 |
| 104 OfflinePageModel* offline_page_model = | 105 OfflinePageModel* offline_page_model = |
| 105 OfflinePageModelFactory::GetForBrowserContext(context); | 106 OfflinePageModelFactory::GetForBrowserContext(context); |
| 106 if (!offline_page_model) | 107 if (!offline_page_model) |
| 107 return; | 108 return; |
| 108 | 109 |
| 109 offline_page_model->GetPageByOfflineURL( | 110 offline_page_model->GetPageByOfflineURL( |
| 110 navigated_url, base::Bind(&OfflinePageTabHelper::RedirectToOnline, | 111 navigated_url, base::Bind(&OfflinePageTabHelper::RedirectToOnline, |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 134 // When the navigation starts, we redirect immediately from online page to | 135 // When the navigation starts, we redirect immediately from online page to |
| 135 // offline version on the case that there is no network connection. If there | 136 // offline version on the case that there is no network connection. If there |
| 136 // is still network connection but with no or poor network connectivity, the | 137 // is still network connection but with no or poor network connectivity, the |
| 137 // navigation will eventually fail and we want to redirect to offline copy | 138 // navigation will eventually fail and we want to redirect to offline copy |
| 138 // in this case. If error code doesn't match this list, then we still show | 139 // in this case. If error code doesn't match this list, then we still show |
| 139 // the error page and not an offline page, so do nothing. | 140 // the error page and not an offline page, so do nothing. |
| 140 if (error_code != net::ERR_INTERNET_DISCONNECTED && | 141 if (error_code != net::ERR_INTERNET_DISCONNECTED && |
| 141 error_code != net::ERR_NAME_NOT_RESOLVED && | 142 error_code != net::ERR_NAME_NOT_RESOLVED && |
| 142 error_code != net::ERR_ADDRESS_UNREACHABLE && | 143 error_code != net::ERR_ADDRESS_UNREACHABLE && |
| 143 error_code != net::ERR_PROXY_CONNECTION_FAILED) { | 144 error_code != net::ERR_PROXY_CONNECTION_FAILED) { |
| 145 ReportUMARedirectResult(RedirectResult::SHOW_NET_ERROR_PAGE); | |
| 146 return; | |
| 147 } | |
| 148 // Otherwise, get the offline URL for this url, and attempt a redirect if | |
| 149 // necessary. | |
| 150 RedirectResult result = | |
| 151 ui::PageTransitionTypeIncludingQualifiersIs( | |
| 152 navigation_handle->GetPageTransition(), | |
| 153 ui::PAGE_TRANSITION_FORWARD_BACK) | |
| 154 ? RedirectResult::FLAKY_NETWORK_FORWARD_BACK | |
| 155 : RedirectResult::FLAKY_NETWORK; | |
| 156 | |
| 157 // Don't actually want to redirect on a forward/back nav. | |
| 158 // TODO(dimich): why is this? Clarify and possibly redirect as well. | |
|
jianli
2016/06/29 00:19:30
This is because doing redirect here does not work
Dmitry Titov
2016/06/29 01:51:30
I don't understand *why* it doesn't work so I'll l
| |
| 159 if (result == RedirectResult::FLAKY_NETWORK_FORWARD_BACK) { | |
|
jianli
2016/06/29 00:19:29
Can we rewrite line 148-164 to the following:
if
Dmitry Titov
2016/06/29 01:51:31
Done.
| |
| 160 ReportUMARedirectResult(RedirectResult::FLAKY_NETWORK_FORWARD_BACK); | |
| 144 return; | 161 return; |
| 145 } | 162 } |
| 146 | 163 |
| 147 // Otherwise, get the offline URL for this url, and attempt a redirect if | 164 GetPagesForRedirectToOffline(navigated_url, result); |
| 148 // necessary. | |
| 149 RedirectReason reason = | |
| 150 ui::PageTransitionTypeIncludingQualifiersIs( | |
| 151 navigation_handle->GetPageTransition(), | |
| 152 ui::PAGE_TRANSITION_FORWARD_BACK) | |
| 153 ? RedirectReason::FLAKY_NETWORK_FORWARD_BACK | |
| 154 : RedirectReason::FLAKY_NETWORK; | |
| 155 GetPagesForRedirectToOffline(navigated_url, reason); | |
| 156 } | 165 } |
| 157 | 166 |
| 158 void OfflinePageTabHelper::RedirectToOnline( | 167 void OfflinePageTabHelper::RedirectToOnline( |
| 159 const GURL& navigated_url, | 168 const GURL& navigated_url, |
| 160 const OfflinePageItem* offline_page) { | 169 const OfflinePageItem* offline_page) { |
| 161 // Bails out if no redirection is needed. | 170 // Bails out if no redirection is needed. |
| 162 if (!offline_page) | 171 if (!offline_page) |
| 163 return; | 172 return; |
| 164 | 173 |
| 165 GURL redirect_url = offline_page->url; | 174 GURL redirect_url = offline_page->url; |
| 166 | 175 if (IsInRedirectLoop(redirect_url)) |
| 167 const content::NavigationController& controller = | |
| 168 web_contents()->GetController(); | |
| 169 | |
| 170 // Avoids looping between online and offline redirections. | |
| 171 content::NavigationEntry* entry = controller.GetPendingEntry(); | |
| 172 if (entry && !entry->GetRedirectChain().empty() && | |
| 173 entry->GetRedirectChain().back() == redirect_url) { | |
| 174 return; | 176 return; |
|
dewittj
2016/06/29 00:16:31
Do we want to UMA the redirect loop?
Dmitry Titov
2016/06/29 01:51:31
Done. I think it might be a fringe condition, but
| |
| 175 } | |
| 176 | 177 |
| 177 Redirect(navigated_url, redirect_url); | 178 Redirect(navigated_url, redirect_url); |
| 178 // Clear the offline page since we are redirecting to online. | 179 // Clear the offline page since we are redirecting to online. |
| 179 offline_page_ = nullptr; | 180 offline_page_ = nullptr; |
| 180 | 181 |
| 181 UMA_HISTOGRAM_COUNTS("OfflinePages.RedirectToOnlineCount", 1); | 182 ReportUMARedirectResult(RedirectResult::CONNECTED_NETWORK); |
| 182 } | 183 } |
| 183 | 184 |
| 184 void OfflinePageTabHelper::GetPagesForRedirectToOffline(const GURL& online_url, | 185 void OfflinePageTabHelper::GetPagesForRedirectToOffline(const GURL& online_url, |
| 185 RedirectReason reason) { | 186 RedirectResult result) { |
| 186 OfflinePageModel* offline_page_model = | 187 OfflinePageModel* offline_page_model = |
| 187 OfflinePageModelFactory::GetForBrowserContext( | 188 OfflinePageModelFactory::GetForBrowserContext( |
| 188 web_contents()->GetBrowserContext()); | 189 web_contents()->GetBrowserContext()); |
| 189 if (!offline_page_model) | 190 if (!offline_page_model) |
| 190 return; | 191 return; |
| 191 | 192 |
| 192 offline_page_model->GetPagesByOnlineURL( | 193 offline_page_model->GetPagesByOnlineURL( |
| 193 online_url, | 194 online_url, |
| 194 base::Bind(&OfflinePageTabHelper::SelectBestPageForRedirectToOffline, | 195 base::Bind(&OfflinePageTabHelper::SelectBestPageForRedirectToOffline, |
| 195 weak_ptr_factory_.GetWeakPtr(), online_url, reason)); | 196 weak_ptr_factory_.GetWeakPtr(), online_url, result)); |
| 196 } | 197 } |
| 197 | 198 |
| 198 void OfflinePageTabHelper::SelectBestPageForRedirectToOffline( | 199 void OfflinePageTabHelper::SelectBestPageForRedirectToOffline( |
| 199 const GURL& online_url, | 200 const GURL& online_url, |
| 200 RedirectReason reason, | 201 RedirectResult result, |
| 201 const MultipleOfflinePageItemResult& pages) { | 202 const MultipleOfflinePageItemResult& pages) { |
| 202 // When there is no valid tab android there is nowhere to show the offline | 203 // When there is no valid tab android there is nowhere to show the offline |
| 203 // page, so we can leave. | 204 // page, so we can leave. |
| 204 std::string tab_id; | 205 std::string tab_id; |
| 205 if (!delegate_->GetTabId(web_contents(), &tab_id)) | 206 if (!delegate_->GetTabId(web_contents(), &tab_id)) { |
| 207 ReportUMARedirectResult(RedirectResult::NO_TAB_ID); | |
| 206 return; | 208 return; |
| 209 } | |
| 207 | 210 |
| 208 const OfflinePageItem* selected_page = nullptr; | 211 const OfflinePageItem* selected_page = nullptr; |
| 209 for (const auto& offline_page : pages) { | 212 for (const auto& offline_page : pages) { |
| 210 if ((offline_page.client_id.name_space == kBookmarkNamespace) || | 213 if ((offline_page.client_id.name_space == kBookmarkNamespace) || |
| 211 (offline_page.client_id.name_space == kLastNNamespace && | 214 (offline_page.client_id.name_space == kLastNNamespace && |
| 212 offline_page.client_id.id == tab_id)) { | 215 offline_page.client_id.id == tab_id)) { |
| 213 if (!selected_page || | 216 if (!selected_page || |
| 214 offline_page.creation_time > selected_page->creation_time) { | 217 offline_page.creation_time > selected_page->creation_time) { |
| 215 selected_page = &offline_page; | 218 selected_page = &offline_page; |
| 216 } | 219 } |
| 217 } | 220 } |
| 218 } | 221 } |
| 219 | 222 |
| 220 if (!selected_page) | 223 if (!selected_page) { |
| 224 ReportUMARedirectResult(result, true); // Report offline page not found. | |
| 221 return; | 225 return; |
| 226 } | |
| 222 | 227 |
| 223 TryRedirectToOffline(reason, online_url, *selected_page); | 228 TryRedirectToOffline(result, online_url, *selected_page); |
| 224 } | 229 } |
| 225 | 230 |
| 226 void OfflinePageTabHelper::TryRedirectToOffline( | 231 void OfflinePageTabHelper::TryRedirectToOffline( |
| 227 RedirectReason redirect_reason, | 232 RedirectResult result, |
| 228 const GURL& from_url, | 233 const GURL& from_url, |
| 229 const OfflinePageItem& offline_page) { | 234 const OfflinePageItem& offline_page) { |
| 230 GURL redirect_url = offline_page.GetOfflineURL(); | 235 GURL redirect_url = offline_page.GetOfflineURL(); |
| 231 if (!redirect_url.is_valid()) | 236 if (!redirect_url.is_valid()) |
| 232 return; | 237 return; |
| 233 | 238 |
| 234 if (redirect_reason == RedirectReason::FLAKY_NETWORK || | 239 if (IsInRedirectLoop(redirect_url)) |
| 235 redirect_reason == RedirectReason::FLAKY_NETWORK_FORWARD_BACK) { | 240 return; |
| 236 UMA_HISTOGRAM_BOOLEAN("OfflinePages.ShowOfflinePageOnBadNetwork", | |
| 237 redirect_reason == RedirectReason::FLAKY_NETWORK); | |
| 238 // Don't actually want to redirect on a forward/back nav. | |
| 239 if (redirect_reason == RedirectReason::FLAKY_NETWORK_FORWARD_BACK) | |
| 240 return; | |
| 241 } else { | |
| 242 const content::NavigationController& controller = | |
| 243 web_contents()->GetController(); | |
| 244 | |
| 245 // Avoids looping between online and offline redirections. | |
| 246 content::NavigationEntry* entry = controller.GetPendingEntry(); | |
| 247 if (entry && !entry->GetRedirectChain().empty() && | |
| 248 entry->GetRedirectChain().back() == redirect_url) { | |
| 249 return; | |
| 250 } | |
| 251 } | |
| 252 | 241 |
| 253 Redirect(from_url, redirect_url); | 242 Redirect(from_url, redirect_url); |
| 254 offline_page_ = base::MakeUnique<OfflinePageItem>(offline_page); | 243 offline_page_ = base::MakeUnique<OfflinePageItem>(offline_page); |
| 255 UMA_HISTOGRAM_COUNTS("OfflinePages.RedirectToOfflineCount", 1); | 244 ReportUMARedirectResult(result); |
| 256 } | 245 } |
| 257 | 246 |
| 258 void OfflinePageTabHelper::Redirect(const GURL& from_url, const GURL& to_url) { | 247 void OfflinePageTabHelper::Redirect(const GURL& from_url, const GURL& to_url) { |
| 259 content::NavigationController::LoadURLParams load_params(to_url); | 248 content::NavigationController::LoadURLParams load_params(to_url); |
| 260 load_params.transition_type = ui::PAGE_TRANSITION_CLIENT_REDIRECT; | 249 load_params.transition_type = ui::PAGE_TRANSITION_CLIENT_REDIRECT; |
| 261 load_params.redirect_chain.push_back(from_url); | 250 load_params.redirect_chain.push_back(from_url); |
| 262 web_contents()->GetController().LoadURLWithParams(load_params); | 251 web_contents()->GetController().LoadURLWithParams(load_params); |
| 263 } | 252 } |
| 264 | 253 |
| 254 bool OfflinePageTabHelper::IsInRedirectLoop(const GURL& to_url) { | |
| 255 // Avoids looping between online and offline redirections. | |
| 256 const content::NavigationController& controller = | |
| 257 web_contents()->GetController(); | |
| 258 content::NavigationEntry* entry = controller.GetPendingEntry(); | |
| 259 return entry && | |
| 260 !entry->GetRedirectChain().empty() && | |
| 261 entry->GetRedirectChain().back() == to_url; | |
| 262 } | |
| 263 | |
| 264 void OfflinePageTabHelper::ReportUMARedirectResult( | |
| 265 RedirectResult result, bool page_not_found) { | |
| 266 if (page_not_found) { | |
| 267 switch (result) { | |
|
dewittj
2016/06/29 00:16:31
This logic is a bit hard to read, it feels like th
Dmitry Titov
2016/06/29 01:51:30
Done.
| |
| 268 case RedirectResult::DISCONNECTED_NETWORK: | |
| 269 result = RedirectResult::DISCONNECTED_NETWORK_NOT_FOUND; | |
| 270 break; | |
| 271 case RedirectResult::FLAKY_NETWORK: | |
| 272 result = RedirectResult::FLAKY_NETWORK_NOT_FOUND; | |
| 273 break; | |
| 274 case RedirectResult::FLAKY_NETWORK_FORWARD_BACK: | |
| 275 result = RedirectResult::FLAKY_NETWORK_FORWARD_BACK_NOT_FOUND; | |
| 276 break; | |
| 277 default: | |
| 278 NOTREACHED(); | |
| 279 } | |
| 280 } | |
| 281 UMA_HISTOGRAM_ENUMERATION("OfflinePages.RedirectResult", | |
| 282 static_cast<int>(result), | |
| 283 static_cast<int>(RedirectResult::REDIRECT_RESULT_MAX)); | |
| 284 } | |
| 265 } // namespace offline_pages | 285 } // namespace offline_pages |
| OLD | NEW |