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 |