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/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 |
| 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) { | |
| 36 // Parameter to send to the error page indicating the error type. | 73 // Parameter to send to the error page 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 // TODO(mmenke): Figure out if the originCountry can be set correctly. | |
| 124 // locale.getCountry() just seems to give the default country | |
| 125 // for the language resources currently in use. | |
| 126 | |
| 127 if (!country_code.empty()) | |
| 128 params_dict->SetString("originCountry", country_code); | |
| 129 | |
| 130 base::JSONWriter::Write(&request_dict, fix_url_request_body); | |
| 85 return true; | 131 return true; |
| 86 } | 132 } |
| 87 | 133 |
| 134 base::string16 FormatURLForDisplay(const GURL& url, bool is_rtl, | |
| 135 const std::string accept_languages) { | |
| 136 // Translate punycode into UTF8, unescape UTF8 URLs. | |
| 137 base::string16 url_for_display(net::FormatUrl( | |
| 138 url, accept_languages, net::kFormatUrlOmitNothing, | |
| 139 net::UnescapeRule::NORMAL, NULL, NULL, NULL)); | |
| 140 // URLs are always LTR. | |
| 141 if (is_rtl) | |
| 142 base::i18n::WrapStringWithLTRFormatting(&url_for_display); | |
| 143 return url_for_display; | |
| 144 } | |
| 145 | |
| 146 LocalizedError::ErrorPageParams* ParseAdditionalSuggestions( | |
| 147 const std::string& data, | |
| 148 const GURL& original_url, | |
| 149 const GURL& search_url, | |
| 150 const std::string& accept_languages, | |
| 151 bool is_rtl) { | |
| 152 scoped_ptr<base::Value> parsed(base::JSONReader::Read(data)); | |
| 153 if (!parsed) | |
| 154 return NULL; | |
| 155 // TODO(mmenke): Open source related protocol buffers and use them directly. | |
| 156 base::DictionaryValue* parsed_dict; | |
| 157 base::ListValue* corrections; | |
| 158 if (!parsed->GetAsDictionary(&parsed_dict)) | |
| 159 return NULL; | |
| 160 if (!parsed_dict->GetList("result.UrlCorrections", &corrections)) | |
| 161 return NULL; | |
| 162 | |
| 163 // Version of URL for display in suggestions. It has to be sanitized first | |
| 164 // because any received suggestions will be relative to the sanitized URL. | |
| 165 base::string16 original_url_for_display = | |
| 166 FormatURLForDisplay(SanitizeURL(original_url), is_rtl, accept_languages); | |
| 167 | |
| 168 scoped_ptr<LocalizedError::ErrorPageParams> params( | |
| 169 new LocalizedError::ErrorPageParams()); | |
| 170 params->override_suggestions.reset(new base::ListValue()); | |
| 171 scoped_ptr<base::ListValue> parsed_corrections(new base::ListValue()); | |
| 172 for (base::ListValue::iterator it = corrections->begin(); | |
| 173 it != corrections->end(); ++it) { | |
| 174 base::DictionaryValue* correction; | |
| 175 if (!(*it)->GetAsDictionary(&correction)) | |
| 176 continue; | |
| 177 | |
| 178 // Doesn't seem like a good idea to show these. | |
|
Deprecated (see juliatuttle)
2014/02/04 17:44:21
What if that's what the user was looking for? (Is
mmenke
2014/02/04 19:43:56
In my experience, FixURL isn't really that clever.
Deprecated (see juliatuttle)
2014/02/04 20:20:20
Alright. I'll tinker with it and see how clever i
mmenke
2014/02/04 20:31:09
May also want to see if we're already excluding po
| |
| 179 bool is_porn; | |
| 180 if (correction->GetBoolean("isPorn", &is_porn) && is_porn) | |
| 181 continue; | |
| 182 if (correction->GetBoolean("isSoftPorn", &is_porn) && is_porn) | |
| 183 continue; | |
| 184 | |
| 185 std::string correction_type; | |
| 186 std::string url_correction; | |
| 187 if (!correction->GetString("correctionType", &correction_type) || | |
| 188 !correction->GetString("urlCorrection", &url_correction)) { | |
| 189 continue; | |
| 190 } | |
| 191 | |
| 192 std::string click_tracking_url; | |
| 193 correction->GetString("clickTrackingUrl", &click_tracking_url); | |
| 194 | |
| 195 if (correction_type == "reloadPage") { | |
| 196 params->suggest_reload = true; | |
| 197 continue; | |
| 198 } | |
| 199 | |
| 200 if (correction_type == "webSearchQuery") { | |
| 201 // If there are mutliple searches suggested, use the first suggestion. | |
| 202 if (params->search_terms.empty()) { | |
| 203 params->search_url = search_url; | |
| 204 params->search_terms = url_correction; | |
| 205 } | |
| 206 continue; | |
| 207 } | |
| 208 | |
| 209 size_t correction_index; | |
| 210 for (correction_index = 0; | |
| 211 correction_index < arraysize(kCorrectionResourceTable); | |
| 212 ++correction_index) { | |
| 213 if (correction_type != | |
| 214 kCorrectionResourceTable[correction_index].correction_type) { | |
| 215 continue; | |
| 216 } | |
| 217 base::DictionaryValue* suggest = new base::DictionaryValue(); | |
| 218 suggest->SetString("header", | |
| 219 l10n_util::GetStringUTF16( | |
| 220 kCorrectionResourceTable[correction_index].resource_id)); | |
| 221 suggest->SetString("urlCorrection", | |
| 222 !click_tracking_url.empty() ? click_tracking_url : | |
| 223 url_correction); | |
| 224 suggest->SetString( | |
| 225 "urlCorrectionForDisplay", | |
| 226 FormatURLForDisplay(GURL(url_correction), is_rtl, accept_languages)); | |
| 227 suggest->SetString("originalUrlForDisplay", original_url_for_display); | |
| 228 params->override_suggestions->Append(suggest); | |
| 229 break; | |
| 230 } | |
| 231 } | |
| 232 | |
| 233 if (params->override_suggestions->empty() && | |
| 234 !params->search_url.is_valid()) { | |
| 235 return NULL; | |
| 236 } | |
| 237 return params.release(); | |
| 238 } | |
| 239 | |
| 88 } // namespace | 240 } // namespace |
| 89 | 241 |
| 90 struct NetErrorHelperCore::ErrorPageInfo { | 242 struct NetErrorHelperCore::ErrorPageInfo { |
| 91 ErrorPageInfo(blink::WebURLError error, bool was_failed_post) | 243 ErrorPageInfo(blink::WebURLError error, bool was_failed_post) |
| 92 : error(error), | 244 : error(error), |
| 93 was_failed_post(was_failed_post), | 245 was_failed_post(was_failed_post), |
| 94 needs_dns_updates(false), | 246 needs_dns_updates(false), |
| 95 is_finished_loading(false) { | 247 is_finished_loading(false) { |
| 96 } | 248 } |
| 97 | 249 |
| 98 // Information about the failed page load. | 250 // Information about the failed page load. |
| 99 blink::WebURLError error; | 251 blink::WebURLError error; |
| 100 bool was_failed_post; | 252 bool was_failed_post; |
| 101 | 253 |
| 102 // Information about the status of the error page. | 254 // Information about the status of the error page. |
| 103 | 255 |
| 104 // True if a page is a DNS error page and has not yet received a final DNS | 256 // True if a page is a DNS error page and has not yet received a final DNS |
| 105 // probe status. | 257 // probe status. |
| 106 bool needs_dns_updates; | 258 bool needs_dns_updates; |
| 107 | 259 |
| 108 // URL of an alternate error page to repace this error page with, if it's a | 260 // 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. | 261 // 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 | 262 // NetErrorHelperCore itself, but it stored here as well in case its modified |
| 111 // for tests to wait for. | 263 // in the middle of an error page load. Empty when no error page should be |
| 112 GURL alternate_error_page_url; | 264 // fetched, or if there's already a fetch in progress. |
| 265 GURL link_doctor_url; | |
| 266 | |
| 267 // Request body to use when requesting suggestions from the FixURL service. | |
| 268 // TODO(mmenke): Investigate loading the error page at the same time as | |
| 269 // the blank page is loading, to get rid of these. | |
| 270 std::string link_doctor_request_body; | |
| 113 | 271 |
| 114 // True if a page has completed loading, at which point it can receive | 272 // True if a page has completed loading, at which point it can receive |
| 115 // updates. | 273 // updates. |
| 116 bool is_finished_loading; | 274 bool is_finished_loading; |
| 117 }; | 275 }; |
| 118 | 276 |
| 119 NetErrorHelperCore::NetErrorHelperCore(Delegate* delegate) | 277 NetErrorHelperCore::NetErrorHelperCore(Delegate* delegate) |
| 120 : delegate_(delegate), | 278 : delegate_(delegate), |
| 121 last_probe_status_(chrome_common_net::DNS_PROBE_POSSIBLE) { | 279 last_probe_status_(chrome_common_net::DNS_PROBE_POSSIBLE) { |
| 122 } | 280 } |
| 123 | 281 |
| 124 NetErrorHelperCore::~NetErrorHelperCore() { | 282 NetErrorHelperCore::~NetErrorHelperCore() { |
| 125 } | 283 } |
| 126 | 284 |
| 127 void NetErrorHelperCore::OnStop() { | 285 void NetErrorHelperCore::OnStop() { |
| 128 // On stop, cancel loading the alternate error page, and prevent any pending | 286 // On stop, cancel loading the alternate error page, and prevent any pending |
| 129 // error page load from starting a new error page load. Swapping in the error | 287 // error page load from starting a new error page load. Swapping in the error |
| 130 // page when it's finished loading could abort the navigation, otherwise. | 288 // page when it's finished loading could abort the navigation, otherwise. |
| 131 if (committed_error_page_info_) | 289 if (committed_error_page_info_) { |
| 132 committed_error_page_info_->alternate_error_page_url = GURL(); | 290 committed_error_page_info_->link_doctor_url = GURL(); |
| 133 if (pending_error_page_info_) | 291 committed_error_page_info_->link_doctor_request_body.clear(); |
| 134 pending_error_page_info_->alternate_error_page_url = GURL(); | 292 } |
| 293 if (pending_error_page_info_) { | |
| 294 pending_error_page_info_->link_doctor_url = GURL(); | |
| 295 pending_error_page_info_->link_doctor_request_body.clear(); | |
| 296 } | |
| 135 delegate_->CancelFetchErrorPage(); | 297 delegate_->CancelFetchErrorPage(); |
| 136 } | 298 } |
| 137 | 299 |
| 138 void NetErrorHelperCore::OnStartLoad(FrameType frame_type, PageType page_type) { | 300 void NetErrorHelperCore::OnStartLoad(FrameType frame_type, PageType page_type) { |
| 139 if (frame_type != MAIN_FRAME) | 301 if (frame_type != MAIN_FRAME) |
| 140 return; | 302 return; |
| 141 | 303 |
| 142 // If there's no pending error page information associated with the page load, | 304 // 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. | 305 // 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) { | 306 if (!pending_error_page_info_ || page_type != ERROR_PAGE) { |
| 145 OnStop(); | 307 OnStop(); |
| 146 } | 308 } |
| 147 } | 309 } |
| 148 | 310 |
| 149 void NetErrorHelperCore::OnCommitLoad(FrameType frame_type) { | 311 void NetErrorHelperCore::OnCommitLoad(FrameType frame_type) { |
| 150 if (frame_type != MAIN_FRAME) | 312 if (frame_type != MAIN_FRAME) |
| 151 return; | 313 return; |
| 152 | 314 |
| 153 committed_error_page_info_.reset(pending_error_page_info_.release()); | 315 committed_error_page_info_.reset(pending_error_page_info_.release()); |
| 154 } | 316 } |
| 155 | 317 |
| 156 void NetErrorHelperCore::OnFinishLoad(FrameType frame_type) { | 318 void NetErrorHelperCore::OnFinishLoad(FrameType frame_type) { |
| 157 if (frame_type != MAIN_FRAME || !committed_error_page_info_) | 319 if (frame_type != MAIN_FRAME || !committed_error_page_info_) |
| 158 return; | 320 return; |
| 159 | 321 |
| 160 committed_error_page_info_->is_finished_loading = true; | 322 committed_error_page_info_->is_finished_loading = true; |
| 161 | 323 |
| 162 if (committed_error_page_info_->alternate_error_page_url.is_valid()) { | 324 if (committed_error_page_info_->link_doctor_url.is_valid()) { |
| 163 // If there is another pending error page load, | 325 // 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. | 326 // cleared. |
| 165 DCHECK(!pending_error_page_info_); | 327 DCHECK(!pending_error_page_info_); |
| 166 DCHECK(!committed_error_page_info_->needs_dns_updates); | 328 DCHECK(!committed_error_page_info_->needs_dns_updates); |
| 167 GURL error_page_url; | |
| 168 delegate_->FetchErrorPage( | 329 delegate_->FetchErrorPage( |
| 169 committed_error_page_info_->alternate_error_page_url); | 330 committed_error_page_info_->link_doctor_url, |
| 331 committed_error_page_info_->link_doctor_request_body); | |
| 170 } | 332 } |
| 171 | 333 |
| 172 if (!committed_error_page_info_->needs_dns_updates || | 334 if (!committed_error_page_info_->needs_dns_updates || |
| 173 last_probe_status_ == chrome_common_net::DNS_PROBE_POSSIBLE) { | 335 last_probe_status_ == chrome_common_net::DNS_PROBE_POSSIBLE) { |
| 174 return; | 336 return; |
| 175 } | 337 } |
| 176 DVLOG(1) << "Error page finished loading; sending saved status."; | 338 DVLOG(1) << "Error page finished loading; sending saved status."; |
| 177 UpdateErrorPage(); | 339 UpdateErrorPage(); |
| 178 } | 340 } |
| 179 | 341 |
| 180 void NetErrorHelperCore::GetErrorHTML( | 342 void NetErrorHelperCore::GetErrorHTML( |
| 181 FrameType frame_type, | 343 FrameType frame_type, |
| 182 const blink::WebURLError& error, | 344 const blink::WebURLError& error, |
| 183 bool is_failed_post, | 345 bool is_failed_post, |
| 184 std::string* error_html) { | 346 std::string* error_html) { |
| 185 if (frame_type == MAIN_FRAME) { | 347 if (frame_type == MAIN_FRAME) { |
| 186 // If an alternate error page was going to be fetched, that should have been | 348 // If an alternate error page was going to be fetched, that should have been |
| 187 // cancelled by loading a new page load (Which has now failed to load). | 349 // cancelled by loading a new page load (Which has now failed to load). |
| 188 DCHECK(!committed_error_page_info_ || | 350 DCHECK(!committed_error_page_info_ || |
| 189 !committed_error_page_info_->alternate_error_page_url.is_valid()); | 351 !committed_error_page_info_->link_doctor_url.is_valid()); |
| 352 | |
| 353 std::string link_doctor_request_body; | |
| 354 | |
| 355 if (link_doctor_url_.is_valid() && | |
| 356 GetFixUrlRequestBody(error, language_, country_code_, api_key_, | |
| 357 &link_doctor_request_body)) { | |
| 358 pending_error_page_info_.reset(new ErrorPageInfo(error, is_failed_post)); | |
| 359 pending_error_page_info_->link_doctor_url = link_doctor_url_; | |
| 360 pending_error_page_info_->link_doctor_request_body = | |
| 361 link_doctor_request_body; | |
| 362 return; | |
| 363 } | |
| 190 | 364 |
| 191 // The last probe status needs to be reset if this is a DNS error. This | 365 // 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 | 366 // 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 | 367 // 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 | 368 // 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. | 369 // will just get the results for the next page load. |
| 196 if (IsDnsError(error)) | 370 if (IsDnsError(error)) |
| 197 last_probe_status_ = chrome_common_net::DNS_PROBE_POSSIBLE; | 371 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 } | 372 } |
| 206 | 373 |
| 207 GenerateLocalErrorPage(frame_type, error, is_failed_post, error_html); | 374 GenerateLocalErrorPage(frame_type, error, is_failed_post, |
| 375 scoped_ptr<LocalizedError::ErrorPageParams>(), | |
| 376 error_html); | |
| 208 } | 377 } |
| 209 | 378 |
| 210 void NetErrorHelperCore::GenerateLocalErrorPage( | 379 void NetErrorHelperCore::GenerateLocalErrorPage( |
| 211 FrameType frame_type, | 380 FrameType frame_type, |
| 212 const blink::WebURLError& error, | 381 const blink::WebURLError& error, |
| 213 bool is_failed_post, | 382 bool is_failed_post, |
| 383 scoped_ptr<LocalizedError::ErrorPageParams> params, | |
| 214 std::string* error_html) { | 384 std::string* error_html) { |
| 215 if (frame_type == MAIN_FRAME) { | 385 if (frame_type == MAIN_FRAME) { |
| 216 pending_error_page_info_.reset(new ErrorPageInfo(error, is_failed_post)); | 386 pending_error_page_info_.reset(new ErrorPageInfo(error, is_failed_post)); |
| 217 if (IsDnsError(error)) { | 387 // Skip DNS logic if suggestions were received from a remote server. |
| 388 // TODO(mmenke): Consider integrating probe results with Link Doctor | |
| 389 // suggestions. | |
| 390 if (IsDnsError(error) && !params) { | |
| 218 // This is not strictly necessary, but waiting for a new status to be | 391 // 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 | 392 // sent as a result of the DidFinishLoading call keeps the histograms |
| 220 // consistent with older versions of the code, at no real cost. | 393 // consistent with older versions of the code, at no real cost. |
| 221 last_probe_status_ = chrome_common_net::DNS_PROBE_POSSIBLE; | 394 last_probe_status_ = chrome_common_net::DNS_PROBE_POSSIBLE; |
| 222 | 395 |
| 223 delegate_->GenerateLocalizedErrorPage( | 396 delegate_->GenerateLocalizedErrorPage( |
| 224 GetUpdatedError(error), is_failed_post, error_html); | 397 GetUpdatedError(error), is_failed_post, params.Pass(), |
| 398 error_html); | |
| 225 pending_error_page_info_->needs_dns_updates = true; | 399 pending_error_page_info_->needs_dns_updates = true; |
| 226 return; | 400 return; |
| 227 } | 401 } |
| 228 } | 402 } |
| 229 delegate_->GenerateLocalizedErrorPage(error, is_failed_post, error_html); | 403 |
| 404 delegate_->GenerateLocalizedErrorPage(error, is_failed_post, | |
| 405 params.Pass(), error_html); | |
| 230 } | 406 } |
| 231 | 407 |
| 232 void NetErrorHelperCore::OnNetErrorInfo( | 408 void NetErrorHelperCore::OnNetErrorInfo( |
| 233 chrome_common_net::DnsProbeStatus status) { | 409 chrome_common_net::DnsProbeStatus status) { |
| 234 DCHECK_NE(chrome_common_net::DNS_PROBE_POSSIBLE, status); | 410 DCHECK_NE(chrome_common_net::DNS_PROBE_POSSIBLE, status); |
| 235 | 411 |
| 236 last_probe_status_ = status; | 412 last_probe_status_ = status; |
| 237 | 413 |
| 238 if (!committed_error_page_info_ || | 414 if (!committed_error_page_info_ || |
| 239 !committed_error_page_info_->needs_dns_updates || | 415 !committed_error_page_info_->needs_dns_updates || |
| 240 !committed_error_page_info_->is_finished_loading) { | 416 !committed_error_page_info_->is_finished_loading) { |
| 241 return; | 417 return; |
| 242 } | 418 } |
| 243 | 419 |
| 244 UpdateErrorPage(); | 420 UpdateErrorPage(); |
| 245 } | 421 } |
| 246 | 422 |
| 423 void NetErrorHelperCore::OnSetLinkDoctorInfo(const GURL& link_doctor_url, | |
| 424 const std::string& language, | |
| 425 const std::string& country_code, | |
| 426 const std::string& api_key, | |
| 427 const GURL& search_url) { | |
| 428 link_doctor_url_ = link_doctor_url; | |
| 429 language_ = language; | |
| 430 country_code_ = country_code; | |
| 431 api_key_ = api_key; | |
| 432 search_url_ = search_url; | |
| 433 } | |
| 434 | |
| 247 void NetErrorHelperCore::UpdateErrorPage() { | 435 void NetErrorHelperCore::UpdateErrorPage() { |
| 248 DCHECK(committed_error_page_info_->needs_dns_updates); | 436 DCHECK(committed_error_page_info_->needs_dns_updates); |
| 249 DCHECK(committed_error_page_info_->is_finished_loading); | 437 DCHECK(committed_error_page_info_->is_finished_loading); |
| 250 DCHECK_NE(chrome_common_net::DNS_PROBE_POSSIBLE, last_probe_status_); | 438 DCHECK_NE(chrome_common_net::DNS_PROBE_POSSIBLE, last_probe_status_); |
| 251 | 439 |
| 252 UMA_HISTOGRAM_ENUMERATION("DnsProbe.ErrorPageUpdateStatus", | 440 UMA_HISTOGRAM_ENUMERATION("DnsProbe.ErrorPageUpdateStatus", |
| 253 last_probe_status_, | 441 last_probe_status_, |
| 254 chrome_common_net::DNS_PROBE_MAX); | 442 chrome_common_net::DNS_PROBE_MAX); |
| 255 // Every status other than DNS_PROBE_POSSIBLE and DNS_PROBE_STARTED is a | 443 // 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 | 444 // final status code. Once one is reached, the page does not need further |
| 257 // updates. | 445 // updates. |
| 258 if (last_probe_status_ != chrome_common_net::DNS_PROBE_STARTED) | 446 if (last_probe_status_ != chrome_common_net::DNS_PROBE_STARTED) |
| 259 committed_error_page_info_->needs_dns_updates = false; | 447 committed_error_page_info_->needs_dns_updates = false; |
| 260 | 448 |
| 261 delegate_->UpdateErrorPage( | 449 delegate_->UpdateErrorPage( |
| 262 GetUpdatedError(committed_error_page_info_->error), | 450 GetUpdatedError(committed_error_page_info_->error), |
| 263 committed_error_page_info_->was_failed_post); | 451 committed_error_page_info_->was_failed_post); |
| 264 } | 452 } |
| 265 | 453 |
| 266 void NetErrorHelperCore::OnAlternateErrorPageFetched(const std::string& data) { | 454 void NetErrorHelperCore::OnAlternateErrorPageFetched( |
| 455 const std::string& data, const std::string& accept_languages, bool is_rtl) { | |
| 267 // Alternate error page load only starts when an error page finishes loading, | 456 // Alternate error page load only starts when an error page finishes loading, |
| 268 // and is cancelled with a new load | 457 // and is cancelled with a new load. |
| 269 DCHECK(!pending_error_page_info_); | 458 DCHECK(!pending_error_page_info_); |
| 270 DCHECK(committed_error_page_info_->is_finished_loading); | 459 DCHECK(committed_error_page_info_->is_finished_loading); |
| 271 | 460 |
| 272 const std::string* error_html = NULL; | 461 scoped_ptr<LocalizedError::ErrorPageParams> params( |
| 273 std::string generated_html; | 462 ParseAdditionalSuggestions( |
| 274 if (!data.empty()) { | 463 data, GURL(committed_error_page_info_->error.unreachableURL), |
| 275 // If the request succeeded, use the response in place of a generated error | 464 search_url_, accept_languages, is_rtl)); |
| 276 // page. | 465 std::string error_html; |
| 277 pending_error_page_info_.reset( | 466 GenerateLocalErrorPage(MAIN_FRAME, |
| 278 new ErrorPageInfo(committed_error_page_info_->error, | 467 committed_error_page_info_->error, |
| 279 committed_error_page_info_->was_failed_post)); | 468 committed_error_page_info_->was_failed_post, |
| 280 error_html = &data; | 469 params.Pass(), |
| 281 } else { | 470 &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 | 471 |
| 291 // |error_page_info| may have been destroyed by this point, since | 472 // |error_page_info| may have been destroyed by this point, since |
| 292 // |pending_error_page_info_| was set to a new ErrorPageInfo. | 473 // |pending_error_page_info_| was set to a new ErrorPageInfo. |
| 293 | 474 |
| 294 // TODO(mmenke): Once the new API is in place, look into replacing this | 475 // 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 | 476 // double page load by just updating the error page, like DNS |
| 296 // probes do. | 477 // probes do. |
| 297 delegate_->LoadErrorPageInMainFrame( | 478 delegate_->LoadErrorPageInMainFrame( |
| 298 *error_html, | 479 error_html, |
| 299 pending_error_page_info_->error.unreachableURL); | 480 pending_error_page_info_->error.unreachableURL); |
| 300 } | 481 } |
| 301 | 482 |
| 302 blink::WebURLError NetErrorHelperCore::GetUpdatedError( | 483 blink::WebURLError NetErrorHelperCore::GetUpdatedError( |
| 303 const blink::WebURLError& error) const { | 484 const blink::WebURLError& error) const { |
| 304 // If a probe didn't run or wasn't conclusive, restore the original error. | 485 // 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 || | 486 if (last_probe_status_ == chrome_common_net::DNS_PROBE_NOT_RUN || |
| 306 last_probe_status_ == | 487 last_probe_status_ == |
| 307 chrome_common_net::DNS_PROBE_FINISHED_INCONCLUSIVE) { | 488 chrome_common_net::DNS_PROBE_FINISHED_INCONCLUSIVE) { |
| 308 return error; | 489 return error; |
| 309 } | 490 } |
| 310 | 491 |
| 311 blink::WebURLError updated_error; | 492 blink::WebURLError updated_error; |
| 312 updated_error.domain = blink::WebString::fromUTF8( | 493 updated_error.domain = blink::WebString::fromUTF8( |
| 313 chrome_common_net::kDnsProbeErrorDomain); | 494 chrome_common_net::kDnsProbeErrorDomain); |
| 314 updated_error.reason = last_probe_status_; | 495 updated_error.reason = last_probe_status_; |
| 315 updated_error.unreachableURL = error.unreachableURL; | 496 updated_error.unreachableURL = error.unreachableURL; |
| 316 | 497 |
| 317 return updated_error; | 498 return updated_error; |
| 318 } | 499 } |
| OLD | NEW |