| 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..e517157eb04152e30e1f13065e7515c096bf5d62 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) {
|
| @@ -116,23 +128,50 @@ struct NetErrorHelperCore::ErrorPageInfo {
|
| bool is_finished_loading;
|
| };
|
|
|
| +bool NetErrorHelperCore::IsReloadableError(
|
| + const NetErrorHelperCore::ErrorPageInfo& info) {
|
| + return info.error.domain.utf8() == net::kErrorDomain &&
|
| + info.error.reason != net::ERR_ABORTED &&
|
| + !info.was_failed_post;
|
| +}
|
| +
|
| NetErrorHelperCore::NetErrorHelperCore(Delegate* delegate)
|
| : 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_(new MockableOneShotTimer()),
|
| + online_(true),
|
| + auto_reload_count_(0),
|
| + can_auto_reload_page_(false) {
|
| }
|
|
|
| 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_ && can_auto_reload_page_) {
|
| + UMA_HISTOGRAM_CUSTOM_ENUMERATION("Net.AutoReload.ErrorAtStop",
|
| + committed_error_page_info_->error.reason,
|
| + net::GetAllErrorCodesForUma());
|
| + UMA_HISTOGRAM_COUNTS("Net.AutoReload.CountAtStop", auto_reload_count_);
|
| + }
|
| + if (committed_error_page_info_) {
|
| committed_error_page_info_->alternate_error_page_url = GURL();
|
| - if (pending_error_page_info_)
|
| + }
|
| + if (pending_error_page_info_) {
|
| pending_error_page_info_->alternate_error_page_url = GURL();
|
| + }
|
| delegate_->CancelFetchErrorPage();
|
| + auto_reload_timer_->Stop();
|
| +}
|
| +
|
| +void NetErrorHelperCore::OnStop() {
|
| + CancelPendingFetches();
|
| + auto_reload_count_ = 0;
|
| + can_auto_reload_page_ = false;
|
| }
|
|
|
| void NetErrorHelperCore::OnStartLoad(FrameType frame_type, PageType page_type) {
|
| @@ -142,7 +181,13 @@ 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();
|
| + // If a non-error load is starting, don't try to auto-reload while it is in
|
| + // flight.
|
| + can_auto_reload_page_ = false;
|
| + } else {
|
| + // If an error load is starting, the resulting error page is autoreloadable.
|
| + can_auto_reload_page_ = true;
|
| }
|
| }
|
|
|
| @@ -150,13 +195,32 @@ void NetErrorHelperCore::OnCommitLoad(FrameType frame_type) {
|
| if (frame_type != MAIN_FRAME)
|
| return;
|
|
|
| + if (committed_error_page_info_ && !pending_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", auto_reload_count_);
|
| + if (auto_reload_count_ == 1) {
|
| + UMA_HISTOGRAM_CUSTOM_ENUMERATION("Net.AutoReload.ErrorAtFirstSuccess",
|
| + reason,
|
| + net::GetAllErrorCodesForUma());
|
| + }
|
| + }
|
| +
|
| 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_) {
|
| + auto_reload_count_ = 0;
|
| + return;
|
| + }
|
| +
|
| committed_error_page_info_->is_finished_loading = true;
|
|
|
| if (committed_error_page_info_->alternate_error_page_url.is_valid()) {
|
| @@ -167,6 +231,10 @@ 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_)) {
|
| + can_auto_reload_page_ = true;
|
| + MaybeStartAutoReloadTimer();
|
| }
|
|
|
| if (!committed_error_page_info_->needs_dns_updates ||
|
| @@ -317,3 +385,72 @@ 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_ || !can_auto_reload_page_)
|
| + return false;
|
| +
|
| + DCHECK(IsReloadableError(*committed_error_page_info_));
|
| +
|
| + if (!online_)
|
| + return false;
|
| +
|
| + StartAutoReloadTimer();
|
| + return true;
|
| +}
|
| +
|
| +void NetErrorHelperCore::StartAutoReloadTimer() {
|
| + DCHECK(committed_error_page_info_);
|
| + DCHECK(can_auto_reload_page_);
|
| + base::TimeDelta delay = GetAutoReloadTime(auto_reload_count_);
|
| + 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();
|
| + auto_reload_count_ = 0;
|
| + }
|
| +
|
| + // If the network state changed to online, maybe start auto-reloading again.
|
| + if (online)
|
| + MaybeStartAutoReloadTimer();
|
| +}
|
| +
|
| +bool NetErrorHelperCore::ShouldSuppressErrorPage(FrameType frame_type,
|
| + const GURL& url) {
|
| + // Don't suppress child frame errors.
|
| + if (frame_type != MAIN_FRAME)
|
| + return false;
|
| +
|
| + // 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_ || !can_auto_reload_page_)
|
| + return false;
|
| +
|
| + GURL error_url = committed_error_page_info_->error.unreachableURL;
|
| + if (error_url != url)
|
| + return false;
|
| +
|
| + MaybeStartAutoReloadTimer();
|
| + return true;
|
| +}
|
|
|