Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 static const int kDelaysMs[] = { | |
| 24 0, 5000, 30000, 60000, 300000, 600000, 1800000 | |
| 25 }; | |
| 26 if (reload_count >= arraysize(kDelaysMs)) | |
| 27 reload_count = arraysize(kDelaysMs) - 1; | |
| 28 return base::TimeDelta::FromMilliseconds(kDelaysMs[reload_count]); | |
| 29 } | |
| 30 | |
| 19 // Returns whether |net_error| is a DNS-related error (and therefore whether | 31 // Returns whether |net_error| is a DNS-related error (and therefore whether |
| 20 // the tab helper should start a DNS probe after receiving it.) | 32 // the tab helper should start a DNS probe after receiving it.) |
| 21 bool IsDnsError(const blink::WebURLError& error) { | 33 bool IsDnsError(const blink::WebURLError& error) { |
| 22 return error.domain.utf8() == net::kErrorDomain && | 34 return error.domain.utf8() == net::kErrorDomain && |
| 23 (error.reason == net::ERR_NAME_NOT_RESOLVED || | 35 (error.reason == net::ERR_NAME_NOT_RESOLVED || |
| 24 error.reason == net::ERR_NAME_RESOLUTION_FAILED); | 36 error.reason == net::ERR_NAME_RESOLUTION_FAILED); |
| 25 } | 37 } |
| 26 | 38 |
| 39 bool IsReloadableError(const blink::WebURLError& error) { | |
| 40 return error.domain.utf8() == net::kErrorDomain && | |
| 41 error.reason != net::ERR_ABORTED; | |
| 42 } | |
| 43 | |
| 27 // If an alternate error page should be retrieved remotely for a main frame load | 44 // 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 | 45 // that failed with |error|, returns true and sets |error_page_url| to the URL |
| 29 // of the remote error page. | 46 // of the remote error page. |
| 30 bool GetErrorPageURL(const blink::WebURLError& error, | 47 bool GetErrorPageURL(const blink::WebURLError& error, |
| 31 const GURL& alt_error_page_url, | 48 const GURL& alt_error_page_url, |
| 32 GURL* error_page_url) { | 49 GURL* error_page_url) { |
| 33 if (!alt_error_page_url.is_valid()) | 50 if (!alt_error_page_url.is_valid()) |
| 34 return false; | 51 return false; |
| 35 | 52 |
| 36 // Parameter to send to the error page indicating the error type. | 53 // Parameter to send to the error page indicating the error type. |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 107 | 124 |
| 108 // URL of an alternate error page to repace this error page with, if it's a | 125 // URL of an alternate error page to repace this error page with, if it's a |
| 109 // valid URL. Request will be issued when the error page finishes loading. | 126 // 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 | 127 // This is done on load complete to ensure that there are two complete loads |
| 111 // for tests to wait for. | 128 // for tests to wait for. |
| 112 GURL alternate_error_page_url; | 129 GURL alternate_error_page_url; |
| 113 | 130 |
| 114 // True if a page has completed loading, at which point it can receive | 131 // True if a page has completed loading, at which point it can receive |
| 115 // updates. | 132 // updates. |
| 116 bool is_finished_loading; | 133 bool is_finished_loading; |
| 134 | |
| 135 int auto_reload_count; | |
| 136 bool can_auto_reload_page; | |
| 117 }; | 137 }; |
| 118 | 138 |
| 119 NetErrorHelperCore::NetErrorHelperCore(Delegate* delegate) | 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) { | |
| 122 } | 146 } |
| 123 | 147 |
| 124 NetErrorHelperCore::~NetErrorHelperCore() { | 148 NetErrorHelperCore::~NetErrorHelperCore() { |
| 125 } | 149 } |
| 126 | 150 |
| 127 void NetErrorHelperCore::OnStop() { | 151 void NetErrorHelperCore::CancelPendingFetches() { |
| 128 // On stop, cancel loading the alternate error page, and prevent any pending | 152 // Cancel loading the alternate error page, and prevent any pending error page |
| 129 // error page load from starting a new error page load. Swapping in the error | 153 // load from starting a new error page load. Swapping in the error page when |
| 130 // page when it's finished loading could abort the navigation, otherwise. | 154 // it's finished loading could abort the navigation, otherwise. |
| 131 if (committed_error_page_info_) | 155 if (committed_error_page_info_) { |
| 156 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.
| |
| 132 committed_error_page_info_->alternate_error_page_url = GURL(); | 157 committed_error_page_info_->alternate_error_page_url = GURL(); |
| 158 } | |
| 133 if (pending_error_page_info_) | 159 if (pending_error_page_info_) |
| 134 pending_error_page_info_->alternate_error_page_url = GURL(); | 160 pending_error_page_info_->alternate_error_page_url = GURL(); |
| 135 delegate_->CancelFetchErrorPage(); | 161 delegate_->CancelFetchErrorPage(); |
| 162 auto_reload_timer_->Stop(); | |
| 163 } | |
| 164 | |
| 165 void NetErrorHelperCore::OnStop() { | |
| 166 CancelPendingFetches(); | |
| 167 if (committed_error_page_info_ && | |
| 168 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.
| |
| 169 UMA_HISTOGRAM_CUSTOM_ENUMERATION("Net.AutoReload.ErrorAtStop", | |
| 170 committed_error_page_info_->error.reason, | |
| 171 net::GetAllErrorCodesForUma()); | |
| 172 UMA_HISTOGRAM_COUNTS("Net.AutoReload.CountAtStop", | |
| 173 committed_error_page_info_->auto_reload_count); | |
| 174 } | |
| 175 committed_error_page_info_->auto_reload_count = 0; | |
| 176 committed_error_page_info_->can_auto_reload_page = false; | |
| 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 committed_error_page_info_->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", | |
| 201 committed_error_page_info_->auto_reload_count); | |
| 202 if (committed_error_page_info_->auto_reload_count == 1) | |
| 203 UMA_HISTOGRAM_CUSTOM_ENUMERATION("Net.AutoReload.ErrorAtFirstSuccess", | |
| 204 reason, | |
| 205 net::GetAllErrorCodesForUma()); | |
|
mmenke
2014/03/07 15:46:17
nit: +braces
Elly Fong-Jones
2014/03/10 19:46:51
Done.
| |
| 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) |
| 213 return; | |
| 214 | |
| 215 if (!committed_error_page_info_) | |
| 158 return; | 216 return; |
| 159 | 217 |
| 160 committed_error_page_info_->is_finished_loading = true; | 218 committed_error_page_info_->is_finished_loading = true; |
| 161 | 219 |
| 162 if (committed_error_page_info_->alternate_error_page_url.is_valid()) { | 220 if (committed_error_page_info_->alternate_error_page_url.is_valid()) { |
| 163 // If there is another pending error page load, | 221 // If there is another pending error page load, |
| 164 // |replace_with_alternate_error_page| should have been set to false. | 222 // |replace_with_alternate_error_page| should have been set to false. |
| 165 DCHECK(!pending_error_page_info_); | 223 DCHECK(!pending_error_page_info_); |
| 166 DCHECK(!committed_error_page_info_->needs_dns_updates); | 224 DCHECK(!committed_error_page_info_->needs_dns_updates); |
| 167 GURL error_page_url; | 225 GURL error_page_url; |
| 168 delegate_->FetchErrorPage( | 226 delegate_->FetchErrorPage( |
| 169 committed_error_page_info_->alternate_error_page_url); | 227 committed_error_page_info_->alternate_error_page_url); |
| 228 } else if (auto_reload_enabled_ && | |
| 229 IsReloadableError(committed_error_page_info_->error) && | |
| 230 !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.
| |
| 231 committed_error_page_info_->can_auto_reload_page = true; | |
| 232 MaybeStartAutoReloadTimer(); | |
| 170 } | 233 } |
| 171 | 234 |
| 172 if (!committed_error_page_info_->needs_dns_updates || | 235 if (!committed_error_page_info_->needs_dns_updates || |
| 173 last_probe_status_ == chrome_common_net::DNS_PROBE_POSSIBLE) { | 236 last_probe_status_ == chrome_common_net::DNS_PROBE_POSSIBLE) { |
| 174 return; | 237 return; |
| 175 } | 238 } |
| 176 DVLOG(1) << "Error page finished loading; sending saved status."; | 239 DVLOG(1) << "Error page finished loading; sending saved status."; |
| 177 UpdateErrorPage(); | 240 UpdateErrorPage(); |
| 178 } | 241 } |
| 179 | 242 |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 310 | 373 |
| 311 blink::WebURLError updated_error; | 374 blink::WebURLError updated_error; |
| 312 updated_error.domain = blink::WebString::fromUTF8( | 375 updated_error.domain = blink::WebString::fromUTF8( |
| 313 chrome_common_net::kDnsProbeErrorDomain); | 376 chrome_common_net::kDnsProbeErrorDomain); |
| 314 updated_error.reason = last_probe_status_; | 377 updated_error.reason = last_probe_status_; |
| 315 updated_error.unreachableURL = error.unreachableURL; | 378 updated_error.unreachableURL = error.unreachableURL; |
| 316 updated_error.staleCopyInCache = error.staleCopyInCache; | 379 updated_error.staleCopyInCache = error.staleCopyInCache; |
| 317 | 380 |
| 318 return updated_error; | 381 return updated_error; |
| 319 } | 382 } |
| 383 | |
| 384 void NetErrorHelperCore::Reload() { | |
| 385 if (!committed_error_page_info_) { | |
| 386 return; | |
| 387 } | |
| 388 delegate_->ReloadPage(); | |
| 389 } | |
| 390 | |
| 391 bool NetErrorHelperCore::MaybeStartAutoReloadTimer() { | |
| 392 if (!committed_error_page_info_) | |
| 393 return false; | |
| 394 | |
| 395 if (!committed_error_page_info_->can_auto_reload_page) | |
| 396 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.
| |
| 397 | |
| 398 DCHECK(IsReloadableError(committed_error_page_info_->error)); | |
| 399 DCHECK(!committed_error_page_info_->was_failed_post); | |
| 400 | |
| 401 if (!online_) | |
| 402 return false; | |
| 403 | |
| 404 StartAutoReloadTimer(); | |
| 405 return true; | |
| 406 } | |
| 407 | |
| 408 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.
| |
| 409 base::TimeDelta delay = | |
| 410 GetAutoReloadTime(committed_error_page_info_->auto_reload_count); | |
| 411 committed_error_page_info_->auto_reload_count++; | |
| 412 auto_reload_timer_->Stop(); | |
| 413 auto_reload_timer_->Start(FROM_HERE, delay, | |
| 414 base::Bind(&NetErrorHelperCore::Reload, | |
| 415 base::Unretained(this))); | |
| 416 } | |
| 417 | |
| 418 void NetErrorHelperCore::NetworkStateChanged(bool online) { | |
| 419 online_ = online; | |
| 420 if (auto_reload_timer_->IsRunning()) { | |
| 421 DCHECK(committed_error_page_info_); | |
| 422 // If there's an existing timer running, stop it and reset the retry count. | |
| 423 auto_reload_timer_->Stop(); | |
| 424 committed_error_page_info_->auto_reload_count = 0; | |
| 425 } | |
| 426 | |
| 427 // If the network state changed to online, maybe start auto-reloading again. | |
| 428 if (online) | |
| 429 MaybeStartAutoReloadTimer(); | |
| 430 } | |
| 431 | |
| 432 bool NetErrorHelperCore::ShouldSuppressErrorPage(const GURL& url) { | |
| 433 // If |auto_reload_timer_| is still running, this error page isn't from an | |
| 434 // auto reload. | |
| 435 if (auto_reload_timer_->IsRunning()) | |
| 436 return false; | |
| 437 | |
| 438 // If there's no committed error page, this error page wasn't from an auto | |
| 439 // reload. | |
| 440 if (!committed_error_page_info_) | |
| 441 return false; | |
| 442 | |
| 443 // Don't suppress errors if not auto-reloading. | |
| 444 if (!committed_error_page_info_->can_auto_reload_page) | |
| 445 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.
| |
| 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 if (!committed_error_page_info_) | |
| 457 return -1; | |
| 458 return committed_error_page_info_->auto_reload_count; | |
| 459 } | |
| OLD | NEW |