Chromium Code Reviews| Index: chrome/renderer/net/net_error_helper_core.cc |
| diff --git a/chrome/renderer/net/net_error_helper_core.cc b/chrome/renderer/net/net_error_helper_core.cc |
| index 2501ec183f9bfe64abf7f978af40df8a0b093322..1498c5f6a791f298a4b4342548139867a74a52e8 100644 |
| --- a/chrome/renderer/net/net_error_helper_core.cc |
| +++ b/chrome/renderer/net/net_error_helper_core.cc |
| @@ -6,6 +6,9 @@ |
| #include <string> |
| +#include "base/bind.h" |
| +#include "base/callback.h" |
| +#include "base/location.h" |
| #include "base/metrics/histogram.h" |
| #include "chrome/common/localized_error.h" |
| #include "net/base/escape.h" |
| @@ -16,6 +19,15 @@ |
| namespace { |
| +base::TimeDelta GetAutoReloadTime(size_t reload_count) { |
| + static const int kDelaysMs[] = { |
| + 0, 5000, 30000, 60000, 300000, 600000, 1800000 |
| + }; |
| + if (reload_count >= arraysize(kDelaysMs)) |
| + reload_count = arraysize(kDelaysMs) - 1; |
| + return base::TimeDelta::FromMilliseconds(kDelaysMs[reload_count]); |
| +} |
| + |
| // Returns whether |net_error| is a DNS-related error (and therefore whether |
| // the tab helper should start a DNS probe after receiving it.) |
| bool IsDnsError(const blink::WebURLError& error) { |
| @@ -24,6 +36,11 @@ bool IsDnsError(const blink::WebURLError& error) { |
| error.reason == net::ERR_NAME_RESOLUTION_FAILED); |
| } |
| +bool IsReloadableError(const blink::WebURLError& error) { |
| + return error.domain.utf8() == net::kErrorDomain && |
| + error.reason != net::ERR_ABORTED; |
| +} |
| + |
| // If an alternate error page should be retrieved remotely for a main frame load |
| // that failed with |error|, returns true and sets |error_page_url| to the URL |
| // of the remote error page. |
| @@ -114,25 +131,49 @@ struct NetErrorHelperCore::ErrorPageInfo { |
| // True if a page has completed loading, at which point it can receive |
| // updates. |
| bool is_finished_loading; |
| + |
| + int auto_reload_count; |
| + bool can_auto_reload_page; |
| }; |
| -NetErrorHelperCore::NetErrorHelperCore(Delegate* delegate) |
| +NetErrorHelperCore::NetErrorHelperCore(Delegate* delegate, |
| + scoped_ptr<MockableOneShotTimer> reload_timer) |
| : delegate_(delegate), |
| - last_probe_status_(chrome_common_net::DNS_PROBE_POSSIBLE) { |
| + last_probe_status_(chrome_common_net::DNS_PROBE_POSSIBLE), |
| + auto_reload_enabled_(false), |
| + auto_reload_timer_(reload_timer.Pass()), |
| + online_(true) { |
| } |
| NetErrorHelperCore::~NetErrorHelperCore() { |
| } |
| -void NetErrorHelperCore::OnStop() { |
| - // On stop, cancel loading the alternate error page, and prevent any pending |
| - // error page load from starting a new error page load. Swapping in the error |
| - // page when it's finished loading could abort the navigation, otherwise. |
| - if (committed_error_page_info_) |
| +void NetErrorHelperCore::CancelPendingFetches() { |
| + // Cancel loading the alternate error page, and prevent any pending error page |
| + // load from starting a new error page load. Swapping in the error page when |
| + // it's finished loading could abort the navigation, otherwise. |
| + if (committed_error_page_info_) { |
| + committed_error_page_info_->can_auto_reload_page = false; |
|
mmenke
2014/03/07 15:46:17
Should probably do this for pending_error_page_inf
Elly Fong-Jones
2014/03/10 19:46:51
Done.
|
| committed_error_page_info_->alternate_error_page_url = GURL(); |
| + } |
| if (pending_error_page_info_) |
| pending_error_page_info_->alternate_error_page_url = GURL(); |
| delegate_->CancelFetchErrorPage(); |
| + auto_reload_timer_->Stop(); |
| +} |
| + |
| +void NetErrorHelperCore::OnStop() { |
| + CancelPendingFetches(); |
| + if (committed_error_page_info_ && |
| + committed_error_page_info_->can_auto_reload_page) { |
|
mmenke
2014/03/07 15:46:17
CancelPendingFetches() sets can_auto_reload_page t
Elly Fong-Jones
2014/03/10 19:46:51
Done.
|
| + UMA_HISTOGRAM_CUSTOM_ENUMERATION("Net.AutoReload.ErrorAtStop", |
| + committed_error_page_info_->error.reason, |
| + net::GetAllErrorCodesForUma()); |
| + UMA_HISTOGRAM_COUNTS("Net.AutoReload.CountAtStop", |
| + committed_error_page_info_->auto_reload_count); |
| + } |
| + committed_error_page_info_->auto_reload_count = 0; |
| + committed_error_page_info_->can_auto_reload_page = false; |
| } |
| void NetErrorHelperCore::OnStartLoad(FrameType frame_type, PageType page_type) { |
| @@ -142,7 +183,7 @@ void NetErrorHelperCore::OnStartLoad(FrameType frame_type, PageType page_type) { |
| // If there's no pending error page information associated with the page load, |
| // or the new page is not an error page, then reset pending error page state. |
| if (!pending_error_page_info_ || page_type != ERROR_PAGE) { |
| - OnStop(); |
| + CancelPendingFetches(); |
| } |
| } |
| @@ -150,11 +191,28 @@ void NetErrorHelperCore::OnCommitLoad(FrameType frame_type) { |
| if (frame_type != MAIN_FRAME) |
| return; |
| + if (committed_error_page_info_ && !pending_error_page_info_ && |
| + committed_error_page_info_->can_auto_reload_page) { |
| + int reason = committed_error_page_info_->error.reason; |
| + UMA_HISTOGRAM_CUSTOM_ENUMERATION("Net.AutoReload.ErrorAtSuccess", |
| + reason, |
| + net::GetAllErrorCodesForUma()); |
| + UMA_HISTOGRAM_COUNTS("Net.AutoReload.CountAtSuccess", |
| + committed_error_page_info_->auto_reload_count); |
| + if (committed_error_page_info_->auto_reload_count == 1) |
| + UMA_HISTOGRAM_CUSTOM_ENUMERATION("Net.AutoReload.ErrorAtFirstSuccess", |
| + reason, |
| + net::GetAllErrorCodesForUma()); |
|
mmenke
2014/03/07 15:46:17
nit: +braces
Elly Fong-Jones
2014/03/10 19:46:51
Done.
|
| + } |
| + |
| committed_error_page_info_.reset(pending_error_page_info_.release()); |
| } |
| void NetErrorHelperCore::OnFinishLoad(FrameType frame_type) { |
| - if (frame_type != MAIN_FRAME || !committed_error_page_info_) |
| + if (frame_type != MAIN_FRAME) |
| + return; |
| + |
| + if (!committed_error_page_info_) |
| return; |
| committed_error_page_info_->is_finished_loading = true; |
| @@ -167,6 +225,11 @@ void NetErrorHelperCore::OnFinishLoad(FrameType frame_type) { |
| GURL error_page_url; |
| delegate_->FetchErrorPage( |
| committed_error_page_info_->alternate_error_page_url); |
| + } else if (auto_reload_enabled_ && |
| + IsReloadableError(committed_error_page_info_->error) && |
| + !committed_error_page_info_->was_failed_post) { |
|
mmenke
2014/03/07 15:46:17
Optional: May want to just pass "committed_error_
Elly Fong-Jones
2014/03/10 19:46:51
Done.
|
| + committed_error_page_info_->can_auto_reload_page = true; |
| + MaybeStartAutoReloadTimer(); |
| } |
| if (!committed_error_page_info_->needs_dns_updates || |
| @@ -317,3 +380,80 @@ blink::WebURLError NetErrorHelperCore::GetUpdatedError( |
| return updated_error; |
| } |
| + |
| +void NetErrorHelperCore::Reload() { |
| + if (!committed_error_page_info_) { |
| + return; |
| + } |
| + delegate_->ReloadPage(); |
| +} |
| + |
| +bool NetErrorHelperCore::MaybeStartAutoReloadTimer() { |
| + if (!committed_error_page_info_) |
| + return false; |
| + |
| + if (!committed_error_page_info_->can_auto_reload_page) |
| + return false; |
|
mmenke
2014/03/07 15:46:17
optional: Suggest just merging these two into one
Elly Fong-Jones
2014/03/10 19:46:51
Done.
|
| + |
| + DCHECK(IsReloadableError(committed_error_page_info_->error)); |
| + DCHECK(!committed_error_page_info_->was_failed_post); |
| + |
| + if (!online_) |
| + return false; |
| + |
| + StartAutoReloadTimer(); |
| + return true; |
| +} |
| + |
| +void NetErrorHelperCore::StartAutoReloadTimer() { |
|
mmenke
2014/03/07 15:46:17
optional: DCHECK(committed_error_page_info_)? We
Elly Fong-Jones
2014/03/10 19:46:51
Done.
|
| + base::TimeDelta delay = |
| + GetAutoReloadTime(committed_error_page_info_->auto_reload_count); |
| + committed_error_page_info_->auto_reload_count++; |
| + auto_reload_timer_->Stop(); |
| + auto_reload_timer_->Start(FROM_HERE, delay, |
| + base::Bind(&NetErrorHelperCore::Reload, |
| + base::Unretained(this))); |
| +} |
| + |
| +void NetErrorHelperCore::NetworkStateChanged(bool online) { |
| + online_ = online; |
| + if (auto_reload_timer_->IsRunning()) { |
| + DCHECK(committed_error_page_info_); |
| + // If there's an existing timer running, stop it and reset the retry count. |
| + auto_reload_timer_->Stop(); |
| + committed_error_page_info_->auto_reload_count = 0; |
| + } |
| + |
| + // If the network state changed to online, maybe start auto-reloading again. |
| + if (online) |
| + MaybeStartAutoReloadTimer(); |
| +} |
| + |
| +bool NetErrorHelperCore::ShouldSuppressErrorPage(const GURL& url) { |
| + // If |auto_reload_timer_| is still running, this error page isn't from an |
| + // auto reload. |
| + if (auto_reload_timer_->IsRunning()) |
| + return false; |
| + |
| + // If there's no committed error page, this error page wasn't from an auto |
| + // reload. |
| + if (!committed_error_page_info_) |
| + return false; |
| + |
| + // Don't suppress errors if not auto-reloading. |
| + if (!committed_error_page_info_->can_auto_reload_page) |
| + return false; |
|
mmenke
2014/03/07 15:46:17
optional: May want to merge this with the above c
Elly Fong-Jones
2014/03/10 19:46:51
Done.
|
| + |
| + GURL error_url = committed_error_page_info_->error.unreachableURL; |
| + if (error_url != url) |
| + return false; |
| + |
| + MaybeStartAutoReloadTimer(); |
| + return true; |
| +} |
| + |
| +int NetErrorHelperCore::GetAutoReloadCount() const { |
| + if (!committed_error_page_info_) |
| + return -1; |
| + return committed_error_page_info_->auto_reload_count; |
| +} |