Suppress tabs permission warning if there is already a browsingHistory warning.
[chromium-blink-merge.git] / chrome / renderer / net / net_error_helper_core.cc
blob517f4d514adf2be1ff3af0e159c8c19d6c91ed77
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
3 // found in the LICENSE file.
5 #include "chrome/renderer/net/net_error_helper_core.h"
7 #include <string>
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/i18n/rtl.h"
12 #include "base/json/json_reader.h"
13 #include "base/json/json_writer.h"
14 #include "base/location.h"
15 #include "base/metrics/histogram.h"
16 #include "base/strings/string16.h"
17 #include "base/values.h"
18 #include "chrome/common/localized_error.h"
19 #include "grit/generated_resources.h"
20 #include "net/base/escape.h"
21 #include "net/base/net_errors.h"
22 #include "net/base/net_util.h"
23 #include "third_party/WebKit/public/platform/WebString.h"
24 #include "third_party/WebKit/public/platform/WebURLError.h"
25 #include "ui/base/l10n/l10n_util.h"
26 #include "url/gurl.h"
28 namespace {
30 struct CorrectionTypeToResourceTable {
31 int resource_id;
32 const char* correction_type;
35 const CorrectionTypeToResourceTable kCorrectionResourceTable[] = {
36 {IDS_ERRORPAGES_SUGGESTION_VISIT_GOOGLE_CACHE, "cachedPage"},
37 // "reloadPage" is has special handling.
38 {IDS_ERRORPAGES_SUGGESTION_CORRECTED_URL, "urlCorrection"},
39 {IDS_ERRORPAGES_SUGGESTION_ALTERNATE_URL, "siteDomain"},
40 {IDS_ERRORPAGES_SUGGESTION_ALTERNATE_URL, "host"},
41 {IDS_ERRORPAGES_SUGGESTION_ALTERNATE_URL, "sitemap"},
42 {IDS_ERRORPAGES_SUGGESTION_ALTERNATE_URL, "pathParentFolder"},
43 // "siteSearchQuery" is not yet supported.
44 // TODO(mmenke): Figure out what format "siteSearchQuery" uses for its
45 // suggestions.
46 // "webSearchQuery" has special handling.
47 {IDS_ERRORPAGES_SUGGESTION_ALTERNATE_URL, "contentOverlap"},
48 {IDS_ERRORPAGES_SUGGESTION_CORRECTED_URL, "emphasizedUrlCorrection"},
51 base::TimeDelta GetAutoReloadTime(size_t reload_count) {
52 static const int kDelaysMs[] = {
53 0, 5000, 30000, 60000, 300000, 600000, 1800000
55 if (reload_count >= arraysize(kDelaysMs))
56 reload_count = arraysize(kDelaysMs) - 1;
57 return base::TimeDelta::FromMilliseconds(kDelaysMs[reload_count]);
60 // Returns whether |net_error| is a DNS-related error (and therefore whether
61 // the tab helper should start a DNS probe after receiving it.)
62 bool IsDnsError(const blink::WebURLError& error) {
63 return error.domain.utf8() == net::kErrorDomain &&
64 (error.reason == net::ERR_NAME_NOT_RESOLVED ||
65 error.reason == net::ERR_NAME_RESOLUTION_FAILED);
68 GURL SanitizeURL(const GURL& url) {
69 GURL::Replacements remove_params;
70 remove_params.ClearUsername();
71 remove_params.ClearPassword();
72 remove_params.ClearQuery();
73 remove_params.ClearRef();
74 return url.ReplaceComponents(remove_params);
77 // If URL correction information should be retrieved remotely for a main frame
78 // load that failed with |error|, returns true and sets
79 // |correction_request_body| to be the body for the correction request.
80 bool GetFixUrlRequestBody(const blink::WebURLError& error,
81 const std::string& language,
82 const std::string& country_code,
83 const std::string& api_key,
84 std::string* correction_request_body) {
85 // Parameter to send to the correction service indicating the error type.
86 std::string error_param;
88 std::string domain = error.domain.utf8();
89 if (domain == "http" && error.reason == 404) {
90 error_param = "http404";
91 } else if (IsDnsError(error)) {
92 error_param = "dnserror";
93 } else if (domain == net::kErrorDomain &&
94 (error.reason == net::ERR_CONNECTION_FAILED ||
95 error.reason == net::ERR_CONNECTION_REFUSED ||
96 error.reason == net::ERR_ADDRESS_UNREACHABLE ||
97 error.reason == net::ERR_CONNECTION_TIMED_OUT)) {
98 error_param = "connectionFailure";
99 } else {
100 return false;
103 // Don't use the correction service for HTTPS (for privacy reasons).
104 GURL unreachable_url(error.unreachableURL);
105 if (unreachable_url.SchemeIsSecure())
106 return false;
108 // TODO(yuusuke): Change to net::FormatUrl when Link Doctor becomes
109 // unicode-capable.
110 std::string spec_to_send = SanitizeURL(unreachable_url).spec();
112 // Notify navigation correction service of the url truncation by sending of
113 // "?" at the end.
114 if (unreachable_url.has_query())
115 spec_to_send.append("?");
117 // Assemble request body, which is a JSON string.
118 // TODO(mmenke): Investigate open sourcing the relevant protocol buffers and
119 // using those directly instead.
121 base::DictionaryValue request_dict;
122 request_dict.SetString("method", "linkdoctor.fixurl.fixurl");
123 request_dict.SetString("apiVersion", "v1");
125 base::DictionaryValue* params_dict = new base::DictionaryValue();
126 request_dict.Set("params", params_dict);
128 params_dict->SetString("key", api_key);
129 params_dict->SetString("urlQuery", spec_to_send);
130 params_dict->SetString("clientName", "chrome");
131 params_dict->SetString("error", error_param);
133 if (!language.empty())
134 params_dict->SetString("language", language);
136 if (!country_code.empty())
137 params_dict->SetString("originCountry", country_code);
139 base::JSONWriter::Write(&request_dict, correction_request_body);
140 return true;
143 base::string16 FormatURLForDisplay(const GURL& url, bool is_rtl,
144 const std::string accept_languages) {
145 // Translate punycode into UTF8, unescape UTF8 URLs.
146 base::string16 url_for_display(net::FormatUrl(
147 url, accept_languages, net::kFormatUrlOmitNothing,
148 net::UnescapeRule::NORMAL, NULL, NULL, NULL));
149 // URLs are always LTR.
150 if (is_rtl)
151 base::i18n::WrapStringWithLTRFormatting(&url_for_display);
152 return url_for_display;
155 LocalizedError::ErrorPageParams* ParseAdditionalSuggestions(
156 const std::string& data,
157 const GURL& original_url,
158 const GURL& search_url,
159 const std::string& accept_languages,
160 bool is_rtl) {
161 scoped_ptr<base::Value> parsed(base::JSONReader::Read(data));
162 if (!parsed)
163 return NULL;
164 // TODO(mmenke): Open source related protocol buffers and use them directly.
165 base::DictionaryValue* parsed_dict;
166 base::ListValue* corrections;
167 if (!parsed->GetAsDictionary(&parsed_dict))
168 return NULL;
169 if (!parsed_dict->GetList("result.UrlCorrections", &corrections))
170 return NULL;
172 // Version of URL for display in suggestions. It has to be sanitized first
173 // because any received suggestions will be relative to the sanitized URL.
174 base::string16 original_url_for_display =
175 FormatURLForDisplay(SanitizeURL(original_url), is_rtl, accept_languages);
177 scoped_ptr<LocalizedError::ErrorPageParams> params(
178 new LocalizedError::ErrorPageParams());
179 params->override_suggestions.reset(new base::ListValue());
180 scoped_ptr<base::ListValue> parsed_corrections(new base::ListValue());
181 for (base::ListValue::iterator it = corrections->begin();
182 it != corrections->end(); ++it) {
183 base::DictionaryValue* correction;
184 if (!(*it)->GetAsDictionary(&correction))
185 continue;
187 // Doesn't seem like a good idea to show these.
188 bool is_porn;
189 if (correction->GetBoolean("isPorn", &is_porn) && is_porn)
190 continue;
191 if (correction->GetBoolean("isSoftPorn", &is_porn) && is_porn)
192 continue;
194 std::string correction_type;
195 std::string url_correction;
196 if (!correction->GetString("correctionType", &correction_type) ||
197 !correction->GetString("urlCorrection", &url_correction)) {
198 continue;
201 std::string click_tracking_url;
202 correction->GetString("clickTrackingUrl", &click_tracking_url);
204 if (correction_type == "reloadPage") {
205 params->suggest_reload = true;
206 continue;
209 if (correction_type == "webSearchQuery") {
210 // If there are mutliple searches suggested, use the first suggestion.
211 if (params->search_terms.empty()) {
212 params->search_url = search_url;
213 params->search_terms = url_correction;
215 continue;
218 size_t correction_index;
219 for (correction_index = 0;
220 correction_index < arraysize(kCorrectionResourceTable);
221 ++correction_index) {
222 if (correction_type !=
223 kCorrectionResourceTable[correction_index].correction_type) {
224 continue;
226 base::DictionaryValue* suggest = new base::DictionaryValue();
227 suggest->SetString("header",
228 l10n_util::GetStringUTF16(
229 kCorrectionResourceTable[correction_index].resource_id));
230 suggest->SetString("urlCorrection",
231 !click_tracking_url.empty() ? click_tracking_url :
232 url_correction);
233 suggest->SetString(
234 "urlCorrectionForDisplay",
235 FormatURLForDisplay(GURL(url_correction), is_rtl, accept_languages));
236 suggest->SetString("originalUrlForDisplay", original_url_for_display);
237 params->override_suggestions->Append(suggest);
238 break;
242 if (params->override_suggestions->empty() &&
243 !params->search_url.is_valid()) {
244 return NULL;
246 return params.release();
249 } // namespace
251 struct NetErrorHelperCore::ErrorPageInfo {
252 ErrorPageInfo(blink::WebURLError error, bool was_failed_post)
253 : error(error),
254 was_failed_post(was_failed_post),
255 needs_dns_updates(false),
256 is_finished_loading(false) {
259 // Information about the failed page load.
260 blink::WebURLError error;
261 bool was_failed_post;
263 // Information about the status of the error page.
265 // True if a page is a DNS error page and has not yet received a final DNS
266 // probe status.
267 bool needs_dns_updates;
269 // Navigation correction service url, which will be used in response to
270 // certain types of network errors. This is also stored by the
271 // NetErrorHelperCore itself, but it stored here as well in case its modified
272 // in the middle of an error page load. Empty when no error page should be
273 // fetched, or if there's already a fetch in progress.
274 GURL navigation_correction_url;
276 // Request body to use when requesting corrections from a web service.
277 // TODO(mmenke): Investigate loading the error page at the same time as
278 // the blank page is loading, to get rid of these.
279 std::string navigation_correction_request_body;
281 // True if a page has completed loading, at which point it can receive
282 // updates.
283 bool is_finished_loading;
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;
293 NetErrorHelperCore::NetErrorHelperCore(Delegate* delegate)
294 : delegate_(delegate),
295 last_probe_status_(chrome_common_net::DNS_PROBE_POSSIBLE),
296 auto_reload_enabled_(false),
297 auto_reload_timer_(new base::Timer(false, false)),
298 // TODO(ellyjones): Make online_ accurate at object creation.
299 online_(true),
300 auto_reload_count_(0),
301 can_auto_reload_page_(false) {
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_);
313 void NetErrorHelperCore::CancelPendingFetches() {
314 // Cancel loading the alternate error page, and prevent any pending error page
315 // load from starting a new error page load. Swapping in the error page when
316 // it's finished loading could abort the navigation, 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_);
323 if (committed_error_page_info_) {
324 committed_error_page_info_->navigation_correction_url = GURL();
325 committed_error_page_info_->navigation_correction_request_body.clear();
327 if (pending_error_page_info_) {
328 pending_error_page_info_->navigation_correction_url = GURL();
329 pending_error_page_info_->navigation_correction_request_body.clear();
331 delegate_->CancelFetchNavigationCorrections();
332 auto_reload_timer_->Stop();
333 can_auto_reload_page_ = false;
336 void NetErrorHelperCore::OnStop() {
337 CancelPendingFetches();
338 auto_reload_count_ = 0;
341 void NetErrorHelperCore::OnStartLoad(FrameType frame_type, PageType page_type) {
342 if (frame_type != MAIN_FRAME)
343 return;
345 // If there's no pending error page information associated with the page load,
346 // or the new page is not an error page, then reset pending error page state.
347 if (!pending_error_page_info_ || page_type != ERROR_PAGE) {
348 CancelPendingFetches();
349 } else if (auto_reload_enabled_) {
350 // If an error load is starting, the resulting error page is autoreloadable.
351 can_auto_reload_page_ = IsReloadableError(*pending_error_page_info_);
355 void NetErrorHelperCore::OnCommitLoad(FrameType frame_type) {
356 if (frame_type != MAIN_FRAME)
357 return;
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());
373 committed_error_page_info_.reset(pending_error_page_info_.release());
376 void NetErrorHelperCore::OnFinishLoad(FrameType frame_type) {
377 if (frame_type != MAIN_FRAME)
378 return;
380 if (!committed_error_page_info_) {
381 auto_reload_count_ = 0;
382 return;
385 committed_error_page_info_->is_finished_loading = true;
387 // Only enable stale cache JS bindings if this wasn't a post.
388 if (!committed_error_page_info_->was_failed_post) {
389 delegate_->EnableStaleLoadBindings(
390 committed_error_page_info_->error.unreachableURL);
393 if (committed_error_page_info_->navigation_correction_url.is_valid()) {
394 // If there is another pending error page load, |fix_url| should have been
395 // cleared.
396 DCHECK(!pending_error_page_info_);
397 DCHECK(!committed_error_page_info_->needs_dns_updates);
398 delegate_->FetchNavigationCorrections(
399 committed_error_page_info_->navigation_correction_url,
400 committed_error_page_info_->navigation_correction_request_body);
401 } else if (auto_reload_enabled_ &&
402 IsReloadableError(*committed_error_page_info_)) {
403 MaybeStartAutoReloadTimer();
406 if (!committed_error_page_info_->needs_dns_updates ||
407 last_probe_status_ == chrome_common_net::DNS_PROBE_POSSIBLE) {
408 return;
410 DVLOG(1) << "Error page finished loading; sending saved status.";
411 UpdateErrorPage();
414 void NetErrorHelperCore::GetErrorHTML(
415 FrameType frame_type,
416 const blink::WebURLError& error,
417 bool is_failed_post,
418 std::string* error_html) {
419 if (frame_type == MAIN_FRAME) {
420 // If navigation corrections were needed before, that should have been
421 // cancelled earlier by starting a new page load (Which has now failed).
422 DCHECK(!committed_error_page_info_ ||
423 !committed_error_page_info_->navigation_correction_url.is_valid());
425 std::string navigation_correction_request_body;
427 if (navigation_correction_url_.is_valid() &&
428 GetFixUrlRequestBody(error, language_, country_code_, api_key_,
429 &navigation_correction_request_body)) {
430 pending_error_page_info_.reset(new ErrorPageInfo(error, is_failed_post));
431 pending_error_page_info_->navigation_correction_url =
432 navigation_correction_url_;
433 pending_error_page_info_->navigation_correction_request_body =
434 navigation_correction_request_body;
435 return;
438 // The last probe status needs to be reset if this is a DNS error. This
439 // means that if a DNS error page is committed but has not yet finished
440 // loading, a DNS probe status scheduled to be sent to it may be thrown
441 // out, but since the new error page should trigger a new DNS probe, it
442 // will just get the results for the next page load.
443 if (IsDnsError(error))
444 last_probe_status_ = chrome_common_net::DNS_PROBE_POSSIBLE;
447 GenerateLocalErrorPage(frame_type, error, is_failed_post,
448 scoped_ptr<LocalizedError::ErrorPageParams>(),
449 error_html);
452 void NetErrorHelperCore::GenerateLocalErrorPage(
453 FrameType frame_type,
454 const blink::WebURLError& error,
455 bool is_failed_post,
456 scoped_ptr<LocalizedError::ErrorPageParams> params,
457 std::string* error_html) {
458 if (frame_type == MAIN_FRAME) {
459 pending_error_page_info_.reset(new ErrorPageInfo(error, is_failed_post));
460 // Skip DNS logic if suggestions were received from a remote server.
461 if (IsDnsError(error) && !params) {
462 // This is not strictly necessary, but waiting for a new status to be
463 // sent as a result of the DidFinishLoading call keeps the histograms
464 // consistent with older versions of the code, at no real cost.
465 last_probe_status_ = chrome_common_net::DNS_PROBE_POSSIBLE;
467 delegate_->GenerateLocalizedErrorPage(
468 GetUpdatedError(error), is_failed_post, params.Pass(),
469 error_html);
470 pending_error_page_info_->needs_dns_updates = true;
471 return;
475 delegate_->GenerateLocalizedErrorPage(error, is_failed_post,
476 params.Pass(), error_html);
479 void NetErrorHelperCore::OnNetErrorInfo(
480 chrome_common_net::DnsProbeStatus status) {
481 DCHECK_NE(chrome_common_net::DNS_PROBE_POSSIBLE, status);
483 last_probe_status_ = status;
485 if (!committed_error_page_info_ ||
486 !committed_error_page_info_->needs_dns_updates ||
487 !committed_error_page_info_->is_finished_loading) {
488 return;
491 UpdateErrorPage();
494 void NetErrorHelperCore::OnSetNavigationCorrectionInfo(
495 const GURL& navigation_correction_url,
496 const std::string& language,
497 const std::string& country_code,
498 const std::string& api_key,
499 const GURL& search_url) {
500 navigation_correction_url_ = navigation_correction_url;
501 language_ = language;
502 country_code_ = country_code;
503 api_key_ = api_key;
504 search_url_ = search_url;
507 void NetErrorHelperCore::UpdateErrorPage() {
508 DCHECK(committed_error_page_info_->needs_dns_updates);
509 DCHECK(committed_error_page_info_->is_finished_loading);
510 DCHECK_NE(chrome_common_net::DNS_PROBE_POSSIBLE, last_probe_status_);
512 UMA_HISTOGRAM_ENUMERATION("DnsProbe.ErrorPageUpdateStatus",
513 last_probe_status_,
514 chrome_common_net::DNS_PROBE_MAX);
515 // Every status other than DNS_PROBE_POSSIBLE and DNS_PROBE_STARTED is a
516 // final status code. Once one is reached, the page does not need further
517 // updates.
518 if (last_probe_status_ != chrome_common_net::DNS_PROBE_STARTED)
519 committed_error_page_info_->needs_dns_updates = false;
521 delegate_->UpdateErrorPage(
522 GetUpdatedError(committed_error_page_info_->error),
523 committed_error_page_info_->was_failed_post);
526 void NetErrorHelperCore::OnNavigationCorrectionsFetched(
527 const std::string& corrections,
528 const std::string& accept_languages,
529 bool is_rtl) {
530 // Loading suggestions only starts when a blank error page finishes loading,
531 // and is cancelled with a new load.
532 DCHECK(!pending_error_page_info_);
533 DCHECK(committed_error_page_info_->is_finished_loading);
535 scoped_ptr<LocalizedError::ErrorPageParams> params(
536 ParseAdditionalSuggestions(
537 corrections, GURL(committed_error_page_info_->error.unreachableURL),
538 search_url_, accept_languages, is_rtl));
539 std::string error_html;
540 GenerateLocalErrorPage(MAIN_FRAME,
541 committed_error_page_info_->error,
542 committed_error_page_info_->was_failed_post,
543 params.Pass(),
544 &error_html);
546 // |error_page_info| may have been destroyed by this point, since
547 // |pending_error_page_info_| was set to a new ErrorPageInfo.
549 // TODO(mmenke): Once the new API is in place, look into replacing this
550 // double page load by just updating the error page, like DNS
551 // probes do.
552 delegate_->LoadErrorPageInMainFrame(
553 error_html,
554 pending_error_page_info_->error.unreachableURL);
557 blink::WebURLError NetErrorHelperCore::GetUpdatedError(
558 const blink::WebURLError& error) const {
559 // If a probe didn't run or wasn't conclusive, restore the original error.
560 if (last_probe_status_ == chrome_common_net::DNS_PROBE_NOT_RUN ||
561 last_probe_status_ ==
562 chrome_common_net::DNS_PROBE_FINISHED_INCONCLUSIVE) {
563 return error;
566 blink::WebURLError updated_error;
567 updated_error.domain = blink::WebString::fromUTF8(
568 chrome_common_net::kDnsProbeErrorDomain);
569 updated_error.reason = last_probe_status_;
570 updated_error.unreachableURL = error.unreachableURL;
571 updated_error.staleCopyInCache = error.staleCopyInCache;
573 return updated_error;
576 void NetErrorHelperCore::Reload() {
577 if (!committed_error_page_info_) {
578 return;
580 delegate_->ReloadPage();
583 bool NetErrorHelperCore::MaybeStartAutoReloadTimer() {
584 if (!committed_error_page_info_ ||
585 !committed_error_page_info_->is_finished_loading ||
586 !can_auto_reload_page_ ||
587 pending_error_page_info_) {
588 return false;
591 DCHECK(IsReloadableError(*committed_error_page_info_));
593 if (!online_)
594 return false;
596 StartAutoReloadTimer();
597 return true;
600 void NetErrorHelperCore::StartAutoReloadTimer() {
601 DCHECK(committed_error_page_info_);
602 DCHECK(can_auto_reload_page_);
603 base::TimeDelta delay = GetAutoReloadTime(auto_reload_count_);
604 auto_reload_count_++;
605 auto_reload_timer_->Stop();
606 auto_reload_timer_->Start(FROM_HERE, delay,
607 base::Bind(&NetErrorHelperCore::Reload,
608 base::Unretained(this)));
611 void NetErrorHelperCore::NetworkStateChanged(bool online) {
612 online_ = online;
613 if (auto_reload_timer_->IsRunning()) {
614 DCHECK(committed_error_page_info_);
615 // If there's an existing timer running, stop it and reset the retry count.
616 auto_reload_timer_->Stop();
617 auto_reload_count_ = 0;
620 // If the network state changed to online, maybe start auto-reloading again.
621 if (online)
622 MaybeStartAutoReloadTimer();
625 bool NetErrorHelperCore::ShouldSuppressErrorPage(FrameType frame_type,
626 const GURL& url) {
627 // Don't suppress child frame errors.
628 if (frame_type != MAIN_FRAME)
629 return false;
631 // If |auto_reload_timer_| is still running, this error page isn't from an
632 // auto reload.
633 if (auto_reload_timer_->IsRunning())
634 return false;
636 // If there's no committed error page, this error page wasn't from an auto
637 // reload.
638 if (!committed_error_page_info_ || !can_auto_reload_page_)
639 return false;
641 GURL error_url = committed_error_page_info_->error.unreachableURL;
642 // TODO(ellyjones): also plumb the error code down to CCRC and check that
643 if (error_url != url)
644 return false;
646 // The first iteration of the timer is started by OnFinishLoad calling
647 // MaybeStartAutoReloadTimer, but since error pages for subsequent loads are
648 // suppressed in this function, subsequent iterations of the timer have to be
649 // started here.
650 MaybeStartAutoReloadTimer();
651 return true;