| 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" | 9 #include "base/bind.h" |
| 10 #include "base/callback.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" | 11 #include "base/location.h" |
| 15 #include "base/metrics/histogram.h" | 12 #include "base/metrics/histogram.h" |
| 16 #include "base/strings/string16.h" | |
| 17 #include "base/values.h" | |
| 18 #include "chrome/common/localized_error.h" | 13 #include "chrome/common/localized_error.h" |
| 19 #include "grit/generated_resources.h" | |
| 20 #include "net/base/escape.h" | 14 #include "net/base/escape.h" |
| 21 #include "net/base/net_errors.h" | 15 #include "net/base/net_errors.h" |
| 22 #include "net/base/net_util.h" | |
| 23 #include "third_party/WebKit/public/platform/WebString.h" | 16 #include "third_party/WebKit/public/platform/WebString.h" |
| 24 #include "third_party/WebKit/public/platform/WebURLError.h" | 17 #include "third_party/WebKit/public/platform/WebURLError.h" |
| 25 #include "ui/base/l10n/l10n_util.h" | |
| 26 #include "url/gurl.h" | 18 #include "url/gurl.h" |
| 27 | 19 |
| 28 namespace { | 20 namespace { |
| 29 | 21 |
| 30 struct CorrectionTypeToResourceTable { | |
| 31 int resource_id; | |
| 32 const char* correction_type; | |
| 33 }; | |
| 34 | |
| 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"}, | |
| 49 }; | |
| 50 | |
| 51 base::TimeDelta GetAutoReloadTime(size_t reload_count) { | 22 base::TimeDelta GetAutoReloadTime(size_t reload_count) { |
| 52 static const int kDelaysMs[] = { | 23 static const int kDelaysMs[] = { |
| 53 0, 5000, 30000, 60000, 300000, 600000, 1800000 | 24 0, 5000, 30000, 60000, 300000, 600000, 1800000 |
| 54 }; | 25 }; |
| 55 if (reload_count >= arraysize(kDelaysMs)) | 26 if (reload_count >= arraysize(kDelaysMs)) |
| 56 reload_count = arraysize(kDelaysMs) - 1; | 27 reload_count = arraysize(kDelaysMs) - 1; |
| 57 return base::TimeDelta::FromMilliseconds(kDelaysMs[reload_count]); | 28 return base::TimeDelta::FromMilliseconds(kDelaysMs[reload_count]); |
| 58 } | 29 } |
| 59 | 30 |
| 60 // 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 |
| 61 // the tab helper should start a DNS probe after receiving it.) | 32 // the tab helper should start a DNS probe after receiving it.) |
| 62 bool IsDnsError(const blink::WebURLError& error) { | 33 bool IsDnsError(const blink::WebURLError& error) { |
| 63 return error.domain.utf8() == net::kErrorDomain && | 34 return error.domain.utf8() == net::kErrorDomain && |
| 64 (error.reason == net::ERR_NAME_NOT_RESOLVED || | 35 (error.reason == net::ERR_NAME_NOT_RESOLVED || |
| 65 error.reason == net::ERR_NAME_RESOLUTION_FAILED); | 36 error.reason == net::ERR_NAME_RESOLUTION_FAILED); |
| 66 } | 37 } |
| 67 | 38 |
| 68 GURL SanitizeURL(const GURL& url) { | 39 // If an alternate error page should be retrieved remotely for a main frame load |
| 69 GURL::Replacements remove_params; | 40 // that failed with |error|, returns true and sets |error_page_url| to the URL |
| 70 remove_params.ClearUsername(); | 41 // of the remote error page. |
| 71 remove_params.ClearPassword(); | 42 bool GetErrorPageURL(const blink::WebURLError& error, |
| 72 remove_params.ClearQuery(); | 43 const GURL& alt_error_page_url, |
| 73 remove_params.ClearRef(); | 44 GURL* error_page_url) { |
| 74 return url.ReplaceComponents(remove_params); | 45 if (!alt_error_page_url.is_valid()) |
| 75 } | 46 return false; |
| 76 | 47 |
| 77 // If URL correction information should be retrieved remotely for a main frame | 48 // Parameter to send to the error page indicating the error type. |
| 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; | 49 std::string error_param; |
| 87 | 50 |
| 88 std::string domain = error.domain.utf8(); | 51 std::string domain = error.domain.utf8(); |
| 89 if (domain == "http" && error.reason == 404) { | 52 if (domain == "http" && error.reason == 404) { |
| 90 error_param = "http404"; | 53 error_param = "http404"; |
| 91 } else if (IsDnsError(error)) { | 54 } else if (IsDnsError(error)) { |
| 92 error_param = "dnserror"; | 55 error_param = "dnserror"; |
| 93 } else if (domain == net::kErrorDomain && | 56 } else if (domain == net::kErrorDomain && |
| 94 (error.reason == net::ERR_CONNECTION_FAILED || | 57 (error.reason == net::ERR_CONNECTION_FAILED || |
| 95 error.reason == net::ERR_CONNECTION_REFUSED || | 58 error.reason == net::ERR_CONNECTION_REFUSED || |
| 96 error.reason == net::ERR_ADDRESS_UNREACHABLE || | 59 error.reason == net::ERR_ADDRESS_UNREACHABLE || |
| 97 error.reason == net::ERR_CONNECTION_TIMED_OUT)) { | 60 error.reason == net::ERR_CONNECTION_TIMED_OUT)) { |
| 98 error_param = "connectionFailure"; | 61 error_param = "connectionfailure"; |
| 99 } else { | 62 } else { |
| 100 return false; | 63 return false; |
| 101 } | 64 } |
| 102 | 65 |
| 103 // Don't use the correction service for HTTPS (for privacy reasons). | 66 // Don't use the Link Doctor for HTTPS (for privacy reasons). |
| 104 GURL unreachable_url(error.unreachableURL); | 67 GURL unreachable_url(error.unreachableURL); |
| 105 if (unreachable_url.SchemeIsSecure()) | 68 if (unreachable_url.SchemeIsSecure()) |
| 106 return false; | 69 return false; |
| 107 | 70 |
| 108 // TODO(yuusuke): Change to net::FormatUrl when Link Doctor becomes | 71 // Sanitize the unreachable URL. |
| 72 GURL::Replacements remove_params; |
| 73 remove_params.ClearUsername(); |
| 74 remove_params.ClearPassword(); |
| 75 remove_params.ClearQuery(); |
| 76 remove_params.ClearRef(); |
| 77 // TODO(yuusuke): change to net::FormatUrl when Link Doctor becomes |
| 109 // unicode-capable. | 78 // unicode-capable. |
| 110 std::string spec_to_send = SanitizeURL(unreachable_url).spec(); | 79 std::string spec_to_send = |
| 80 unreachable_url.ReplaceComponents(remove_params).spec(); |
| 111 | 81 |
| 112 // Notify navigation correction service of the url truncation by sending of | 82 // Notify Link Doctor of the url truncation by sending of "?" at the end. |
| 113 // "?" at the end. | |
| 114 if (unreachable_url.has_query()) | 83 if (unreachable_url.has_query()) |
| 115 spec_to_send.append("?"); | 84 spec_to_send.append("?"); |
| 116 | 85 |
| 117 // Assemble request body, which is a JSON string. | 86 std::string params(alt_error_page_url.query()); |
| 118 // TODO(mmenke): Investigate open sourcing the relevant protocol buffers and | 87 params.append("&url="); |
| 119 // using those directly instead. | 88 params.append(net::EscapeQueryParamValue(spec_to_send, true)); |
| 89 params.append("&sourceid=chrome"); |
| 90 params.append("&error="); |
| 91 params.append(error_param); |
| 120 | 92 |
| 121 base::DictionaryValue request_dict; | 93 // Build the final url to request. |
| 122 request_dict.SetString("method", "linkdoctor.fixurl.fixurl"); | 94 GURL::Replacements link_doctor_params; |
| 123 request_dict.SetString("apiVersion", "v1"); | 95 link_doctor_params.SetQueryStr(params); |
| 124 | 96 *error_page_url = alt_error_page_url.ReplaceComponents(link_doctor_params); |
| 125 base::DictionaryValue* params_dict = new base::DictionaryValue(); | |
| 126 request_dict.Set("params", params_dict); | |
| 127 | |
| 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); | |
| 132 | |
| 133 if (!language.empty()) | |
| 134 params_dict->SetString("language", language); | |
| 135 | |
| 136 if (!country_code.empty()) | |
| 137 params_dict->SetString("originCountry", country_code); | |
| 138 | |
| 139 base::JSONWriter::Write(&request_dict, correction_request_body); | |
| 140 return true; | 97 return true; |
| 141 } | 98 } |
| 142 | 99 |
| 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; | |
| 153 } | |
| 154 | |
| 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; | |
| 171 | |
| 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); | |
| 176 | |
| 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; | |
| 186 | |
| 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; | |
| 193 | |
| 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; | |
| 199 } | |
| 200 | |
| 201 std::string click_tracking_url; | |
| 202 correction->GetString("clickTrackingUrl", &click_tracking_url); | |
| 203 | |
| 204 if (correction_type == "reloadPage") { | |
| 205 params->suggest_reload = true; | |
| 206 continue; | |
| 207 } | |
| 208 | |
| 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; | |
| 214 } | |
| 215 continue; | |
| 216 } | |
| 217 | |
| 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; | |
| 225 } | |
| 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; | |
| 239 } | |
| 240 } | |
| 241 | |
| 242 if (params->override_suggestions->empty() && | |
| 243 !params->search_url.is_valid()) { | |
| 244 return NULL; | |
| 245 } | |
| 246 return params.release(); | |
| 247 } | |
| 248 | |
| 249 } // namespace | 100 } // namespace |
| 250 | 101 |
| 251 struct NetErrorHelperCore::ErrorPageInfo { | 102 struct NetErrorHelperCore::ErrorPageInfo { |
| 252 ErrorPageInfo(blink::WebURLError error, bool was_failed_post) | 103 ErrorPageInfo(blink::WebURLError error, bool was_failed_post) |
| 253 : error(error), | 104 : error(error), |
| 254 was_failed_post(was_failed_post), | 105 was_failed_post(was_failed_post), |
| 255 needs_dns_updates(false), | 106 needs_dns_updates(false), |
| 256 is_finished_loading(false) { | 107 is_finished_loading(false) { |
| 257 } | 108 } |
| 258 | 109 |
| 259 // Information about the failed page load. | 110 // Information about the failed page load. |
| 260 blink::WebURLError error; | 111 blink::WebURLError error; |
| 261 bool was_failed_post; | 112 bool was_failed_post; |
| 262 | 113 |
| 263 // Information about the status of the error page. | 114 // Information about the status of the error page. |
| 264 | 115 |
| 265 // True if a page is a DNS error page and has not yet received a final DNS | 116 // True if a page is a DNS error page and has not yet received a final DNS |
| 266 // probe status. | 117 // probe status. |
| 267 bool needs_dns_updates; | 118 bool needs_dns_updates; |
| 268 | 119 |
| 269 // Navigation correction service url, which will be used in response to | 120 // URL of an alternate error page to repace this error page with, if it's a |
| 270 // certain types of network errors. This is also stored by the | 121 // valid URL. Request will be issued when the error page finishes loading. |
| 271 // NetErrorHelperCore itself, but it stored here as well in case its modified | 122 // This is done on load complete to ensure that there are two complete loads |
| 272 // in the middle of an error page load. Empty when no error page should be | 123 // for tests to wait for. |
| 273 // fetched, or if there's already a fetch in progress. | 124 GURL alternate_error_page_url; |
| 274 GURL navigation_correction_url; | |
| 275 | |
| 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; | |
| 280 | 125 |
| 281 // True if a page has completed loading, at which point it can receive | 126 // True if a page has completed loading, at which point it can receive |
| 282 // updates. | 127 // updates. |
| 283 bool is_finished_loading; | 128 bool is_finished_loading; |
| 284 }; | 129 }; |
| 285 | 130 |
| 286 bool NetErrorHelperCore::IsReloadableError( | 131 bool NetErrorHelperCore::IsReloadableError( |
| 287 const NetErrorHelperCore::ErrorPageInfo& info) { | 132 const NetErrorHelperCore::ErrorPageInfo& info) { |
| 288 return info.error.domain.utf8() == net::kErrorDomain && | 133 return info.error.domain.utf8() == net::kErrorDomain && |
| 289 info.error.reason != net::ERR_ABORTED && | 134 info.error.reason != net::ERR_ABORTED && |
| (...skipping 23 matching lines...) Expand all Loading... |
| 313 void NetErrorHelperCore::CancelPendingFetches() { | 158 void NetErrorHelperCore::CancelPendingFetches() { |
| 314 // Cancel loading the alternate error page, and prevent any pending error page | 159 // 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 | 160 // load from starting a new error page load. Swapping in the error page when |
| 316 // it's finished loading could abort the navigation, otherwise. | 161 // it's finished loading could abort the navigation, otherwise. |
| 317 if (committed_error_page_info_ && can_auto_reload_page_) { | 162 if (committed_error_page_info_ && can_auto_reload_page_) { |
| 318 UMA_HISTOGRAM_CUSTOM_ENUMERATION("Net.AutoReload.ErrorAtStop", | 163 UMA_HISTOGRAM_CUSTOM_ENUMERATION("Net.AutoReload.ErrorAtStop", |
| 319 -committed_error_page_info_->error.reason, | 164 -committed_error_page_info_->error.reason, |
| 320 net::GetAllErrorCodesForUma()); | 165 net::GetAllErrorCodesForUma()); |
| 321 UMA_HISTOGRAM_COUNTS("Net.AutoReload.CountAtStop", auto_reload_count_); | 166 UMA_HISTOGRAM_COUNTS("Net.AutoReload.CountAtStop", auto_reload_count_); |
| 322 } | 167 } |
| 323 if (committed_error_page_info_) { | 168 if (committed_error_page_info_) |
| 324 committed_error_page_info_->navigation_correction_url = GURL(); | 169 committed_error_page_info_->alternate_error_page_url = GURL(); |
| 325 committed_error_page_info_->navigation_correction_request_body.clear(); | 170 if (pending_error_page_info_) |
| 326 } | 171 pending_error_page_info_->alternate_error_page_url = GURL(); |
| 327 if (pending_error_page_info_) { | 172 delegate_->CancelFetchErrorPage(); |
| 328 pending_error_page_info_->navigation_correction_url = GURL(); | |
| 329 pending_error_page_info_->navigation_correction_request_body.clear(); | |
| 330 } | |
| 331 delegate_->CancelFetchNavigationCorrections(); | |
| 332 auto_reload_timer_->Stop(); | 173 auto_reload_timer_->Stop(); |
| 333 can_auto_reload_page_ = false; | 174 can_auto_reload_page_ = false; |
| 334 } | 175 } |
| 335 | 176 |
| 336 void NetErrorHelperCore::OnStop() { | 177 void NetErrorHelperCore::OnStop() { |
| 337 CancelPendingFetches(); | 178 CancelPendingFetches(); |
| 338 auto_reload_count_ = 0; | 179 auto_reload_count_ = 0; |
| 339 } | 180 } |
| 340 | 181 |
| 341 void NetErrorHelperCore::OnStartLoad(FrameType frame_type, PageType page_type) { | 182 void NetErrorHelperCore::OnStartLoad(FrameType frame_type, PageType page_type) { |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 383 } | 224 } |
| 384 | 225 |
| 385 committed_error_page_info_->is_finished_loading = true; | 226 committed_error_page_info_->is_finished_loading = true; |
| 386 | 227 |
| 387 // Only enable stale cache JS bindings if this wasn't a post. | 228 // Only enable stale cache JS bindings if this wasn't a post. |
| 388 if (!committed_error_page_info_->was_failed_post) { | 229 if (!committed_error_page_info_->was_failed_post) { |
| 389 delegate_->EnableStaleLoadBindings( | 230 delegate_->EnableStaleLoadBindings( |
| 390 committed_error_page_info_->error.unreachableURL); | 231 committed_error_page_info_->error.unreachableURL); |
| 391 } | 232 } |
| 392 | 233 |
| 393 if (committed_error_page_info_->navigation_correction_url.is_valid()) { | 234 if (committed_error_page_info_->alternate_error_page_url.is_valid()) { |
| 394 // If there is another pending error page load, |fix_url| should have been | 235 // If there is another pending error page load, |
| 395 // cleared. | 236 // |replace_with_alternate_error_page| should have been set to false. |
| 396 DCHECK(!pending_error_page_info_); | 237 DCHECK(!pending_error_page_info_); |
| 397 DCHECK(!committed_error_page_info_->needs_dns_updates); | 238 DCHECK(!committed_error_page_info_->needs_dns_updates); |
| 398 delegate_->FetchNavigationCorrections( | 239 GURL error_page_url; |
| 399 committed_error_page_info_->navigation_correction_url, | 240 delegate_->FetchErrorPage( |
| 400 committed_error_page_info_->navigation_correction_request_body); | 241 committed_error_page_info_->alternate_error_page_url); |
| 401 } else if (auto_reload_enabled_ && | 242 } else if (auto_reload_enabled_ && |
| 402 IsReloadableError(*committed_error_page_info_)) { | 243 IsReloadableError(*committed_error_page_info_)) { |
| 403 MaybeStartAutoReloadTimer(); | 244 MaybeStartAutoReloadTimer(); |
| 404 } | 245 } |
| 405 | 246 |
| 406 if (!committed_error_page_info_->needs_dns_updates || | 247 if (!committed_error_page_info_->needs_dns_updates || |
| 407 last_probe_status_ == chrome_common_net::DNS_PROBE_POSSIBLE) { | 248 last_probe_status_ == chrome_common_net::DNS_PROBE_POSSIBLE) { |
| 408 return; | 249 return; |
| 409 } | 250 } |
| 410 DVLOG(1) << "Error page finished loading; sending saved status."; | 251 DVLOG(1) << "Error page finished loading; sending saved status."; |
| 411 UpdateErrorPage(); | 252 UpdateErrorPage(); |
| 412 } | 253 } |
| 413 | 254 |
| 414 void NetErrorHelperCore::GetErrorHTML( | 255 void NetErrorHelperCore::GetErrorHTML( |
| 415 FrameType frame_type, | 256 FrameType frame_type, |
| 416 const blink::WebURLError& error, | 257 const blink::WebURLError& error, |
| 417 bool is_failed_post, | 258 bool is_failed_post, |
| 418 std::string* error_html) { | 259 std::string* error_html) { |
| 419 if (frame_type == MAIN_FRAME) { | 260 if (frame_type == MAIN_FRAME) { |
| 420 // If navigation corrections were needed before, that should have been | 261 // If an alternate error page was going to be fetched, that should have been |
| 421 // cancelled earlier by starting a new page load (Which has now failed). | 262 // cancelled by loading a new page load (Which has now failed to load). |
| 422 DCHECK(!committed_error_page_info_ || | 263 DCHECK(!committed_error_page_info_ || |
| 423 !committed_error_page_info_->navigation_correction_url.is_valid()); | 264 !committed_error_page_info_->alternate_error_page_url.is_valid()); |
| 424 | |
| 425 std::string navigation_correction_request_body; | |
| 426 | |
| 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; | |
| 436 } | |
| 437 | 265 |
| 438 // The last probe status needs to be reset if this is a DNS error. This | 266 // 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 | 267 // 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 | 268 // 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 | 269 // 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. | 270 // will just get the results for the next page load. |
| 443 if (IsDnsError(error)) | 271 if (IsDnsError(error)) |
| 444 last_probe_status_ = chrome_common_net::DNS_PROBE_POSSIBLE; | 272 last_probe_status_ = chrome_common_net::DNS_PROBE_POSSIBLE; |
| 273 |
| 274 GURL error_page_url; |
| 275 if (GetErrorPageURL(error, alt_error_page_url_, &error_page_url)) { |
| 276 pending_error_page_info_.reset(new ErrorPageInfo(error, is_failed_post)); |
| 277 pending_error_page_info_->alternate_error_page_url = error_page_url; |
| 278 return; |
| 279 } |
| 445 } | 280 } |
| 446 | 281 |
| 447 GenerateLocalErrorPage(frame_type, error, is_failed_post, | 282 GenerateLocalErrorPage(frame_type, error, is_failed_post, error_html); |
| 448 scoped_ptr<LocalizedError::ErrorPageParams>(), | |
| 449 error_html); | |
| 450 } | 283 } |
| 451 | 284 |
| 452 void NetErrorHelperCore::GenerateLocalErrorPage( | 285 void NetErrorHelperCore::GenerateLocalErrorPage( |
| 453 FrameType frame_type, | 286 FrameType frame_type, |
| 454 const blink::WebURLError& error, | 287 const blink::WebURLError& error, |
| 455 bool is_failed_post, | 288 bool is_failed_post, |
| 456 scoped_ptr<LocalizedError::ErrorPageParams> params, | |
| 457 std::string* error_html) { | 289 std::string* error_html) { |
| 458 if (frame_type == MAIN_FRAME) { | 290 if (frame_type == MAIN_FRAME) { |
| 459 pending_error_page_info_.reset(new ErrorPageInfo(error, is_failed_post)); | 291 pending_error_page_info_.reset(new ErrorPageInfo(error, is_failed_post)); |
| 460 // Skip DNS logic if suggestions were received from a remote server. | 292 if (IsDnsError(error)) { |
| 461 if (IsDnsError(error) && !params) { | |
| 462 // This is not strictly necessary, but waiting for a new status to be | 293 // 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 | 294 // sent as a result of the DidFinishLoading call keeps the histograms |
| 464 // consistent with older versions of the code, at no real cost. | 295 // consistent with older versions of the code, at no real cost. |
| 465 last_probe_status_ = chrome_common_net::DNS_PROBE_POSSIBLE; | 296 last_probe_status_ = chrome_common_net::DNS_PROBE_POSSIBLE; |
| 466 | 297 |
| 467 delegate_->GenerateLocalizedErrorPage( | 298 delegate_->GenerateLocalizedErrorPage( |
| 468 GetUpdatedError(error), is_failed_post, params.Pass(), | 299 GetUpdatedError(error), is_failed_post, error_html); |
| 469 error_html); | |
| 470 pending_error_page_info_->needs_dns_updates = true; | 300 pending_error_page_info_->needs_dns_updates = true; |
| 471 return; | 301 return; |
| 472 } | 302 } |
| 473 } | 303 } |
| 474 | 304 delegate_->GenerateLocalizedErrorPage(error, is_failed_post, error_html); |
| 475 delegate_->GenerateLocalizedErrorPage(error, is_failed_post, | |
| 476 params.Pass(), error_html); | |
| 477 } | 305 } |
| 478 | 306 |
| 479 void NetErrorHelperCore::OnNetErrorInfo( | 307 void NetErrorHelperCore::OnNetErrorInfo( |
| 480 chrome_common_net::DnsProbeStatus status) { | 308 chrome_common_net::DnsProbeStatus status) { |
| 481 DCHECK_NE(chrome_common_net::DNS_PROBE_POSSIBLE, status); | 309 DCHECK_NE(chrome_common_net::DNS_PROBE_POSSIBLE, status); |
| 482 | 310 |
| 483 last_probe_status_ = status; | 311 last_probe_status_ = status; |
| 484 | 312 |
| 485 if (!committed_error_page_info_ || | 313 if (!committed_error_page_info_ || |
| 486 !committed_error_page_info_->needs_dns_updates || | 314 !committed_error_page_info_->needs_dns_updates || |
| 487 !committed_error_page_info_->is_finished_loading) { | 315 !committed_error_page_info_->is_finished_loading) { |
| 488 return; | 316 return; |
| 489 } | 317 } |
| 490 | 318 |
| 491 UpdateErrorPage(); | 319 UpdateErrorPage(); |
| 492 } | 320 } |
| 493 | 321 |
| 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; | |
| 505 } | |
| 506 | |
| 507 void NetErrorHelperCore::UpdateErrorPage() { | 322 void NetErrorHelperCore::UpdateErrorPage() { |
| 508 DCHECK(committed_error_page_info_->needs_dns_updates); | 323 DCHECK(committed_error_page_info_->needs_dns_updates); |
| 509 DCHECK(committed_error_page_info_->is_finished_loading); | 324 DCHECK(committed_error_page_info_->is_finished_loading); |
| 510 DCHECK_NE(chrome_common_net::DNS_PROBE_POSSIBLE, last_probe_status_); | 325 DCHECK_NE(chrome_common_net::DNS_PROBE_POSSIBLE, last_probe_status_); |
| 511 | 326 |
| 512 UMA_HISTOGRAM_ENUMERATION("DnsProbe.ErrorPageUpdateStatus", | 327 UMA_HISTOGRAM_ENUMERATION("DnsProbe.ErrorPageUpdateStatus", |
| 513 last_probe_status_, | 328 last_probe_status_, |
| 514 chrome_common_net::DNS_PROBE_MAX); | 329 chrome_common_net::DNS_PROBE_MAX); |
| 515 // Every status other than DNS_PROBE_POSSIBLE and DNS_PROBE_STARTED is a | 330 // 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 | 331 // final status code. Once one is reached, the page does not need further |
| 517 // updates. | 332 // updates. |
| 518 if (last_probe_status_ != chrome_common_net::DNS_PROBE_STARTED) | 333 if (last_probe_status_ != chrome_common_net::DNS_PROBE_STARTED) |
| 519 committed_error_page_info_->needs_dns_updates = false; | 334 committed_error_page_info_->needs_dns_updates = false; |
| 520 | 335 |
| 521 delegate_->UpdateErrorPage( | 336 delegate_->UpdateErrorPage( |
| 522 GetUpdatedError(committed_error_page_info_->error), | 337 GetUpdatedError(committed_error_page_info_->error), |
| 523 committed_error_page_info_->was_failed_post); | 338 committed_error_page_info_->was_failed_post); |
| 524 } | 339 } |
| 525 | 340 |
| 526 void NetErrorHelperCore::OnNavigationCorrectionsFetched( | 341 void NetErrorHelperCore::OnAlternateErrorPageFetched(const std::string& data) { |
| 527 const std::string& corrections, | 342 // Alternate error page load only starts when an error page finishes loading, |
| 528 const std::string& accept_languages, | 343 // and is cancelled with a new load |
| 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_); | 344 DCHECK(!pending_error_page_info_); |
| 533 DCHECK(committed_error_page_info_->is_finished_loading); | 345 DCHECK(committed_error_page_info_->is_finished_loading); |
| 534 | 346 |
| 535 scoped_ptr<LocalizedError::ErrorPageParams> params( | 347 const std::string* error_html = NULL; |
| 536 ParseAdditionalSuggestions( | 348 std::string generated_html; |
| 537 corrections, GURL(committed_error_page_info_->error.unreachableURL), | 349 if (!data.empty()) { |
| 538 search_url_, accept_languages, is_rtl)); | 350 // If the request succeeded, use the response in place of a generated error |
| 539 std::string error_html; | 351 // page. |
| 540 GenerateLocalErrorPage(MAIN_FRAME, | 352 pending_error_page_info_.reset( |
| 541 committed_error_page_info_->error, | 353 new ErrorPageInfo(committed_error_page_info_->error, |
| 542 committed_error_page_info_->was_failed_post, | 354 committed_error_page_info_->was_failed_post)); |
| 543 params.Pass(), | 355 error_html = &data; |
| 544 &error_html); | 356 } else { |
| 357 // Otherwise, generate a local error page. |pending_error_page_info_| will |
| 358 // be set by GenerateLocalErrorPage. |
| 359 GenerateLocalErrorPage(MAIN_FRAME, |
| 360 committed_error_page_info_->error, |
| 361 committed_error_page_info_->was_failed_post, |
| 362 &generated_html); |
| 363 error_html = &generated_html; |
| 364 } |
| 545 | 365 |
| 546 // |error_page_info| may have been destroyed by this point, since | 366 // |error_page_info| may have been destroyed by this point, since |
| 547 // |pending_error_page_info_| was set to a new ErrorPageInfo. | 367 // |pending_error_page_info_| was set to a new ErrorPageInfo. |
| 548 | 368 |
| 549 // TODO(mmenke): Once the new API is in place, look into replacing this | 369 // 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 | 370 // double page load by just updating the error page, like DNS |
| 551 // probes do. | 371 // probes do. |
| 552 delegate_->LoadErrorPageInMainFrame( | 372 delegate_->LoadErrorPageInMainFrame( |
| 553 error_html, | 373 *error_html, |
| 554 pending_error_page_info_->error.unreachableURL); | 374 pending_error_page_info_->error.unreachableURL); |
| 555 } | 375 } |
| 556 | 376 |
| 557 blink::WebURLError NetErrorHelperCore::GetUpdatedError( | 377 blink::WebURLError NetErrorHelperCore::GetUpdatedError( |
| 558 const blink::WebURLError& error) const { | 378 const blink::WebURLError& error) const { |
| 559 // If a probe didn't run or wasn't conclusive, restore the original error. | 379 // 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 || | 380 if (last_probe_status_ == chrome_common_net::DNS_PROBE_NOT_RUN || |
| 561 last_probe_status_ == | 381 last_probe_status_ == |
| 562 chrome_common_net::DNS_PROBE_FINISHED_INCONCLUSIVE) { | 382 chrome_common_net::DNS_PROBE_FINISHED_INCONCLUSIVE) { |
| 563 return error; | 383 return error; |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 643 if (error_url != url) | 463 if (error_url != url) |
| 644 return false; | 464 return false; |
| 645 | 465 |
| 646 // The first iteration of the timer is started by OnFinishLoad calling | 466 // The first iteration of the timer is started by OnFinishLoad calling |
| 647 // MaybeStartAutoReloadTimer, but since error pages for subsequent loads are | 467 // MaybeStartAutoReloadTimer, but since error pages for subsequent loads are |
| 648 // suppressed in this function, subsequent iterations of the timer have to be | 468 // suppressed in this function, subsequent iterations of the timer have to be |
| 649 // started here. | 469 // started here. |
| 650 MaybeStartAutoReloadTimer(); | 470 MaybeStartAutoReloadTimer(); |
| 651 return true; | 471 return true; |
| 652 } | 472 } |
| OLD | NEW |