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

Side by Side Diff: chrome/renderer/net/net_error_helper_core.cc

Issue 136203009: Support auto-reload on errors. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@lkgr
Patch Set: Add MockableOneShotTimer tests. Created 6 years, 9 months 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 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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/renderer/net/net_error_helper_core.h" 5 #include "chrome/renderer/net/net_error_helper_core.h"
6 6
7 #include <string> 7 #include <string>
8 8
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/location.h"
9 #include "base/metrics/histogram.h" 12 #include "base/metrics/histogram.h"
10 #include "chrome/common/localized_error.h" 13 #include "chrome/common/localized_error.h"
11 #include "net/base/escape.h" 14 #include "net/base/escape.h"
12 #include "net/base/net_errors.h" 15 #include "net/base/net_errors.h"
13 #include "third_party/WebKit/public/platform/WebString.h" 16 #include "third_party/WebKit/public/platform/WebString.h"
14 #include "third_party/WebKit/public/platform/WebURLError.h" 17 #include "third_party/WebKit/public/platform/WebURLError.h"
15 #include "url/gurl.h" 18 #include "url/gurl.h"
16 19
17 namespace { 20 namespace {
18 21
22 base::TimeDelta GetAutoReloadTime(size_t reload_count) {
23 LOG(ERROR) << "GetAutoReloadTime: " << reload_count;
mmenke 2014/03/11 20:07:54 nit: Remove logging
Elly Fong-Jones 2014/03/12 15:08:58 Done.
24 static const int kDelaysMs[] = {
25 0, 5000, 30000, 60000, 300000, 600000, 1800000
26 };
27 if (reload_count >= arraysize(kDelaysMs))
28 reload_count = arraysize(kDelaysMs) - 1;
29 return base::TimeDelta::FromMilliseconds(kDelaysMs[reload_count]);
30 }
31
19 // Returns whether |net_error| is a DNS-related error (and therefore whether 32 // Returns whether |net_error| is a DNS-related error (and therefore whether
20 // the tab helper should start a DNS probe after receiving it.) 33 // the tab helper should start a DNS probe after receiving it.)
21 bool IsDnsError(const blink::WebURLError& error) { 34 bool IsDnsError(const blink::WebURLError& error) {
22 return error.domain.utf8() == net::kErrorDomain && 35 return error.domain.utf8() == net::kErrorDomain &&
23 (error.reason == net::ERR_NAME_NOT_RESOLVED || 36 (error.reason == net::ERR_NAME_NOT_RESOLVED ||
24 error.reason == net::ERR_NAME_RESOLUTION_FAILED); 37 error.reason == net::ERR_NAME_RESOLUTION_FAILED);
25 } 38 }
26 39
27 // If an alternate error page should be retrieved remotely for a main frame load 40 // If an alternate error page should be retrieved remotely for a main frame load
28 // that failed with |error|, returns true and sets |error_page_url| to the URL 41 // that failed with |error|, returns true and sets |error_page_url| to the URL
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
109 // valid URL. Request will be issued when the error page finishes loading. 122 // valid URL. Request will be issued when the error page finishes loading.
110 // This is done on load complete to ensure that there are two complete loads 123 // This is done on load complete to ensure that there are two complete loads
111 // for tests to wait for. 124 // for tests to wait for.
112 GURL alternate_error_page_url; 125 GURL alternate_error_page_url;
113 126
114 // True if a page has completed loading, at which point it can receive 127 // True if a page has completed loading, at which point it can receive
115 // updates. 128 // updates.
116 bool is_finished_loading; 129 bool is_finished_loading;
117 }; 130 };
118 131
119 NetErrorHelperCore::NetErrorHelperCore(Delegate* delegate) 132 bool NetErrorHelperCore::IsReloadableError(
133 const NetErrorHelperCore::ErrorPageInfo& info) {
134 return info.error.domain.utf8() == net::kErrorDomain &&
135 info.error.reason != net::ERR_ABORTED &&
136 !info.was_failed_post;
137 }
138
139 NetErrorHelperCore::NetErrorHelperCore(Delegate* delegate,
140 scoped_ptr<MockableOneShotTimer> reload_timer)
120 : delegate_(delegate), 141 : delegate_(delegate),
121 last_probe_status_(chrome_common_net::DNS_PROBE_POSSIBLE) { 142 last_probe_status_(chrome_common_net::DNS_PROBE_POSSIBLE),
143 auto_reload_enabled_(false),
144 auto_reload_timer_(reload_timer.Pass()),
145 online_(true),
146 auto_reload_count_(0),
147 can_auto_reload_page_(false) {
122 } 148 }
123 149
124 NetErrorHelperCore::~NetErrorHelperCore() { 150 NetErrorHelperCore::~NetErrorHelperCore() {
125 } 151 }
126 152
153 void NetErrorHelperCore::CancelPendingFetches() {
154 // Cancel loading the alternate error page, and prevent any pending error page
155 // load from starting a new error page load. Swapping in the error page when
156 // it's finished loading could abort the navigation, otherwise.
157 if (committed_error_page_info_ && can_auto_reload_page_) {
158 UMA_HISTOGRAM_CUSTOM_ENUMERATION("Net.AutoReload.ErrorAtStop",
159 committed_error_page_info_->error.reason,
160 net::GetAllErrorCodesForUma());
161 UMA_HISTOGRAM_COUNTS("Net.AutoReload.CountAtStop", auto_reload_count_);
162 }
163 if (committed_error_page_info_) {
164 committed_error_page_info_->alternate_error_page_url = GURL();
165 }
166 if (pending_error_page_info_) {
167 pending_error_page_info_->alternate_error_page_url = GURL();
168 }
169 delegate_->CancelFetchErrorPage();
170 auto_reload_timer_->Stop();
171 }
172
127 void NetErrorHelperCore::OnStop() { 173 void NetErrorHelperCore::OnStop() {
128 // On stop, cancel loading the alternate error page, and prevent any pending 174 CancelPendingFetches();
129 // error page load from starting a new error page load. Swapping in the error 175 auto_reload_count_ = 0;
130 // page when it's finished loading could abort the navigation, otherwise. 176 can_auto_reload_page_ = false;
131 if (committed_error_page_info_)
132 committed_error_page_info_->alternate_error_page_url = GURL();
133 if (pending_error_page_info_)
134 pending_error_page_info_->alternate_error_page_url = GURL();
135 delegate_->CancelFetchErrorPage();
136 } 177 }
137 178
138 void NetErrorHelperCore::OnStartLoad(FrameType frame_type, PageType page_type) { 179 void NetErrorHelperCore::OnStartLoad(FrameType frame_type, PageType page_type) {
139 if (frame_type != MAIN_FRAME) 180 if (frame_type != MAIN_FRAME)
140 return; 181 return;
141 182
142 // If there's no pending error page information associated with the page load, 183 // If there's no pending error page information associated with the page load,
143 // or the new page is not an error page, then reset pending error page state. 184 // or the new page is not an error page, then reset pending error page state.
144 if (!pending_error_page_info_ || page_type != ERROR_PAGE) { 185 if (!pending_error_page_info_ || page_type != ERROR_PAGE) {
145 OnStop(); 186 CancelPendingFetches();
146 } 187 }
147 } 188 }
148 189
149 void NetErrorHelperCore::OnCommitLoad(FrameType frame_type) { 190 void NetErrorHelperCore::OnCommitLoad(FrameType frame_type) {
150 if (frame_type != MAIN_FRAME) 191 if (frame_type != MAIN_FRAME)
151 return; 192 return;
152 193
194 if (committed_error_page_info_ && !pending_error_page_info_ &&
195 can_auto_reload_page_) {
196 int reason = committed_error_page_info_->error.reason;
197 UMA_HISTOGRAM_CUSTOM_ENUMERATION("Net.AutoReload.ErrorAtSuccess",
198 reason,
199 net::GetAllErrorCodesForUma());
200 UMA_HISTOGRAM_COUNTS("Net.AutoReload.CountAtSuccess", auto_reload_count_);
201 if (auto_reload_count_ == 1) {
202 UMA_HISTOGRAM_CUSTOM_ENUMERATION("Net.AutoReload.ErrorAtFirstSuccess",
203 reason,
204 net::GetAllErrorCodesForUma());
205 }
206 }
207
153 committed_error_page_info_.reset(pending_error_page_info_.release()); 208 committed_error_page_info_.reset(pending_error_page_info_.release());
154 } 209 }
155 210
156 void NetErrorHelperCore::OnFinishLoad(FrameType frame_type) { 211 void NetErrorHelperCore::OnFinishLoad(FrameType frame_type) {
157 if (frame_type != MAIN_FRAME || !committed_error_page_info_) 212 if (frame_type != MAIN_FRAME)
158 return; 213 return;
159 214
215 if (!committed_error_page_info_) {
216 auto_reload_count_ = 0;
217 return;
218 }
219
160 committed_error_page_info_->is_finished_loading = true; 220 committed_error_page_info_->is_finished_loading = true;
161 221
162 if (committed_error_page_info_->alternate_error_page_url.is_valid()) { 222 if (committed_error_page_info_->alternate_error_page_url.is_valid()) {
163 // If there is another pending error page load, 223 // If there is another pending error page load,
164 // |replace_with_alternate_error_page| should have been set to false. 224 // |replace_with_alternate_error_page| should have been set to false.
165 DCHECK(!pending_error_page_info_); 225 DCHECK(!pending_error_page_info_);
166 DCHECK(!committed_error_page_info_->needs_dns_updates); 226 DCHECK(!committed_error_page_info_->needs_dns_updates);
167 GURL error_page_url; 227 GURL error_page_url;
168 delegate_->FetchErrorPage( 228 delegate_->FetchErrorPage(
169 committed_error_page_info_->alternate_error_page_url); 229 committed_error_page_info_->alternate_error_page_url);
230 } else if (auto_reload_enabled_ &&
231 IsReloadableError(*committed_error_page_info_)) {
232 can_auto_reload_page_ = true;
233 MaybeStartAutoReloadTimer();
170 } 234 }
171 235
172 if (!committed_error_page_info_->needs_dns_updates || 236 if (!committed_error_page_info_->needs_dns_updates ||
173 last_probe_status_ == chrome_common_net::DNS_PROBE_POSSIBLE) { 237 last_probe_status_ == chrome_common_net::DNS_PROBE_POSSIBLE) {
174 return; 238 return;
175 } 239 }
176 DVLOG(1) << "Error page finished loading; sending saved status."; 240 DVLOG(1) << "Error page finished loading; sending saved status.";
177 UpdateErrorPage(); 241 UpdateErrorPage();
178 } 242 }
179 243
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
310 374
311 blink::WebURLError updated_error; 375 blink::WebURLError updated_error;
312 updated_error.domain = blink::WebString::fromUTF8( 376 updated_error.domain = blink::WebString::fromUTF8(
313 chrome_common_net::kDnsProbeErrorDomain); 377 chrome_common_net::kDnsProbeErrorDomain);
314 updated_error.reason = last_probe_status_; 378 updated_error.reason = last_probe_status_;
315 updated_error.unreachableURL = error.unreachableURL; 379 updated_error.unreachableURL = error.unreachableURL;
316 updated_error.staleCopyInCache = error.staleCopyInCache; 380 updated_error.staleCopyInCache = error.staleCopyInCache;
317 381
318 return updated_error; 382 return updated_error;
319 } 383 }
384
385 void NetErrorHelperCore::Reload() {
386 if (!committed_error_page_info_) {
387 return;
388 }
389 delegate_->ReloadPage();
390 }
391
392 bool NetErrorHelperCore::MaybeStartAutoReloadTimer() {
393 if (!committed_error_page_info_ || !can_auto_reload_page_)
394 return false;
395
396 DCHECK(IsReloadableError(*committed_error_page_info_));
397
398 if (!online_)
399 return false;
400
401 StartAutoReloadTimer();
mmenke 2014/03/11 20:07:54 If there's an uncommitted load, we should not do t
Elly Fong-Jones 2014/03/12 15:08:58 Hm. I've made OnStartLoad update can_auto_reload_p
402 return true;
403 }
404
405 void NetErrorHelperCore::StartAutoReloadTimer() {
406 DCHECK(committed_error_page_info_);
407 DCHECK(can_auto_reload_page_);
408 base::TimeDelta delay =
409 GetAutoReloadTime(auto_reload_count_);
mmenke 2014/03/11 20:07:54 nit: May it on one line.
Elly Fong-Jones 2014/03/12 15:08:58 Done.
410 auto_reload_count_++;
411 auto_reload_timer_->Stop();
412 auto_reload_timer_->Start(FROM_HERE, delay,
413 base::Bind(&NetErrorHelperCore::Reload,
414 base::Unretained(this)));
415 }
416
417 void NetErrorHelperCore::NetworkStateChanged(bool online) {
418 online_ = online;
419 if (auto_reload_timer_->IsRunning()) {
420 DCHECK(committed_error_page_info_);
421 // If there's an existing timer running, stop it and reset the retry count.
422 auto_reload_timer_->Stop();
423 auto_reload_count_ = 0;
424 }
425
426 // If the network state changed to online, maybe start auto-reloading again.
427 if (online)
428 MaybeStartAutoReloadTimer();
429 }
430
431 bool NetErrorHelperCore::ShouldSuppressErrorPage(FrameType frame_type,
432 const GURL& url) {
433 // Don't suppress child frame errors.
434 if (frame_type != MAIN_FRAME)
435 return false;
436
437 // If |auto_reload_timer_| is still running, this error page isn't from an
438 // auto reload.
439 if (auto_reload_timer_->IsRunning())
440 return false;
441
442 // If there's no committed error page, this error page wasn't from an auto
443 // reload.
444 if (!committed_error_page_info_ || !can_auto_reload_page_)
445 return false;
446
447 GURL error_url = committed_error_page_info_->error.unreachableURL;
448 if (error_url != url)
449 return false;
450
451 MaybeStartAutoReloadTimer();
452 return true;
453 }
454
455 int NetErrorHelperCore::GetAutoReloadCount() const {
456 return auto_reload_count_;
457 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698