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 b169d4964bceadfb8e287c396afcda0c272d7fa8..815ecfe06892fd0f9e393cdac1ba25d03d9efae7 100644 |
--- a/chrome/renderer/net/net_error_helper_core.cc |
+++ b/chrome/renderer/net/net_error_helper_core.cc |
@@ -22,6 +22,7 @@ |
#include "base/strings/string_util.h" |
#include "base/values.h" |
#include "chrome/common/localized_error.h" |
+#include "content/public/common/url_constants.h" |
#include "grit/generated_resources.h" |
#include "net/base/escape.h" |
#include "net/base/net_errors.h" |
@@ -340,6 +341,29 @@ scoped_ptr<LocalizedError::ErrorPageParams> CreateErrorPageParams( |
return params.Pass(); |
} |
+void ReportAutoReloadSuccess(const blink::WebURLError& error, size_t count) { |
+ if (error.domain.utf8() != net::kErrorDomain) |
+ return; |
+ UMA_HISTOGRAM_CUSTOM_ENUMERATION("Net.AutoReload.ErrorAtSuccess", |
+ -error.reason, |
+ net::GetAllErrorCodesForUma()); |
+ UMA_HISTOGRAM_COUNTS("Net.AutoReload.CountAtSuccess", count); |
+ if (count == 1) { |
+ UMA_HISTOGRAM_CUSTOM_ENUMERATION("Net.AutoReload.ErrorAtFirstSuccess", |
+ -error.reason, |
+ net::GetAllErrorCodesForUma()); |
+ } |
+} |
+ |
+void ReportAutoReloadFailure(const blink::WebURLError& error, size_t count) { |
+ if (error.domain.utf8() != net::kErrorDomain) |
+ return; |
+ UMA_HISTOGRAM_CUSTOM_ENUMERATION("Net.AutoReload.ErrorAtStop", |
+ -error.reason, |
+ net::GetAllErrorCodesForUma()); |
+ UMA_HISTOGRAM_COUNTS("Net.AutoReload.CountAtStop", count); |
+} |
+ |
} // namespace |
struct NetErrorHelperCore::ErrorPageInfo { |
@@ -350,7 +374,8 @@ struct NetErrorHelperCore::ErrorPageInfo { |
needs_load_navigation_corrections(false), |
reload_button_in_page(false), |
load_stale_button_in_page(false), |
- is_finished_loading(false) { |
+ is_finished_loading(false), |
+ auto_reload_triggered(false) { |
} |
// Information about the failed page load. |
@@ -386,6 +411,10 @@ struct NetErrorHelperCore::ErrorPageInfo { |
// True if a page has completed loading, at which point it can receive |
// updates. |
bool is_finished_loading; |
+ |
+ // True if the auto-reload timer has fired and a reload is or has been in |
+ // flight. |
+ bool auto_reload_triggered; |
}; |
NetErrorHelperCore::NavigationCorrectionParams::NavigationCorrectionParams() { |
@@ -406,19 +435,19 @@ NetErrorHelperCore::NetErrorHelperCore(Delegate* delegate) |
last_probe_status_(chrome_common_net::DNS_PROBE_POSSIBLE), |
auto_reload_enabled_(false), |
auto_reload_timer_(new base::Timer(false, false)), |
+ auto_reload_paused_(false), |
+ uncommitted_load_started_(false), |
// TODO(ellyjones): Make online_ accurate at object creation. |
online_(true), |
auto_reload_count_(0), |
- can_auto_reload_page_(false), |
navigation_from_button_(NO_BUTTON) { |
} |
NetErrorHelperCore::~NetErrorHelperCore() { |
- 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_->auto_reload_triggered) { |
+ ReportAutoReloadFailure(committed_error_page_info_->error, |
+ auto_reload_count_); |
} |
} |
@@ -426,23 +455,23 @@ 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_->needs_load_navigation_corrections = false; |
if (pending_error_page_info_) |
pending_error_page_info_->needs_load_navigation_corrections = false; |
delegate_->CancelFetchNavigationCorrections(); |
auto_reload_timer_->Stop(); |
- can_auto_reload_page_ = false; |
+ auto_reload_paused_ = false; |
} |
void NetErrorHelperCore::OnStop() { |
+ if (committed_error_page_info_ && |
+ committed_error_page_info_->auto_reload_triggered) { |
+ ReportAutoReloadFailure(committed_error_page_info_->error, |
+ auto_reload_count_); |
+ } |
CancelPendingFetches(); |
+ uncommitted_load_started_ = false; |
auto_reload_count_ = 0; |
} |
@@ -450,20 +479,23 @@ void NetErrorHelperCore::OnStartLoad(FrameType frame_type, PageType page_type) { |
if (frame_type != MAIN_FRAME) |
return; |
+ uncommitted_load_started_ = true; |
+ |
// 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) { |
+ if (!pending_error_page_info_ || page_type != ERROR_PAGE) |
CancelPendingFetches(); |
- } else if (auto_reload_enabled_) { |
- // If an error load is starting, the resulting error page is autoreloadable. |
- can_auto_reload_page_ = IsReloadableError(*pending_error_page_info_); |
- } |
} |
-void NetErrorHelperCore::OnCommitLoad(FrameType frame_type) { |
+void NetErrorHelperCore::OnCommitLoad(FrameType frame_type, const GURL& url) { |
if (frame_type != MAIN_FRAME) |
return; |
+ // uncommitted_load_started_ could already be false, since RenderFrameImpl |
+ // calls OnCommitLoad once for each in-page navigation (like a fragment |
+ // change) with no corresponding OnStartLoad. |
+ uncommitted_load_started_ = false; |
+ |
// Track if an error occurred due to a page button press. |
// This isn't perfect; if (for instance), the server is slow responding |
// to a request generated from the page reload button, and the user hits |
@@ -483,17 +515,13 @@ void NetErrorHelperCore::OnCommitLoad(FrameType frame_type) { |
navigation_from_button_ = NO_BUTTON; |
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_->auto_reload_triggered) { |
+ const blink::WebURLError& error = committed_error_page_info_->error; |
+ const GURL& error_url = error.unreachableURL; |
+ if (url == error_url) |
+ ReportAutoReloadSuccess(error, auto_reload_count_); |
+ else if (url != GURL(content::kUnreachableWebDataURL)) |
+ ReportAutoReloadFailure(error, auto_reload_count_); |
} |
committed_error_page_info_.reset(pending_error_page_info_.release()); |
@@ -734,23 +762,27 @@ void NetErrorHelperCore::Reload() { |
bool NetErrorHelperCore::MaybeStartAutoReloadTimer() { |
if (!committed_error_page_info_ || |
!committed_error_page_info_->is_finished_loading || |
- !can_auto_reload_page_ || |
- pending_error_page_info_) { |
+ pending_error_page_info_ || |
+ uncommitted_load_started_) { |
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_); |
+ DCHECK(IsReloadableError(*committed_error_page_info_)); |
+ |
+ committed_error_page_info_->auto_reload_triggered = true; |
+ |
+ if (!online_) { |
+ auto_reload_paused_ = true; |
+ return; |
+ } |
+ |
+ auto_reload_paused_ = false; |
base::TimeDelta delay = GetAutoReloadTime(auto_reload_count_); |
auto_reload_timer_->Stop(); |
auto_reload_timer_->Start(FROM_HERE, delay, |
@@ -764,17 +796,23 @@ void NetErrorHelperCore::AutoReloadTimerFired() { |
} |
void NetErrorHelperCore::NetworkStateChanged(bool online) { |
+ bool was_online = 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 (!was_online && online) { |
+ // Transitioning offline -> online |
+ if (auto_reload_paused_) |
+ MaybeStartAutoReloadTimer(); |
+ } else if (was_online && !online) { |
+ // Transitioning online -> offline |
+ if (auto_reload_timer_->IsRunning()) { |
+ DCHECK(committed_error_page_info_); |
+ DCHECK(!auto_reload_paused_); |
+ DCHECK(committed_error_page_info_->auto_reload_triggered); |
+ auto_reload_timer_->Stop(); |
+ auto_reload_count_ = 0; |
+ auto_reload_paused_ = true; |
+ } |
} |
- |
- // If the network state changed to online, maybe start auto-reloading again. |
- if (online) |
- MaybeStartAutoReloadTimer(); |
} |
bool NetErrorHelperCore::ShouldSuppressErrorPage(FrameType frame_type, |
@@ -783,21 +821,36 @@ bool NetErrorHelperCore::ShouldSuppressErrorPage(FrameType frame_type, |
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()) |
+ if (!auto_reload_enabled_) |
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_) |
+ if (!committed_error_page_info_) |
+ return false; |
+ |
+ // If the error page wasn't reloadable, display it. |
+ if (!IsReloadableError(*committed_error_page_info_)) |
return false; |
+ // If |auto_reload_timer_| is still running or is paused, this error page |
+ // isn't from an auto reload. |
+ if (auto_reload_timer_->IsRunning() || auto_reload_paused_) |
+ return false; |
+ |
+ // If the error page was reloadable, and the timer isn't running or paused, an |
+ // auto-reload has already been triggered. |
+ DCHECK(committed_error_page_info_->auto_reload_triggered); |
+ |
GURL error_url = committed_error_page_info_->error.unreachableURL; |
// TODO(ellyjones): also plumb the error code down to CCRC and check that |
if (error_url != url) |
return false; |
+ // Suppressed an error-page load; the previous uncommitted load was the error |
+ // page load starting, so forget about it. |
+ uncommitted_load_started_ = false; |
+ |
// The first iteration of the timer is started by OnFinishLoad calling |
// MaybeStartAutoReloadTimer, but since error pages for subsequent loads are |
// suppressed in this function, subsequent iterations of the timer have to be |