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" | |
| 9 #include "base/i18n/rtl.h" | 11 #include "base/i18n/rtl.h" |
| 10 #include "base/json/json_reader.h" | 12 #include "base/json/json_reader.h" |
| 11 #include "base/json/json_writer.h" | 13 #include "base/json/json_writer.h" |
| 14 #include "base/location.h" | |
| 12 #include "base/metrics/histogram.h" | 15 #include "base/metrics/histogram.h" |
| 13 #include "base/strings/string16.h" | 16 #include "base/strings/string16.h" |
| 14 #include "base/values.h" | 17 #include "base/values.h" |
| 15 #include "chrome/common/localized_error.h" | 18 #include "chrome/common/localized_error.h" |
| 16 #include "grit/generated_resources.h" | 19 #include "grit/generated_resources.h" |
| 17 #include "net/base/escape.h" | 20 #include "net/base/escape.h" |
| 18 #include "net/base/net_errors.h" | 21 #include "net/base/net_errors.h" |
| 19 #include "net/base/net_util.h" | 22 #include "net/base/net_util.h" |
| 20 #include "third_party/WebKit/public/platform/WebString.h" | 23 #include "third_party/WebKit/public/platform/WebString.h" |
| 21 #include "third_party/WebKit/public/platform/WebURLError.h" | 24 #include "third_party/WebKit/public/platform/WebURLError.h" |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 38 {IDS_ERRORPAGES_SUGGESTION_ALTERNATE_URL, "sitemap"}, | 41 {IDS_ERRORPAGES_SUGGESTION_ALTERNATE_URL, "sitemap"}, |
| 39 {IDS_ERRORPAGES_SUGGESTION_ALTERNATE_URL, "pathParentFolder"}, | 42 {IDS_ERRORPAGES_SUGGESTION_ALTERNATE_URL, "pathParentFolder"}, |
| 40 // "siteSearchQuery" is not yet supported. | 43 // "siteSearchQuery" is not yet supported. |
| 41 // TODO(mmenke): Figure out what format "siteSearchQuery" uses for its | 44 // TODO(mmenke): Figure out what format "siteSearchQuery" uses for its |
| 42 // suggestions. | 45 // suggestions. |
| 43 // "webSearchQuery" has special handling. | 46 // "webSearchQuery" has special handling. |
| 44 {IDS_ERRORPAGES_SUGGESTION_ALTERNATE_URL, "contentOverlap"}, | 47 {IDS_ERRORPAGES_SUGGESTION_ALTERNATE_URL, "contentOverlap"}, |
| 45 {IDS_ERRORPAGES_SUGGESTION_CORRECTED_URL, "emphasizedUrlCorrection"}, | 48 {IDS_ERRORPAGES_SUGGESTION_CORRECTED_URL, "emphasizedUrlCorrection"}, |
| 46 }; | 49 }; |
| 47 | 50 |
| 51 base::TimeDelta GetAutoReloadTime(size_t reload_count) { | |
| 52 static const int kDelaysMs[] = { | |
| 53 0, 5000, 30000, 60000, 300000, 600000, 1800000 | |
| 54 }; | |
| 55 if (reload_count >= arraysize(kDelaysMs)) | |
| 56 reload_count = arraysize(kDelaysMs) - 1; | |
| 57 return base::TimeDelta::FromMilliseconds(kDelaysMs[reload_count]); | |
| 58 } | |
| 59 | |
| 48 // Returns whether |net_error| is a DNS-related error (and therefore whether | 60 // Returns whether |net_error| is a DNS-related error (and therefore whether |
| 49 // the tab helper should start a DNS probe after receiving it.) | 61 // the tab helper should start a DNS probe after receiving it.) |
| 50 bool IsDnsError(const blink::WebURLError& error) { | 62 bool IsDnsError(const blink::WebURLError& error) { |
| 51 return error.domain.utf8() == net::kErrorDomain && | 63 return error.domain.utf8() == net::kErrorDomain && |
| 52 (error.reason == net::ERR_NAME_NOT_RESOLVED || | 64 (error.reason == net::ERR_NAME_NOT_RESOLVED || |
| 53 error.reason == net::ERR_NAME_RESOLUTION_FAILED); | 65 error.reason == net::ERR_NAME_RESOLUTION_FAILED); |
| 54 } | 66 } |
| 55 | 67 |
| 56 GURL SanitizeURL(const GURL& url) { | 68 GURL SanitizeURL(const GURL& url) { |
| 57 GURL::Replacements remove_params; | 69 GURL::Replacements remove_params; |
| (...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 264 // Request body to use when requesting corrections from a web service. | 276 // Request body to use when requesting corrections from a web service. |
| 265 // TODO(mmenke): Investigate loading the error page at the same time as | 277 // TODO(mmenke): Investigate loading the error page at the same time as |
| 266 // the blank page is loading, to get rid of these. | 278 // the blank page is loading, to get rid of these. |
| 267 std::string navigation_correction_request_body; | 279 std::string navigation_correction_request_body; |
| 268 | 280 |
| 269 // True if a page has completed loading, at which point it can receive | 281 // True if a page has completed loading, at which point it can receive |
| 270 // updates. | 282 // updates. |
| 271 bool is_finished_loading; | 283 bool is_finished_loading; |
| 272 }; | 284 }; |
| 273 | 285 |
| 286 bool NetErrorHelperCore::IsReloadableError( | |
| 287 const NetErrorHelperCore::ErrorPageInfo& info) { | |
| 288 return info.error.domain.utf8() == net::kErrorDomain && | |
| 289 info.error.reason != net::ERR_ABORTED && | |
| 290 !info.was_failed_post; | |
| 291 } | |
| 292 | |
| 274 NetErrorHelperCore::NetErrorHelperCore(Delegate* delegate) | 293 NetErrorHelperCore::NetErrorHelperCore(Delegate* delegate) |
| 275 : delegate_(delegate), | 294 : delegate_(delegate), |
| 276 last_probe_status_(chrome_common_net::DNS_PROBE_POSSIBLE) { | 295 last_probe_status_(chrome_common_net::DNS_PROBE_POSSIBLE), |
| 296 auto_reload_enabled_(false), | |
| 297 auto_reload_timer_(new MockableOneShotTimer()), | |
| 298 // TODO(ellyjones): Make online_ accurate at object creation. | |
| 299 online_(true), | |
| 300 auto_reload_count_(0), | |
| 301 can_auto_reload_page_(false) { | |
| 277 } | 302 } |
| 278 | 303 |
| 279 NetErrorHelperCore::~NetErrorHelperCore() { | 304 NetErrorHelperCore::~NetErrorHelperCore() { |
| 305 if (committed_error_page_info_ && can_auto_reload_page_) { | |
| 306 UMA_HISTOGRAM_CUSTOM_ENUMERATION("Net.AutoReload.ErrorAtStop", | |
| 307 -committed_error_page_info_->error.reason, | |
| 308 net::GetAllErrorCodesForUma()); | |
| 309 UMA_HISTOGRAM_COUNTS("Net.AutoReload.CountAtStop", auto_reload_count_); | |
| 310 } | |
| 280 } | 311 } |
| 281 | 312 |
| 282 void NetErrorHelperCore::OnStop() { | 313 void NetErrorHelperCore::CancelPendingFetches() { |
| 283 // On stop, cancel loading navigation corrections, and prevent any | 314 // Cancel loading the alternate error page, and prevent any pending error page |
| 284 // pending error page load from starting to load corrections. Swapping in an | 315 // load from starting a new error page load. Swapping in the error page when |
| 285 // error page once corrections are received could interrupt a navigation, | 316 // it's finished loading could abort the navigation, otherwise. |
| 286 // otherwise. | 317 if (committed_error_page_info_ && can_auto_reload_page_) { |
| 318 UMA_HISTOGRAM_CUSTOM_ENUMERATION("Net.AutoReload.ErrorAtStop", | |
| 319 -committed_error_page_info_->error.reason, | |
| 320 net::GetAllErrorCodesForUma()); | |
| 321 UMA_HISTOGRAM_COUNTS("Net.AutoReload.CountAtStop", auto_reload_count_); | |
| 322 } | |
| 287 if (committed_error_page_info_) { | 323 if (committed_error_page_info_) { |
| 288 committed_error_page_info_->navigation_correction_url = GURL(); | 324 committed_error_page_info_->navigation_correction_url = GURL(); |
| 289 committed_error_page_info_->navigation_correction_request_body.clear(); | 325 committed_error_page_info_->navigation_correction_request_body.clear(); |
| 290 } | 326 } |
| 291 if (pending_error_page_info_) { | 327 if (pending_error_page_info_) { |
| 292 pending_error_page_info_->navigation_correction_url = GURL(); | 328 pending_error_page_info_->navigation_correction_url = GURL(); |
| 293 pending_error_page_info_->navigation_correction_request_body.clear(); | 329 pending_error_page_info_->navigation_correction_request_body.clear(); |
| 294 } | 330 } |
| 295 delegate_->CancelFetchNavigationCorrections(); | 331 delegate_->CancelFetchNavigationCorrections(); |
| 332 auto_reload_timer_->Stop(); | |
| 333 can_auto_reload_page_ = false; | |
| 334 } | |
| 335 | |
| 336 void NetErrorHelperCore::OnStop() { | |
| 337 CancelPendingFetches(); | |
| 338 auto_reload_count_ = 0; | |
| 296 } | 339 } |
| 297 | 340 |
| 298 void NetErrorHelperCore::OnStartLoad(FrameType frame_type, PageType page_type) { | 341 void NetErrorHelperCore::OnStartLoad(FrameType frame_type, PageType page_type) { |
| 299 if (frame_type != MAIN_FRAME) | 342 if (frame_type != MAIN_FRAME) |
| 300 return; | 343 return; |
| 301 | 344 |
| 302 // If there's no pending error page information associated with the page load, | 345 // If there's no pending error page information associated with the page load, |
| 303 // or the new page is not an error page, then reset pending error page state. | 346 // or the new page is not an error page, then reset pending error page state. |
| 304 if (!pending_error_page_info_ || page_type != ERROR_PAGE) { | 347 if (!pending_error_page_info_ || page_type != ERROR_PAGE) { |
| 305 OnStop(); | 348 CancelPendingFetches(); |
| 349 } else { | |
| 350 // If an error load is starting, the resulting error page is autoreloadable. | |
| 351 can_auto_reload_page_ = IsReloadableError(*pending_error_page_info_); | |
| 306 } | 352 } |
| 307 } | 353 } |
| 308 | 354 |
| 309 void NetErrorHelperCore::OnCommitLoad(FrameType frame_type) { | 355 void NetErrorHelperCore::OnCommitLoad(FrameType frame_type) { |
| 310 if (frame_type != MAIN_FRAME) | 356 if (frame_type != MAIN_FRAME) |
| 311 return; | 357 return; |
| 312 | 358 |
| 359 if (committed_error_page_info_ && !pending_error_page_info_ && | |
| 360 can_auto_reload_page_) { | |
| 361 int reason = committed_error_page_info_->error.reason; | |
| 362 UMA_HISTOGRAM_CUSTOM_ENUMERATION("Net.AutoReload.ErrorAtSuccess", | |
| 363 -reason, | |
| 364 net::GetAllErrorCodesForUma()); | |
| 365 UMA_HISTOGRAM_COUNTS("Net.AutoReload.CountAtSuccess", auto_reload_count_); | |
| 366 if (auto_reload_count_ == 1) { | |
| 367 UMA_HISTOGRAM_CUSTOM_ENUMERATION("Net.AutoReload.ErrorAtFirstSuccess", | |
| 368 -reason, | |
| 369 net::GetAllErrorCodesForUma()); | |
| 370 } | |
| 371 } | |
| 372 | |
| 313 committed_error_page_info_.reset(pending_error_page_info_.release()); | 373 committed_error_page_info_.reset(pending_error_page_info_.release()); |
| 314 } | 374 } |
| 315 | 375 |
| 316 void NetErrorHelperCore::OnFinishLoad(FrameType frame_type) { | 376 void NetErrorHelperCore::OnFinishLoad(FrameType frame_type) { |
| 317 if (frame_type != MAIN_FRAME || !committed_error_page_info_) | 377 if (frame_type != MAIN_FRAME) |
| 318 return; | 378 return; |
| 319 | 379 |
| 380 if (!committed_error_page_info_) { | |
| 381 auto_reload_count_ = 0; | |
| 382 return; | |
| 383 } | |
| 384 | |
| 320 committed_error_page_info_->is_finished_loading = true; | 385 committed_error_page_info_->is_finished_loading = true; |
| 321 | 386 |
| 322 if (committed_error_page_info_->navigation_correction_url.is_valid()) { | 387 if (committed_error_page_info_->navigation_correction_url.is_valid()) { |
| 323 // If there is another pending error page load, |fix_url| should have been | 388 // If there is another pending error page load, |fix_url| should have been |
| 324 // cleared. | 389 // cleared. |
| 325 DCHECK(!pending_error_page_info_); | 390 DCHECK(!pending_error_page_info_); |
| 326 DCHECK(!committed_error_page_info_->needs_dns_updates); | 391 DCHECK(!committed_error_page_info_->needs_dns_updates); |
| 327 delegate_->FetchNavigationCorrections( | 392 delegate_->FetchNavigationCorrections( |
| 328 committed_error_page_info_->navigation_correction_url, | 393 committed_error_page_info_->navigation_correction_url, |
| 329 committed_error_page_info_->navigation_correction_request_body); | 394 committed_error_page_info_->navigation_correction_request_body); |
| 395 } else if (auto_reload_enabled_ && | |
| 396 IsReloadableError(*committed_error_page_info_)) { | |
| 397 MaybeStartAutoReloadTimer(); | |
| 330 } | 398 } |
| 331 | 399 |
| 332 if (!committed_error_page_info_->needs_dns_updates || | 400 if (!committed_error_page_info_->needs_dns_updates || |
| 333 last_probe_status_ == chrome_common_net::DNS_PROBE_POSSIBLE) { | 401 last_probe_status_ == chrome_common_net::DNS_PROBE_POSSIBLE) { |
| 334 return; | 402 return; |
| 335 } | 403 } |
| 336 DVLOG(1) << "Error page finished loading; sending saved status."; | 404 DVLOG(1) << "Error page finished loading; sending saved status."; |
| 337 UpdateErrorPage(); | 405 UpdateErrorPage(); |
| 338 } | 406 } |
| 339 | 407 |
| (...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 491 | 559 |
| 492 blink::WebURLError updated_error; | 560 blink::WebURLError updated_error; |
| 493 updated_error.domain = blink::WebString::fromUTF8( | 561 updated_error.domain = blink::WebString::fromUTF8( |
| 494 chrome_common_net::kDnsProbeErrorDomain); | 562 chrome_common_net::kDnsProbeErrorDomain); |
| 495 updated_error.reason = last_probe_status_; | 563 updated_error.reason = last_probe_status_; |
| 496 updated_error.unreachableURL = error.unreachableURL; | 564 updated_error.unreachableURL = error.unreachableURL; |
| 497 updated_error.staleCopyInCache = error.staleCopyInCache; | 565 updated_error.staleCopyInCache = error.staleCopyInCache; |
| 498 | 566 |
| 499 return updated_error; | 567 return updated_error; |
| 500 } | 568 } |
| 569 | |
| 570 void NetErrorHelperCore::Reload() { | |
| 571 if (!committed_error_page_info_) { | |
|
mmenke
2014/03/13 19:18:12
Can this happen?
| |
| 572 return; | |
| 573 } | |
| 574 delegate_->ReloadPage(); | |
| 575 } | |
| 576 | |
| 577 bool NetErrorHelperCore::MaybeStartAutoReloadTimer() { | |
| 578 if (!committed_error_page_info_ || | |
| 579 !committed_error_page_info_->is_finished_loading || | |
| 580 !can_auto_reload_page_ || | |
| 581 pending_error_page_info_) { | |
| 582 return false; | |
| 583 } | |
| 584 | |
| 585 DCHECK(IsReloadableError(*committed_error_page_info_)); | |
| 586 | |
| 587 if (!online_) | |
| 588 return false; | |
| 589 | |
| 590 StartAutoReloadTimer(); | |
| 591 return true; | |
| 592 } | |
| 593 | |
| 594 void NetErrorHelperCore::StartAutoReloadTimer() { | |
| 595 DCHECK(committed_error_page_info_); | |
| 596 DCHECK(can_auto_reload_page_); | |
| 597 base::TimeDelta delay = GetAutoReloadTime(auto_reload_count_); | |
| 598 auto_reload_count_++; | |
| 599 auto_reload_timer_->Stop(); | |
| 600 auto_reload_timer_->Start(FROM_HERE, delay, | |
| 601 base::Bind(&NetErrorHelperCore::Reload, | |
| 602 base::Unretained(this))); | |
| 603 } | |
| 604 | |
| 605 void NetErrorHelperCore::NetworkStateChanged(bool online) { | |
| 606 online_ = online; | |
| 607 if (auto_reload_timer_->IsRunning()) { | |
| 608 DCHECK(committed_error_page_info_); | |
| 609 // If there's an existing timer running, stop it and reset the retry count. | |
| 610 auto_reload_timer_->Stop(); | |
| 611 auto_reload_count_ = 0; | |
| 612 } | |
| 613 | |
| 614 // If the network state changed to online, maybe start auto-reloading again. | |
| 615 if (online) | |
| 616 MaybeStartAutoReloadTimer(); | |
| 617 } | |
| 618 | |
| 619 bool NetErrorHelperCore::ShouldSuppressErrorPage(FrameType frame_type, | |
| 620 const GURL& url) { | |
| 621 // Don't suppress child frame errors. | |
| 622 if (frame_type != MAIN_FRAME) | |
| 623 return false; | |
| 624 | |
| 625 // If |auto_reload_timer_| is still running, this error page isn't from an | |
| 626 // auto reload. | |
| 627 if (auto_reload_timer_->IsRunning()) | |
| 628 return false; | |
| 629 | |
| 630 // If there's no committed error page, this error page wasn't from an auto | |
| 631 // reload. | |
| 632 if (!committed_error_page_info_ || !can_auto_reload_page_) | |
| 633 return false; | |
| 634 | |
| 635 GURL error_url = committed_error_page_info_->error.unreachableURL; | |
| 636 // TODO(ellyjones): also plumb the error code down to CCRC and check that | |
| 637 if (error_url != url) | |
| 638 return false; | |
| 639 | |
| 640 // The first iteration of the timer is started by OnFinishLoad calling | |
| 641 // MaybeStartAutoReloadTimer, but since error pages for subsequent loads are | |
| 642 // suppressed in this function, subsequent iterations of the timer have to be | |
| 643 // started here. | |
| 644 MaybeStartAutoReloadTimer(); | |
| 645 return true; | |
| 646 } | |
| OLD | NEW |