| 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/i18n/rtl.h" |
| 10 #include "base/json/json_reader.h" |
| 11 #include "base/json/json_writer.h" |
| 9 #include "base/metrics/histogram.h" | 12 #include "base/metrics/histogram.h" |
| 13 #include "base/strings/string16.h" |
| 14 #include "base/values.h" |
| 10 #include "chrome/common/localized_error.h" | 15 #include "chrome/common/localized_error.h" |
| 16 #include "grit/generated_resources.h" |
| 11 #include "net/base/escape.h" | 17 #include "net/base/escape.h" |
| 12 #include "net/base/net_errors.h" | 18 #include "net/base/net_errors.h" |
| 19 #include "net/base/net_util.h" |
| 13 #include "third_party/WebKit/public/platform/WebString.h" | 20 #include "third_party/WebKit/public/platform/WebString.h" |
| 14 #include "third_party/WebKit/public/platform/WebURLError.h" | 21 #include "third_party/WebKit/public/platform/WebURLError.h" |
| 22 #include "ui/base/l10n/l10n_util.h" |
| 15 #include "url/gurl.h" | 23 #include "url/gurl.h" |
| 16 | 24 |
| 17 namespace { | 25 namespace { |
| 18 | 26 |
| 27 struct CorrectionTypeToResourceTable { |
| 28 int resource_id; |
| 29 const char* correction_type; |
| 30 }; |
| 31 |
| 32 const CorrectionTypeToResourceTable kCorrectionResourceTable[] = { |
| 33 {IDS_ERRORPAGES_SUGGESTION_VISIT_GOOGLE_CACHE, "cachedPage"}, |
| 34 // "reloadPage" is has special handling. |
| 35 {IDS_ERRORPAGES_SUGGESTION_CORRECTED_URL, "urlCorrection"}, |
| 36 {IDS_ERRORPAGES_SUGGESTION_ALTERNATE_URL, "siteDomain"}, |
| 37 {IDS_ERRORPAGES_SUGGESTION_ALTERNATE_URL, "host"}, |
| 38 {IDS_ERRORPAGES_SUGGESTION_ALTERNATE_URL, "sitemap"}, |
| 39 {IDS_ERRORPAGES_SUGGESTION_ALTERNATE_URL, "pathParentFolder"}, |
| 40 // "siteSearchQuery" is not yet supported. |
| 41 // TODO(mmenke): Figure out what format "siteSearchQuery" uses for its |
| 42 // suggestions. |
| 43 // "webSearchQuery" has special handling. |
| 44 {IDS_ERRORPAGES_SUGGESTION_ALTERNATE_URL, "contentOverlap"}, |
| 45 {IDS_ERRORPAGES_SUGGESTION_CORRECTED_URL, "emphasizedUrlCorrection"}, |
| 46 }; |
| 47 |
| 19 // Returns whether |net_error| is a DNS-related error (and therefore whether | 48 // Returns whether |net_error| is a DNS-related error (and therefore whether |
| 20 // the tab helper should start a DNS probe after receiving it.) | 49 // the tab helper should start a DNS probe after receiving it.) |
| 21 bool IsDnsError(const blink::WebURLError& error) { | 50 bool IsDnsError(const blink::WebURLError& error) { |
| 22 return error.domain.utf8() == net::kErrorDomain && | 51 return error.domain.utf8() == net::kErrorDomain && |
| 23 (error.reason == net::ERR_NAME_NOT_RESOLVED || | 52 (error.reason == net::ERR_NAME_NOT_RESOLVED || |
| 24 error.reason == net::ERR_NAME_RESOLUTION_FAILED); | 53 error.reason == net::ERR_NAME_RESOLUTION_FAILED); |
| 25 } | 54 } |
| 26 | 55 |
| 27 // If an alternate error page should be retrieved remotely for a main frame load | 56 GURL SanitizeURL(const GURL& url) { |
| 28 // that failed with |error|, returns true and sets |error_page_url| to the URL | 57 GURL::Replacements remove_params; |
| 29 // of the remote error page. | 58 remove_params.ClearUsername(); |
| 30 bool GetErrorPageURL(const blink::WebURLError& error, | 59 remove_params.ClearPassword(); |
| 31 const GURL& alt_error_page_url, | 60 remove_params.ClearQuery(); |
| 32 GURL* error_page_url) { | 61 remove_params.ClearRef(); |
| 33 if (!alt_error_page_url.is_valid()) | 62 return url.ReplaceComponents(remove_params); |
| 34 return false; | 63 } |
| 35 | 64 |
| 36 // Parameter to send to the error page indicating the error type. | 65 // If URL correction information should be retrieved remotely for a main frame |
| 66 // load that failed with |error|, returns true and sets |
| 67 // |fix_url_request_body| to be the body for the correcion request. |
| 68 bool GetFixUrlRequestBody(const blink::WebURLError& error, |
| 69 const std::string& language, |
| 70 const std::string& country_code, |
| 71 const std::string& api_key, |
| 72 std::string* fix_url_request_body) { |
| 73 // Parameter to send to the Link Doctor service indicating the error type. |
| 37 std::string error_param; | 74 std::string error_param; |
| 38 | 75 |
| 39 std::string domain = error.domain.utf8(); | 76 std::string domain = error.domain.utf8(); |
| 40 if (domain == "http" && error.reason == 404) { | 77 if (domain == "http" && error.reason == 404) { |
| 41 error_param = "http404"; | 78 error_param = "http404"; |
| 42 } else if (IsDnsError(error)) { | 79 } else if (IsDnsError(error)) { |
| 43 error_param = "dnserror"; | 80 error_param = "dnserror"; |
| 44 } else if (domain == net::kErrorDomain && | 81 } else if (domain == net::kErrorDomain && |
| 45 (error.reason == net::ERR_CONNECTION_FAILED || | 82 (error.reason == net::ERR_CONNECTION_FAILED || |
| 46 error.reason == net::ERR_CONNECTION_REFUSED || | 83 error.reason == net::ERR_CONNECTION_REFUSED || |
| 47 error.reason == net::ERR_ADDRESS_UNREACHABLE || | 84 error.reason == net::ERR_ADDRESS_UNREACHABLE || |
| 48 error.reason == net::ERR_CONNECTION_TIMED_OUT)) { | 85 error.reason == net::ERR_CONNECTION_TIMED_OUT)) { |
| 49 error_param = "connectionfailure"; | 86 error_param = "connectionFailure"; |
| 50 } else { | 87 } else { |
| 51 return false; | 88 return false; |
| 52 } | 89 } |
| 53 | 90 |
| 54 // Don't use the Link Doctor for HTTPS (for privacy reasons). | 91 // Don't use the Link Doctor for HTTPS (for privacy reasons). |
| 55 GURL unreachable_url(error.unreachableURL); | 92 GURL unreachable_url(error.unreachableURL); |
| 56 if (unreachable_url.SchemeIsSecure()) | 93 if (unreachable_url.SchemeIsSecure()) |
| 57 return false; | 94 return false; |
| 58 | 95 |
| 59 // Sanitize the unreachable URL. | 96 // TODO(yuusuke): Change to net::FormatUrl when Link Doctor becomes |
| 60 GURL::Replacements remove_params; | |
| 61 remove_params.ClearUsername(); | |
| 62 remove_params.ClearPassword(); | |
| 63 remove_params.ClearQuery(); | |
| 64 remove_params.ClearRef(); | |
| 65 // TODO(yuusuke): change to net::FormatUrl when Link Doctor becomes | |
| 66 // unicode-capable. | 97 // unicode-capable. |
| 67 std::string spec_to_send = | 98 std::string spec_to_send = SanitizeURL(unreachable_url).spec(); |
| 68 unreachable_url.ReplaceComponents(remove_params).spec(); | |
| 69 | 99 |
| 70 // Notify Link Doctor of the url truncation by sending of "?" at the end. | 100 // Notify Link Doctor of the url truncation by sending of "?" at the end. |
| 71 if (unreachable_url.has_query()) | 101 if (unreachable_url.has_query()) |
| 72 spec_to_send.append("?"); | 102 spec_to_send.append("?"); |
| 73 | 103 |
| 74 std::string params(alt_error_page_url.query()); | 104 // Assemble request body, which is a JSON string. |
| 75 params.append("&url="); | 105 // TODO(mmenke): Investigate open sourcing the relevant protocol buffers and |
| 76 params.append(net::EscapeQueryParamValue(spec_to_send, true)); | 106 // using those directly instead. |
| 77 params.append("&sourceid=chrome"); | |
| 78 params.append("&error="); | |
| 79 params.append(error_param); | |
| 80 | 107 |
| 81 // Build the final url to request. | 108 base::DictionaryValue request_dict; |
| 82 GURL::Replacements link_doctor_params; | 109 request_dict.SetString("method", "linkdoctor.fixurl.fixurl"); |
| 83 link_doctor_params.SetQueryStr(params); | 110 request_dict.SetString("apiVersion", "v1"); |
| 84 *error_page_url = alt_error_page_url.ReplaceComponents(link_doctor_params); | 111 |
| 112 base::DictionaryValue* params_dict = new base::DictionaryValue(); |
| 113 request_dict.Set("params", params_dict); |
| 114 |
| 115 params_dict->SetString("key", api_key); |
| 116 params_dict->SetString("urlQuery", spec_to_send); |
| 117 params_dict->SetString("clientName", "chrome"); |
| 118 params_dict->SetString("error", error_param); |
| 119 |
| 120 if (!language.empty()) |
| 121 params_dict->SetString("language", language); |
| 122 |
| 123 if (!country_code.empty()) |
| 124 params_dict->SetString("originCountry", country_code); |
| 125 |
| 126 base::JSONWriter::Write(&request_dict, fix_url_request_body); |
| 85 return true; | 127 return true; |
| 86 } | 128 } |
| 87 | 129 |
| 130 base::string16 FormatURLForDisplay(const GURL& url, bool is_rtl, |
| 131 const std::string accept_languages) { |
| 132 // Translate punycode into UTF8, unescape UTF8 URLs. |
| 133 base::string16 url_for_display(net::FormatUrl( |
| 134 url, accept_languages, net::kFormatUrlOmitNothing, |
| 135 net::UnescapeRule::NORMAL, NULL, NULL, NULL)); |
| 136 // URLs are always LTR. |
| 137 if (is_rtl) |
| 138 base::i18n::WrapStringWithLTRFormatting(&url_for_display); |
| 139 return url_for_display; |
| 140 } |
| 141 |
| 142 LocalizedError::ErrorPageParams* ParseAdditionalSuggestions( |
| 143 const std::string& data, |
| 144 const GURL& original_url, |
| 145 const GURL& search_url, |
| 146 const std::string& accept_languages, |
| 147 bool is_rtl) { |
| 148 scoped_ptr<base::Value> parsed(base::JSONReader::Read(data)); |
| 149 if (!parsed) |
| 150 return NULL; |
| 151 // TODO(mmenke): Open source related protocol buffers and use them directly. |
| 152 base::DictionaryValue* parsed_dict; |
| 153 base::ListValue* corrections; |
| 154 if (!parsed->GetAsDictionary(&parsed_dict)) |
| 155 return NULL; |
| 156 if (!parsed_dict->GetList("result.UrlCorrections", &corrections)) |
| 157 return NULL; |
| 158 |
| 159 // Version of URL for display in suggestions. It has to be sanitized first |
| 160 // because any received suggestions will be relative to the sanitized URL. |
| 161 base::string16 original_url_for_display = |
| 162 FormatURLForDisplay(SanitizeURL(original_url), is_rtl, accept_languages); |
| 163 |
| 164 scoped_ptr<LocalizedError::ErrorPageParams> params( |
| 165 new LocalizedError::ErrorPageParams()); |
| 166 params->override_suggestions.reset(new base::ListValue()); |
| 167 scoped_ptr<base::ListValue> parsed_corrections(new base::ListValue()); |
| 168 for (base::ListValue::iterator it = corrections->begin(); |
| 169 it != corrections->end(); ++it) { |
| 170 base::DictionaryValue* correction; |
| 171 if (!(*it)->GetAsDictionary(&correction)) |
| 172 continue; |
| 173 |
| 174 // Doesn't seem like a good idea to show these. |
| 175 bool is_porn; |
| 176 if (correction->GetBoolean("isPorn", &is_porn) && is_porn) |
| 177 continue; |
| 178 if (correction->GetBoolean("isSoftPorn", &is_porn) && is_porn) |
| 179 continue; |
| 180 |
| 181 std::string correction_type; |
| 182 std::string url_correction; |
| 183 if (!correction->GetString("correctionType", &correction_type) || |
| 184 !correction->GetString("urlCorrection", &url_correction)) { |
| 185 continue; |
| 186 } |
| 187 |
| 188 std::string click_tracking_url; |
| 189 correction->GetString("clickTrackingUrl", &click_tracking_url); |
| 190 |
| 191 if (correction_type == "reloadPage") { |
| 192 params->suggest_reload = true; |
| 193 continue; |
| 194 } |
| 195 |
| 196 if (correction_type == "webSearchQuery") { |
| 197 // If there are mutliple searches suggested, use the first suggestion. |
| 198 if (params->search_terms.empty()) { |
| 199 params->search_url = search_url; |
| 200 params->search_terms = url_correction; |
| 201 } |
| 202 continue; |
| 203 } |
| 204 |
| 205 size_t correction_index; |
| 206 for (correction_index = 0; |
| 207 correction_index < arraysize(kCorrectionResourceTable); |
| 208 ++correction_index) { |
| 209 if (correction_type != |
| 210 kCorrectionResourceTable[correction_index].correction_type) { |
| 211 continue; |
| 212 } |
| 213 base::DictionaryValue* suggest = new base::DictionaryValue(); |
| 214 suggest->SetString("header", |
| 215 l10n_util::GetStringUTF16( |
| 216 kCorrectionResourceTable[correction_index].resource_id)); |
| 217 suggest->SetString("urlCorrection", |
| 218 !click_tracking_url.empty() ? click_tracking_url : |
| 219 url_correction); |
| 220 suggest->SetString( |
| 221 "urlCorrectionForDisplay", |
| 222 FormatURLForDisplay(GURL(url_correction), is_rtl, accept_languages)); |
| 223 suggest->SetString("originalUrlForDisplay", original_url_for_display); |
| 224 params->override_suggestions->Append(suggest); |
| 225 break; |
| 226 } |
| 227 } |
| 228 |
| 229 if (params->override_suggestions->empty() && |
| 230 !params->search_url.is_valid()) { |
| 231 return NULL; |
| 232 } |
| 233 return params.release(); |
| 234 } |
| 235 |
| 88 } // namespace | 236 } // namespace |
| 89 | 237 |
| 90 struct NetErrorHelperCore::ErrorPageInfo { | 238 struct NetErrorHelperCore::ErrorPageInfo { |
| 91 ErrorPageInfo(blink::WebURLError error, bool was_failed_post) | 239 ErrorPageInfo(blink::WebURLError error, bool was_failed_post) |
| 92 : error(error), | 240 : error(error), |
| 93 was_failed_post(was_failed_post), | 241 was_failed_post(was_failed_post), |
| 94 needs_dns_updates(false), | 242 needs_dns_updates(false), |
| 95 is_finished_loading(false) { | 243 is_finished_loading(false) { |
| 96 } | 244 } |
| 97 | 245 |
| 98 // Information about the failed page load. | 246 // Information about the failed page load. |
| 99 blink::WebURLError error; | 247 blink::WebURLError error; |
| 100 bool was_failed_post; | 248 bool was_failed_post; |
| 101 | 249 |
| 102 // Information about the status of the error page. | 250 // Information about the status of the error page. |
| 103 | 251 |
| 104 // True if a page is a DNS error page and has not yet received a final DNS | 252 // True if a page is a DNS error page and has not yet received a final DNS |
| 105 // probe status. | 253 // probe status. |
| 106 bool needs_dns_updates; | 254 bool needs_dns_updates; |
| 107 | 255 |
| 108 // URL of an alternate error page to repace this error page with, if it's a | 256 // URL of the FixURL service, which will be used to request suggestions on |
| 109 // valid URL. Request will be issued when the error page finishes loading. | 257 // certain types of network errors. This is also stored by the |
| 110 // This is done on load complete to ensure that there are two complete loads | 258 // NetErrorHelperCore itself, but it stored here as well in case its modified |
| 111 // for tests to wait for. | 259 // in the middle of an error page load. Empty when no error page should be |
| 112 GURL alternate_error_page_url; | 260 // fetched, or if there's already a fetch in progress. |
| 261 GURL link_doctor_url; |
| 262 |
| 263 // Request body to use when requesting suggestions from the FixURL service. |
| 264 // TODO(mmenke): Investigate loading the error page at the same time as |
| 265 // the blank page is loading, to get rid of these. |
| 266 std::string link_doctor_request_body; |
| 113 | 267 |
| 114 // True if a page has completed loading, at which point it can receive | 268 // True if a page has completed loading, at which point it can receive |
| 115 // updates. | 269 // updates. |
| 116 bool is_finished_loading; | 270 bool is_finished_loading; |
| 117 }; | 271 }; |
| 118 | 272 |
| 119 NetErrorHelperCore::NetErrorHelperCore(Delegate* delegate) | 273 NetErrorHelperCore::NetErrorHelperCore(Delegate* delegate) |
| 120 : delegate_(delegate), | 274 : delegate_(delegate), |
| 121 last_probe_status_(chrome_common_net::DNS_PROBE_POSSIBLE) { | 275 last_probe_status_(chrome_common_net::DNS_PROBE_POSSIBLE) { |
| 122 } | 276 } |
| 123 | 277 |
| 124 NetErrorHelperCore::~NetErrorHelperCore() { | 278 NetErrorHelperCore::~NetErrorHelperCore() { |
| 125 } | 279 } |
| 126 | 280 |
| 127 void NetErrorHelperCore::OnStop() { | 281 void NetErrorHelperCore::OnStop() { |
| 128 // On stop, cancel loading the alternate error page, and prevent any pending | 282 // On stop, cancel loading the Link Doctor suggestions, and prevent any |
| 129 // error page load from starting a new error page load. Swapping in the error | 283 // pending error page load from starting to load suggestions. Swapping in an |
| 130 // page when it's finished loading could abort the navigation, otherwise. | 284 // error page once suggestions are received could interrupt a navigation, |
| 131 if (committed_error_page_info_) | 285 // otherwise. |
| 132 committed_error_page_info_->alternate_error_page_url = GURL(); | 286 if (committed_error_page_info_) { |
| 133 if (pending_error_page_info_) | 287 committed_error_page_info_->link_doctor_url = GURL(); |
| 134 pending_error_page_info_->alternate_error_page_url = GURL(); | 288 committed_error_page_info_->link_doctor_request_body.clear(); |
| 135 delegate_->CancelFetchErrorPage(); | 289 } |
| 290 if (pending_error_page_info_) { |
| 291 pending_error_page_info_->link_doctor_url = GURL(); |
| 292 pending_error_page_info_->link_doctor_request_body.clear(); |
| 293 } |
| 294 delegate_->CancelFetchLinkDoctorSuggestions(); |
| 136 } | 295 } |
| 137 | 296 |
| 138 void NetErrorHelperCore::OnStartLoad(FrameType frame_type, PageType page_type) { | 297 void NetErrorHelperCore::OnStartLoad(FrameType frame_type, PageType page_type) { |
| 139 if (frame_type != MAIN_FRAME) | 298 if (frame_type != MAIN_FRAME) |
| 140 return; | 299 return; |
| 141 | 300 |
| 142 // If there's no pending error page information associated with the page load, | 301 // 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. | 302 // 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) { | 303 if (!pending_error_page_info_ || page_type != ERROR_PAGE) { |
| 145 OnStop(); | 304 OnStop(); |
| 146 } | 305 } |
| 147 } | 306 } |
| 148 | 307 |
| 149 void NetErrorHelperCore::OnCommitLoad(FrameType frame_type) { | 308 void NetErrorHelperCore::OnCommitLoad(FrameType frame_type) { |
| 150 if (frame_type != MAIN_FRAME) | 309 if (frame_type != MAIN_FRAME) |
| 151 return; | 310 return; |
| 152 | 311 |
| 153 committed_error_page_info_.reset(pending_error_page_info_.release()); | 312 committed_error_page_info_.reset(pending_error_page_info_.release()); |
| 154 } | 313 } |
| 155 | 314 |
| 156 void NetErrorHelperCore::OnFinishLoad(FrameType frame_type) { | 315 void NetErrorHelperCore::OnFinishLoad(FrameType frame_type) { |
| 157 if (frame_type != MAIN_FRAME || !committed_error_page_info_) | 316 if (frame_type != MAIN_FRAME || !committed_error_page_info_) |
| 158 return; | 317 return; |
| 159 | 318 |
| 160 committed_error_page_info_->is_finished_loading = true; | 319 committed_error_page_info_->is_finished_loading = true; |
| 161 | 320 |
| 162 if (committed_error_page_info_->alternate_error_page_url.is_valid()) { | 321 if (committed_error_page_info_->link_doctor_url.is_valid()) { |
| 163 // If there is another pending error page load, | 322 // If there is another pending error page load, |fix_url| should have been |
| 164 // |replace_with_alternate_error_page| should have been set to false. | 323 // cleared. |
| 165 DCHECK(!pending_error_page_info_); | 324 DCHECK(!pending_error_page_info_); |
| 166 DCHECK(!committed_error_page_info_->needs_dns_updates); | 325 DCHECK(!committed_error_page_info_->needs_dns_updates); |
| 167 GURL error_page_url; | 326 delegate_->FetchLinkDoctorSuggestions( |
| 168 delegate_->FetchErrorPage( | 327 committed_error_page_info_->link_doctor_url, |
| 169 committed_error_page_info_->alternate_error_page_url); | 328 committed_error_page_info_->link_doctor_request_body); |
| 170 } | 329 } |
| 171 | 330 |
| 172 if (!committed_error_page_info_->needs_dns_updates || | 331 if (!committed_error_page_info_->needs_dns_updates || |
| 173 last_probe_status_ == chrome_common_net::DNS_PROBE_POSSIBLE) { | 332 last_probe_status_ == chrome_common_net::DNS_PROBE_POSSIBLE) { |
| 174 return; | 333 return; |
| 175 } | 334 } |
| 176 DVLOG(1) << "Error page finished loading; sending saved status."; | 335 DVLOG(1) << "Error page finished loading; sending saved status."; |
| 177 UpdateErrorPage(); | 336 UpdateErrorPage(); |
| 178 } | 337 } |
| 179 | 338 |
| 180 void NetErrorHelperCore::GetErrorHTML( | 339 void NetErrorHelperCore::GetErrorHTML( |
| 181 FrameType frame_type, | 340 FrameType frame_type, |
| 182 const blink::WebURLError& error, | 341 const blink::WebURLError& error, |
| 183 bool is_failed_post, | 342 bool is_failed_post, |
| 184 std::string* error_html) { | 343 std::string* error_html) { |
| 185 if (frame_type == MAIN_FRAME) { | 344 if (frame_type == MAIN_FRAME) { |
| 186 // If an alternate error page was going to be fetched, that should have been | 345 // If Link Doctor suggestions were needed before, that should have been |
| 187 // cancelled by loading a new page load (Which has now failed to load). | 346 // cancelled earlier by starting a new page load (Which has now failed). |
| 188 DCHECK(!committed_error_page_info_ || | 347 DCHECK(!committed_error_page_info_ || |
| 189 !committed_error_page_info_->alternate_error_page_url.is_valid()); | 348 !committed_error_page_info_->link_doctor_url.is_valid()); |
| 349 |
| 350 std::string link_doctor_request_body; |
| 351 |
| 352 if (link_doctor_url_.is_valid() && |
| 353 GetFixUrlRequestBody(error, language_, country_code_, api_key_, |
| 354 &link_doctor_request_body)) { |
| 355 pending_error_page_info_.reset(new ErrorPageInfo(error, is_failed_post)); |
| 356 pending_error_page_info_->link_doctor_url = link_doctor_url_; |
| 357 pending_error_page_info_->link_doctor_request_body = |
| 358 link_doctor_request_body; |
| 359 return; |
| 360 } |
| 190 | 361 |
| 191 // The last probe status needs to be reset if this is a DNS error. This | 362 // The last probe status needs to be reset if this is a DNS error. This |
| 192 // means that if a DNS error page is committed but has not yet finished | 363 // means that if a DNS error page is committed but has not yet finished |
| 193 // loading, a DNS probe status scheduled to be sent to it may be thrown | 364 // loading, a DNS probe status scheduled to be sent to it may be thrown |
| 194 // out, but since the new error page should trigger a new DNS probe, it | 365 // out, but since the new error page should trigger a new DNS probe, it |
| 195 // will just get the results for the next page load. | 366 // will just get the results for the next page load. |
| 196 if (IsDnsError(error)) | 367 if (IsDnsError(error)) |
| 197 last_probe_status_ = chrome_common_net::DNS_PROBE_POSSIBLE; | 368 last_probe_status_ = chrome_common_net::DNS_PROBE_POSSIBLE; |
| 198 | |
| 199 GURL error_page_url; | |
| 200 if (GetErrorPageURL(error, alt_error_page_url_, &error_page_url)) { | |
| 201 pending_error_page_info_.reset(new ErrorPageInfo(error, is_failed_post)); | |
| 202 pending_error_page_info_->alternate_error_page_url = error_page_url; | |
| 203 return; | |
| 204 } | |
| 205 } | 369 } |
| 206 | 370 |
| 207 GenerateLocalErrorPage(frame_type, error, is_failed_post, error_html); | 371 GenerateLocalErrorPage(frame_type, error, is_failed_post, |
| 372 scoped_ptr<LocalizedError::ErrorPageParams>(), |
| 373 error_html); |
| 208 } | 374 } |
| 209 | 375 |
| 210 void NetErrorHelperCore::GenerateLocalErrorPage( | 376 void NetErrorHelperCore::GenerateLocalErrorPage( |
| 211 FrameType frame_type, | 377 FrameType frame_type, |
| 212 const blink::WebURLError& error, | 378 const blink::WebURLError& error, |
| 213 bool is_failed_post, | 379 bool is_failed_post, |
| 380 scoped_ptr<LocalizedError::ErrorPageParams> params, |
| 214 std::string* error_html) { | 381 std::string* error_html) { |
| 215 if (frame_type == MAIN_FRAME) { | 382 if (frame_type == MAIN_FRAME) { |
| 216 pending_error_page_info_.reset(new ErrorPageInfo(error, is_failed_post)); | 383 pending_error_page_info_.reset(new ErrorPageInfo(error, is_failed_post)); |
| 217 if (IsDnsError(error)) { | 384 // Skip DNS logic if suggestions were received from a remote server. |
| 385 // TODO(mmenke): Consider integrating probe results with Link Doctor |
| 386 // suggestions. |
| 387 if (IsDnsError(error) && !params) { |
| 218 // This is not strictly necessary, but waiting for a new status to be | 388 // This is not strictly necessary, but waiting for a new status to be |
| 219 // sent as a result of the DidFinishLoading call keeps the histograms | 389 // sent as a result of the DidFinishLoading call keeps the histograms |
| 220 // consistent with older versions of the code, at no real cost. | 390 // consistent with older versions of the code, at no real cost. |
| 221 last_probe_status_ = chrome_common_net::DNS_PROBE_POSSIBLE; | 391 last_probe_status_ = chrome_common_net::DNS_PROBE_POSSIBLE; |
| 222 | 392 |
| 223 delegate_->GenerateLocalizedErrorPage( | 393 delegate_->GenerateLocalizedErrorPage( |
| 224 GetUpdatedError(error), is_failed_post, error_html); | 394 GetUpdatedError(error), is_failed_post, params.Pass(), |
| 395 error_html); |
| 225 pending_error_page_info_->needs_dns_updates = true; | 396 pending_error_page_info_->needs_dns_updates = true; |
| 226 return; | 397 return; |
| 227 } | 398 } |
| 228 } | 399 } |
| 229 delegate_->GenerateLocalizedErrorPage(error, is_failed_post, error_html); | 400 |
| 401 delegate_->GenerateLocalizedErrorPage(error, is_failed_post, |
| 402 params.Pass(), error_html); |
| 230 } | 403 } |
| 231 | 404 |
| 232 void NetErrorHelperCore::OnNetErrorInfo( | 405 void NetErrorHelperCore::OnNetErrorInfo( |
| 233 chrome_common_net::DnsProbeStatus status) { | 406 chrome_common_net::DnsProbeStatus status) { |
| 234 DCHECK_NE(chrome_common_net::DNS_PROBE_POSSIBLE, status); | 407 DCHECK_NE(chrome_common_net::DNS_PROBE_POSSIBLE, status); |
| 235 | 408 |
| 236 last_probe_status_ = status; | 409 last_probe_status_ = status; |
| 237 | 410 |
| 238 if (!committed_error_page_info_ || | 411 if (!committed_error_page_info_ || |
| 239 !committed_error_page_info_->needs_dns_updates || | 412 !committed_error_page_info_->needs_dns_updates || |
| 240 !committed_error_page_info_->is_finished_loading) { | 413 !committed_error_page_info_->is_finished_loading) { |
| 241 return; | 414 return; |
| 242 } | 415 } |
| 243 | 416 |
| 244 UpdateErrorPage(); | 417 UpdateErrorPage(); |
| 245 } | 418 } |
| 246 | 419 |
| 420 void NetErrorHelperCore::OnSetLinkDoctorInfo(const GURL& link_doctor_url, |
| 421 const std::string& language, |
| 422 const std::string& country_code, |
| 423 const std::string& api_key, |
| 424 const GURL& search_url) { |
| 425 link_doctor_url_ = link_doctor_url; |
| 426 language_ = language; |
| 427 country_code_ = country_code; |
| 428 api_key_ = api_key; |
| 429 search_url_ = search_url; |
| 430 } |
| 431 |
| 247 void NetErrorHelperCore::UpdateErrorPage() { | 432 void NetErrorHelperCore::UpdateErrorPage() { |
| 248 DCHECK(committed_error_page_info_->needs_dns_updates); | 433 DCHECK(committed_error_page_info_->needs_dns_updates); |
| 249 DCHECK(committed_error_page_info_->is_finished_loading); | 434 DCHECK(committed_error_page_info_->is_finished_loading); |
| 250 DCHECK_NE(chrome_common_net::DNS_PROBE_POSSIBLE, last_probe_status_); | 435 DCHECK_NE(chrome_common_net::DNS_PROBE_POSSIBLE, last_probe_status_); |
| 251 | 436 |
| 252 UMA_HISTOGRAM_ENUMERATION("DnsProbe.ErrorPageUpdateStatus", | 437 UMA_HISTOGRAM_ENUMERATION("DnsProbe.ErrorPageUpdateStatus", |
| 253 last_probe_status_, | 438 last_probe_status_, |
| 254 chrome_common_net::DNS_PROBE_MAX); | 439 chrome_common_net::DNS_PROBE_MAX); |
| 255 // Every status other than DNS_PROBE_POSSIBLE and DNS_PROBE_STARTED is a | 440 // Every status other than DNS_PROBE_POSSIBLE and DNS_PROBE_STARTED is a |
| 256 // final status code. Once one is reached, the page does not need further | 441 // final status code. Once one is reached, the page does not need further |
| 257 // updates. | 442 // updates. |
| 258 if (last_probe_status_ != chrome_common_net::DNS_PROBE_STARTED) | 443 if (last_probe_status_ != chrome_common_net::DNS_PROBE_STARTED) |
| 259 committed_error_page_info_->needs_dns_updates = false; | 444 committed_error_page_info_->needs_dns_updates = false; |
| 260 | 445 |
| 261 delegate_->UpdateErrorPage( | 446 delegate_->UpdateErrorPage( |
| 262 GetUpdatedError(committed_error_page_info_->error), | 447 GetUpdatedError(committed_error_page_info_->error), |
| 263 committed_error_page_info_->was_failed_post); | 448 committed_error_page_info_->was_failed_post); |
| 264 } | 449 } |
| 265 | 450 |
| 266 void NetErrorHelperCore::OnAlternateErrorPageFetched(const std::string& data) { | 451 void NetErrorHelperCore::OnLinkDoctorSuggestionsFetched( |
| 267 // Alternate error page load only starts when an error page finishes loading, | 452 const std::string& suggestions, |
| 268 // and is cancelled with a new load | 453 const std::string& accept_languages, |
| 454 bool is_rtl) { |
| 455 // Loading suggestions only starts when a blank error page finishes loading, |
| 456 // and is cancelled with a new load. |
| 269 DCHECK(!pending_error_page_info_); | 457 DCHECK(!pending_error_page_info_); |
| 270 DCHECK(committed_error_page_info_->is_finished_loading); | 458 DCHECK(committed_error_page_info_->is_finished_loading); |
| 271 | 459 |
| 272 const std::string* error_html = NULL; | 460 scoped_ptr<LocalizedError::ErrorPageParams> params( |
| 273 std::string generated_html; | 461 ParseAdditionalSuggestions( |
| 274 if (!data.empty()) { | 462 suggestions, GURL(committed_error_page_info_->error.unreachableURL), |
| 275 // If the request succeeded, use the response in place of a generated error | 463 search_url_, accept_languages, is_rtl)); |
| 276 // page. | 464 std::string error_html; |
| 277 pending_error_page_info_.reset( | 465 GenerateLocalErrorPage(MAIN_FRAME, |
| 278 new ErrorPageInfo(committed_error_page_info_->error, | 466 committed_error_page_info_->error, |
| 279 committed_error_page_info_->was_failed_post)); | 467 committed_error_page_info_->was_failed_post, |
| 280 error_html = &data; | 468 params.Pass(), |
| 281 } else { | 469 &error_html); |
| 282 // Otherwise, generate a local error page. |pending_error_page_info_| will | |
| 283 // be set by GenerateLocalErrorPage. | |
| 284 GenerateLocalErrorPage(MAIN_FRAME, | |
| 285 committed_error_page_info_->error, | |
| 286 committed_error_page_info_->was_failed_post, | |
| 287 &generated_html); | |
| 288 error_html = &generated_html; | |
| 289 } | |
| 290 | 470 |
| 291 // |error_page_info| may have been destroyed by this point, since | 471 // |error_page_info| may have been destroyed by this point, since |
| 292 // |pending_error_page_info_| was set to a new ErrorPageInfo. | 472 // |pending_error_page_info_| was set to a new ErrorPageInfo. |
| 293 | 473 |
| 294 // TODO(mmenke): Once the new API is in place, look into replacing this | 474 // TODO(mmenke): Once the new API is in place, look into replacing this |
| 295 // double page load by just updating the error page, like DNS | 475 // double page load by just updating the error page, like DNS |
| 296 // probes do. | 476 // probes do. |
| 297 delegate_->LoadErrorPageInMainFrame( | 477 delegate_->LoadErrorPageInMainFrame( |
| 298 *error_html, | 478 error_html, |
| 299 pending_error_page_info_->error.unreachableURL); | 479 pending_error_page_info_->error.unreachableURL); |
| 300 } | 480 } |
| 301 | 481 |
| 302 blink::WebURLError NetErrorHelperCore::GetUpdatedError( | 482 blink::WebURLError NetErrorHelperCore::GetUpdatedError( |
| 303 const blink::WebURLError& error) const { | 483 const blink::WebURLError& error) const { |
| 304 // If a probe didn't run or wasn't conclusive, restore the original error. | 484 // If a probe didn't run or wasn't conclusive, restore the original error. |
| 305 if (last_probe_status_ == chrome_common_net::DNS_PROBE_NOT_RUN || | 485 if (last_probe_status_ == chrome_common_net::DNS_PROBE_NOT_RUN || |
| 306 last_probe_status_ == | 486 last_probe_status_ == |
| 307 chrome_common_net::DNS_PROBE_FINISHED_INCONCLUSIVE) { | 487 chrome_common_net::DNS_PROBE_FINISHED_INCONCLUSIVE) { |
| 308 return error; | 488 return error; |
| 309 } | 489 } |
| 310 | 490 |
| 311 blink::WebURLError updated_error; | 491 blink::WebURLError updated_error; |
| 312 updated_error.domain = blink::WebString::fromUTF8( | 492 updated_error.domain = blink::WebString::fromUTF8( |
| 313 chrome_common_net::kDnsProbeErrorDomain); | 493 chrome_common_net::kDnsProbeErrorDomain); |
| 314 updated_error.reason = last_probe_status_; | 494 updated_error.reason = last_probe_status_; |
| 315 updated_error.unreachableURL = error.unreachableURL; | 495 updated_error.unreachableURL = error.unreachableURL; |
| 316 | 496 |
| 317 return updated_error; | 497 return updated_error; |
| 318 } | 498 } |
| OLD | NEW |