1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/common/localized_error.h" 6 7 #include "base/i18n/rtl.h" 8 #include "base/logging.h" 9 #include "base/strings/string16.h" 10 #include "base/strings/string_number_conversions.h" 11 #include "base/strings/string_util.h" 12 #include "base/strings/utf_string_conversions.h" 13 #include "base/values.h" 14 #include "chrome/common/net/net_error_info.h" 15 #include "chrome/grit/chromium_strings.h" 16 #include "chrome/grit/generated_resources.h" 17 #include "extensions/common/constants.h" 18 #include "extensions/common/extension_icon_set.h" 19 #include "extensions/common/manifest_handlers/icons_handler.h" 20 #include "net/base/escape.h" 21 #include "net/base/net_errors.h" 22 #include "net/base/net_util.h" 23 #include "third_party/WebKit/public/platform/WebURLError.h" 24 #include "ui/base/l10n/l10n_util.h" 25 #include "ui/base/webui/web_ui_util.h" 26 27 #if defined(OS_WIN) 28 #include "base/win/windows_version.h" 29 #endif 30 31 using blink::WebURLError; 32 33 // Some error pages have no details. 34 const unsigned int kErrorPagesNoDetails = 0; 35 36 namespace { 37 38 static const char kRedirectLoopLearnMoreUrl[] = 39 "https://www.google.com/support/chrome/bin/answer.py?answer=95626"; 40 static const char kWeakDHKeyLearnMoreUrl[] = 41 "http://sites.google.com/a/chromium.org/dev/" 42 "err_ssl_weak_server_ephemeral_dh_key"; 43 #if defined(OS_CHROMEOS) 44 static const char kAppWarningLearnMoreUrl[] = 45 "chrome-extension://honijodknafkokifofgiaalefdiedpko/main.html" 46 "?answer=1721911"; 47 #endif // defined(OS_CHROMEOS) 48 49 enum NAV_SUGGESTIONS { 50 SUGGEST_NONE = 0, 51 SUGGEST_RELOAD = 1 << 0, 52 SUGGEST_CHECK_CONNECTION = 1 << 1, 53 SUGGEST_DNS_CONFIG = 1 << 2, 54 SUGGEST_FIREWALL_CONFIG = 1 << 3, 55 SUGGEST_PROXY_CONFIG = 1 << 4, 56 SUGGEST_DISABLE_EXTENSION = 1 << 5, 57 SUGGEST_LEARNMORE = 1 << 6, 58 SUGGEST_VIEW_POLICIES = 1 << 7, 59 SUGGEST_CONTACT_ADMINISTRATOR = 1 << 8, 60 }; 61 62 struct LocalizedErrorMap { 63 int error_code; 64 unsigned int title_resource_id; 65 unsigned int heading_resource_id; 66 // Detailed summary used when the error is in the main frame. 67 unsigned int summary_resource_id; 68 // Short one sentence description shown on mouse over when the error is in 69 // a frame. 70 unsigned int details_resource_id; 71 int suggestions; // Bitmap of SUGGEST_* values. 72 }; 73 74 const LocalizedErrorMap net_error_options[] = { 75 {net::ERR_TIMED_OUT, 76 IDS_ERRORPAGES_TITLE_NOT_AVAILABLE, 77 IDS_ERRORPAGES_HEADING_NOT_AVAILABLE, 78 IDS_ERRORPAGES_SUMMARY_TIMED_OUT, 79 IDS_ERRORPAGES_DETAILS_TIMED_OUT, 80 SUGGEST_RELOAD | SUGGEST_CHECK_CONNECTION | SUGGEST_FIREWALL_CONFIG | 81 SUGGEST_PROXY_CONFIG, 82 }, 83 {net::ERR_CONNECTION_TIMED_OUT, 84 IDS_ERRORPAGES_TITLE_NOT_AVAILABLE, 85 IDS_ERRORPAGES_HEADING_NOT_AVAILABLE, 86 IDS_ERRORPAGES_SUMMARY_TIMED_OUT, 87 IDS_ERRORPAGES_DETAILS_TIMED_OUT, 88 SUGGEST_RELOAD | SUGGEST_CHECK_CONNECTION | SUGGEST_FIREWALL_CONFIG | 89 SUGGEST_PROXY_CONFIG, 90 }, 91 {net::ERR_CONNECTION_CLOSED, 92 IDS_ERRORPAGES_TITLE_NOT_AVAILABLE, 93 IDS_ERRORPAGES_HEADING_NOT_AVAILABLE, 94 IDS_ERRORPAGES_SUMMARY_NOT_AVAILABLE, 95 IDS_ERRORPAGES_DETAILS_CONNECTION_CLOSED, 96 SUGGEST_RELOAD, 97 }, 98 {net::ERR_CONNECTION_RESET, 99 IDS_ERRORPAGES_TITLE_NOT_AVAILABLE, 100 IDS_ERRORPAGES_HEADING_NOT_AVAILABLE, 101 IDS_ERRORPAGES_SUMMARY_CONNECTION_RESET, 102 IDS_ERRORPAGES_DETAILS_CONNECTION_RESET, 103 SUGGEST_RELOAD | SUGGEST_CHECK_CONNECTION | SUGGEST_FIREWALL_CONFIG | 104 SUGGEST_PROXY_CONFIG, 105 }, 106 {net::ERR_CONNECTION_REFUSED, 107 IDS_ERRORPAGES_TITLE_NOT_AVAILABLE, 108 IDS_ERRORPAGES_HEADING_NOT_AVAILABLE, 109 IDS_ERRORPAGES_SUMMARY_CONNECTION_REFUSED, 110 IDS_ERRORPAGES_DETAILS_CONNECTION_REFUSED, 111 SUGGEST_RELOAD | SUGGEST_CHECK_CONNECTION | SUGGEST_FIREWALL_CONFIG | 112 SUGGEST_PROXY_CONFIG, 113 }, 114 {net::ERR_CONNECTION_FAILED, 115 IDS_ERRORPAGES_TITLE_NOT_AVAILABLE, 116 IDS_ERRORPAGES_HEADING_NOT_AVAILABLE, 117 IDS_ERRORPAGES_SUMMARY_NOT_AVAILABLE, 118 IDS_ERRORPAGES_DETAILS_CONNECTION_FAILED, 119 SUGGEST_RELOAD, 120 }, 121 {net::ERR_NAME_NOT_RESOLVED, 122 IDS_ERRORPAGES_TITLE_NOT_AVAILABLE, 123 IDS_ERRORPAGES_HEADING_NOT_AVAILABLE, 124 IDS_ERRORPAGES_SUMMARY_NAME_NOT_RESOLVED, 125 IDS_ERRORPAGES_DETAILS_NAME_NOT_RESOLVED, 126 SUGGEST_RELOAD | SUGGEST_CHECK_CONNECTION | SUGGEST_DNS_CONFIG | 127 SUGGEST_FIREWALL_CONFIG | SUGGEST_PROXY_CONFIG, 128 }, 129 {net::ERR_ADDRESS_UNREACHABLE, 130 IDS_ERRORPAGES_TITLE_NOT_AVAILABLE, 131 IDS_ERRORPAGES_HEADING_NOT_AVAILABLE, 132 IDS_ERRORPAGES_SUMMARY_ADDRESS_UNREACHABLE, 133 IDS_ERRORPAGES_DETAILS_ADDRESS_UNREACHABLE, 134 SUGGEST_RELOAD | SUGGEST_FIREWALL_CONFIG | SUGGEST_PROXY_CONFIG, 135 }, 136 {net::ERR_NETWORK_ACCESS_DENIED, 137 IDS_ERRORPAGES_TITLE_NOT_AVAILABLE, 138 IDS_ERRORPAGES_HEADING_NETWORK_ACCESS_DENIED, 139 IDS_ERRORPAGES_SUMMARY_NETWORK_ACCESS_DENIED, 140 IDS_ERRORPAGES_DETAILS_NETWORK_ACCESS_DENIED, 141 SUGGEST_FIREWALL_CONFIG, 142 }, 143 {net::ERR_PROXY_CONNECTION_FAILED, 144 IDS_ERRORPAGES_TITLE_NOT_AVAILABLE, 145 IDS_ERRORPAGES_HEADING_PROXY_CONNECTION_FAILED, 146 IDS_ERRORPAGES_SUMMARY_PROXY_CONNECTION_FAILED, 147 IDS_ERRORPAGES_DETAILS_PROXY_CONNECTION_FAILED, 148 SUGGEST_PROXY_CONFIG, 149 }, 150 {net::ERR_INTERNET_DISCONNECTED, 151 IDS_ERRORPAGES_TITLE_NOT_AVAILABLE, 152 IDS_ERRORPAGES_HEADING_INTERNET_DISCONNECTED, 153 IDS_ERRORPAGES_SUMMARY_INTERNET_DISCONNECTED, 154 IDS_ERRORPAGES_DETAILS_INTERNET_DISCONNECTED, 155 SUGGEST_NONE, 156 }, 157 {net::ERR_FILE_NOT_FOUND, 158 IDS_ERRORPAGES_TITLE_NOT_FOUND, 159 IDS_ERRORPAGES_HEADING_NOT_FOUND, 160 IDS_ERRORPAGES_SUMMARY_NOT_FOUND, 161 IDS_ERRORPAGES_DETAILS_FILE_NOT_FOUND, 162 SUGGEST_NONE, 163 }, 164 {net::ERR_CACHE_MISS, 165 IDS_ERRORPAGES_TITLE_LOAD_FAILED, 166 IDS_ERRORPAGES_HEADING_CACHE_MISS, 167 IDS_ERRORPAGES_SUMMARY_CACHE_MISS, 168 IDS_ERRORPAGES_DETAILS_CACHE_MISS, 169 SUGGEST_RELOAD, 170 }, 171 {net::ERR_CACHE_READ_FAILURE, 172 IDS_ERRORPAGES_TITLE_LOAD_FAILED, 173 IDS_ERRORPAGES_HEADING_CACHE_READ_FAILURE, 174 IDS_ERRORPAGES_SUMMARY_CACHE_READ_FAILURE, 175 IDS_ERRORPAGES_DETAILS_CACHE_READ_FAILURE, 176 SUGGEST_RELOAD, 177 }, 178 {net::ERR_NETWORK_IO_SUSPENDED, 179 IDS_ERRORPAGES_TITLE_LOAD_FAILED, 180 IDS_ERRORPAGES_HEADING_NETWORK_IO_SUSPENDED, 181 IDS_ERRORPAGES_SUMMARY_NETWORK_IO_SUSPENDED, 182 IDS_ERRORPAGES_DETAILS_NETWORK_IO_SUSPENDED, 183 SUGGEST_RELOAD, 184 }, 185 {net::ERR_TOO_MANY_REDIRECTS, 186 IDS_ERRORPAGES_TITLE_LOAD_FAILED, 187 IDS_ERRORPAGES_HEADING_TOO_MANY_REDIRECTS, 188 IDS_ERRORPAGES_SUMMARY_TOO_MANY_REDIRECTS, 189 IDS_ERRORPAGES_DETAILS_TOO_MANY_REDIRECTS, 190 SUGGEST_RELOAD | SUGGEST_LEARNMORE, 191 }, 192 {net::ERR_EMPTY_RESPONSE, 193 IDS_ERRORPAGES_TITLE_LOAD_FAILED, 194 IDS_ERRORPAGES_HEADING_EMPTY_RESPONSE, 195 IDS_ERRORPAGES_SUMMARY_EMPTY_RESPONSE, 196 IDS_ERRORPAGES_DETAILS_EMPTY_RESPONSE, 197 SUGGEST_RELOAD, 198 }, 199 {net::ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH, 200 IDS_ERRORPAGES_TITLE_LOAD_FAILED, 201 IDS_ERRORPAGES_HEADING_DUPLICATE_HEADERS, 202 IDS_ERRORPAGES_SUMMARY_DUPLICATE_HEADERS, 203 IDS_ERRORPAGES_DETAILS_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH, 204 SUGGEST_NONE, 205 }, 206 {net::ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION, 207 IDS_ERRORPAGES_TITLE_LOAD_FAILED, 208 IDS_ERRORPAGES_HEADING_DUPLICATE_HEADERS, 209 IDS_ERRORPAGES_SUMMARY_DUPLICATE_HEADERS, 210 IDS_ERRORPAGES_DETAILS_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION, 211 SUGGEST_NONE, 212 }, 213 {net::ERR_RESPONSE_HEADERS_MULTIPLE_LOCATION, 214 IDS_ERRORPAGES_TITLE_LOAD_FAILED, 215 IDS_ERRORPAGES_HEADING_DUPLICATE_HEADERS, 216 IDS_ERRORPAGES_SUMMARY_DUPLICATE_HEADERS, 217 IDS_ERRORPAGES_DETAILS_RESPONSE_HEADERS_MULTIPLE_LOCATION, 218 SUGGEST_NONE, 219 }, 220 {net::ERR_CONTENT_LENGTH_MISMATCH, 221 IDS_ERRORPAGES_TITLE_NOT_AVAILABLE, 222 IDS_ERRORPAGES_HEADING_NOT_AVAILABLE, 223 IDS_ERRORPAGES_SUMMARY_NOT_AVAILABLE, 224 IDS_ERRORPAGES_DETAILS_CONNECTION_CLOSED, 225 SUGGEST_RELOAD, 226 }, 227 {net::ERR_INCOMPLETE_CHUNKED_ENCODING, 228 IDS_ERRORPAGES_TITLE_NOT_AVAILABLE, 229 IDS_ERRORPAGES_HEADING_NOT_AVAILABLE, 230 IDS_ERRORPAGES_SUMMARY_NOT_AVAILABLE, 231 IDS_ERRORPAGES_DETAILS_CONNECTION_CLOSED, 232 SUGGEST_RELOAD, 233 }, 234 {net::ERR_SSL_PROTOCOL_ERROR, 235 IDS_ERRORPAGES_TITLE_LOAD_FAILED, 236 IDS_ERRORPAGES_HEADING_SSL_PROTOCOL_ERROR, 237 IDS_ERRORPAGES_SUMMARY_SSL_PROTOCOL_ERROR, 238 IDS_ERRORPAGES_DETAILS_SSL_PROTOCOL_ERROR, 239 SUGGEST_NONE, 240 }, 241 {net::ERR_SSL_UNSAFE_NEGOTIATION, 242 IDS_ERRORPAGES_TITLE_LOAD_FAILED, 243 IDS_ERRORPAGES_HEADING_SSL_PROTOCOL_ERROR, 244 IDS_ERRORPAGES_SUMMARY_SSL_PROTOCOL_ERROR, 245 IDS_ERRORPAGES_DETAILS_SSL_UNSAFE_NEGOTIATION, 246 SUGGEST_NONE, 247 }, 248 {net::ERR_BAD_SSL_CLIENT_AUTH_CERT, 249 IDS_ERRORPAGES_TITLE_LOAD_FAILED, 250 IDS_ERRORPAGES_HEADING_BAD_SSL_CLIENT_AUTH_CERT, 251 IDS_ERRORPAGES_SUMMARY_BAD_SSL_CLIENT_AUTH_CERT, 252 IDS_ERRORPAGES_DETAILS_BAD_SSL_CLIENT_AUTH_CERT, 253 SUGGEST_NONE, 254 }, 255 {net::ERR_SSL_WEAK_SERVER_EPHEMERAL_DH_KEY, 256 IDS_ERRORPAGES_TITLE_LOAD_FAILED, 257 IDS_ERRORPAGES_HEADING_WEAK_SERVER_EPHEMERAL_DH_KEY, 258 IDS_ERRORPAGES_SUMMARY_WEAK_SERVER_EPHEMERAL_DH_KEY, 259 IDS_ERRORPAGES_DETAILS_SSL_PROTOCOL_ERROR, 260 SUGGEST_LEARNMORE, 261 }, 262 {net::ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN, 263 IDS_ERRORPAGES_TITLE_LOAD_FAILED, 264 IDS_ERRORPAGES_HEADING_PINNING_FAILURE, 265 IDS_ERRORPAGES_SUMMARY_PINNING_FAILURE, 266 IDS_ERRORPAGES_DETAILS_PINNING_FAILURE, 267 SUGGEST_NONE, 268 }, 269 {net::ERR_TEMPORARILY_THROTTLED, 270 IDS_ERRORPAGES_TITLE_ACCESS_DENIED, 271 IDS_ERRORPAGES_HEADING_ACCESS_DENIED, 272 IDS_ERRORPAGES_SUMMARY_TEMPORARILY_THROTTLED, 273 IDS_ERRORPAGES_DETAILS_TEMPORARILY_THROTTLED, 274 SUGGEST_NONE, 275 }, 276 {net::ERR_BLOCKED_BY_CLIENT, 277 IDS_ERRORPAGES_TITLE_BLOCKED, 278 IDS_ERRORPAGES_HEADING_BLOCKED, 279 IDS_ERRORPAGES_SUMMARY_BLOCKED, 280 IDS_ERRORPAGES_DETAILS_BLOCKED, 281 SUGGEST_RELOAD | SUGGEST_DISABLE_EXTENSION, 282 }, 283 {net::ERR_NETWORK_CHANGED, 284 IDS_ERRORPAGES_TITLE_LOAD_FAILED, 285 IDS_ERRORPAGES_HEADING_NETWORK_ACCESS_DENIED, 286 IDS_ERRORPAGES_SUMMARY_NETWORK_CHANGED, 287 IDS_ERRORPAGES_DETAILS_NETWORK_CHANGED, 288 SUGGEST_RELOAD | SUGGEST_CHECK_CONNECTION, 289 }, 290 {net::ERR_BLOCKED_BY_ADMINISTRATOR, 291 IDS_ERRORPAGES_TITLE_BLOCKED, 292 IDS_ERRORPAGES_HEADING_BLOCKED_BY_ADMINISTRATOR, 293 IDS_ERRORPAGES_SUMMARY_BLOCKED_BY_ADMINISTRATOR, 294 IDS_ERRORPAGES_DETAILS_BLOCKED_BY_ADMINISTRATOR, 295 SUGGEST_VIEW_POLICIES | SUGGEST_CONTACT_ADMINISTRATOR, 296 }, 297 {net::ERR_BLOCKED_ENROLLMENT_CHECK_PENDING, 298 IDS_ERRORPAGES_TITLE_BLOCKED, 299 IDS_ERRORPAGES_HEADING_BLOCKED_BY_ADMINISTRATOR, 300 IDS_ERRORPAGES_SUMMARY_BLOCKED_ENROLLMENT_CHECK_PENDING, 301 IDS_ERRORPAGES_DETAILS_BLOCKED_ENROLLMENT_CHECK_PENDING, 302 SUGGEST_CHECK_CONNECTION, 303 }, 304 }; 305 306 // Special error page to be used in the case of navigating back to a page 307 // generated by a POST. LocalizedError::HasStrings expects this net error code 308 // to also appear in the array above. 309 const LocalizedErrorMap repost_error = { 310 net::ERR_CACHE_MISS, 311 IDS_ERRORPAGES_TITLE_NOT_AVAILABLE, 312 IDS_HTTP_POST_WARNING_TITLE, 313 IDS_ERRORPAGES_HTTP_POST_WARNING, 314 IDS_ERRORPAGES_DETAILS_CACHE_MISS, 315 SUGGEST_RELOAD, 316 }; 317 318 const LocalizedErrorMap http_error_options[] = { 319 {403, 320 IDS_ERRORPAGES_TITLE_ACCESS_DENIED, 321 IDS_ERRORPAGES_HEADING_ACCESS_DENIED, 322 IDS_ERRORPAGES_SUMMARY_FORBIDDEN, 323 IDS_ERRORPAGES_DETAILS_FORBIDDEN, 324 SUGGEST_NONE, 325 }, 326 {410, 327 IDS_ERRORPAGES_TITLE_NOT_FOUND, 328 IDS_ERRORPAGES_HEADING_NOT_FOUND, 329 IDS_ERRORPAGES_SUMMARY_GONE, 330 IDS_ERRORPAGES_DETAILS_GONE, 331 SUGGEST_NONE, 332 }, 333 334 {500, 335 IDS_ERRORPAGES_TITLE_LOAD_FAILED, 336 IDS_ERRORPAGES_HEADING_HTTP_SERVER_ERROR, 337 IDS_ERRORPAGES_SUMMARY_INTERNAL_SERVER_ERROR, 338 IDS_ERRORPAGES_DETAILS_INTERNAL_SERVER_ERROR, 339 SUGGEST_RELOAD, 340 }, 341 {501, 342 IDS_ERRORPAGES_TITLE_LOAD_FAILED, 343 IDS_ERRORPAGES_HEADING_HTTP_SERVER_ERROR, 344 IDS_ERRORPAGES_SUMMARY_WEBSITE_CANNOT_HANDLE, 345 IDS_ERRORPAGES_DETAILS_NOT_IMPLEMENTED, 346 SUGGEST_NONE, 347 }, 348 {502, 349 IDS_ERRORPAGES_TITLE_LOAD_FAILED, 350 IDS_ERRORPAGES_HEADING_HTTP_SERVER_ERROR, 351 IDS_ERRORPAGES_SUMMARY_BAD_GATEWAY, 352 IDS_ERRORPAGES_DETAILS_BAD_GATEWAY, 353 SUGGEST_RELOAD, 354 }, 355 {503, 356 IDS_ERRORPAGES_TITLE_LOAD_FAILED, 357 IDS_ERRORPAGES_HEADING_HTTP_SERVER_ERROR, 358 IDS_ERRORPAGES_SUMMARY_SERVICE_UNAVAILABLE, 359 IDS_ERRORPAGES_DETAILS_SERVICE_UNAVAILABLE, 360 SUGGEST_RELOAD, 361 }, 362 {504, 363 IDS_ERRORPAGES_TITLE_LOAD_FAILED, 364 IDS_ERRORPAGES_HEADING_HTTP_SERVER_ERROR, 365 IDS_ERRORPAGES_SUMMARY_GATEWAY_TIMEOUT, 366 IDS_ERRORPAGES_DETAILS_GATEWAY_TIMEOUT, 367 SUGGEST_RELOAD, 368 }, 369 {505, 370 IDS_ERRORPAGES_TITLE_LOAD_FAILED, 371 IDS_ERRORPAGES_HEADING_HTTP_SERVER_ERROR, 372 IDS_ERRORPAGES_SUMMARY_WEBSITE_CANNOT_HANDLE, 373 IDS_ERRORPAGES_DETAILS_HTTP_VERSION_NOT_SUPPORTED, 374 SUGGEST_NONE, 375 }, 376 }; 377 378 const LocalizedErrorMap dns_probe_error_options[] = { 379 {chrome_common_net::DNS_PROBE_POSSIBLE, 380 IDS_ERRORPAGES_TITLE_NOT_AVAILABLE, 381 IDS_ERRORPAGES_HEADING_NOT_AVAILABLE, 382 IDS_ERRORPAGES_SUMMARY_DNS_PROBE_RUNNING, 383 IDS_ERRORPAGES_DETAILS_DNS_PROBE_RUNNING, 384 SUGGEST_RELOAD, 385 }, 386 387 // DNS_PROBE_NOT_RUN is not here; NetErrorHelper will restore the original 388 // error, which might be one of several DNS-related errors. 389 390 {chrome_common_net::DNS_PROBE_STARTED, 391 IDS_ERRORPAGES_TITLE_NOT_AVAILABLE, 392 IDS_ERRORPAGES_HEADING_NOT_AVAILABLE, 393 IDS_ERRORPAGES_SUMMARY_DNS_PROBE_RUNNING, 394 IDS_ERRORPAGES_DETAILS_DNS_PROBE_RUNNING, 395 // Include SUGGEST_RELOAD so the More button doesn't jump when we update. 396 SUGGEST_RELOAD, 397 }, 398 399 // DNS_PROBE_FINISHED_UNKNOWN is not here; NetErrorHelper will restore the 400 // original error, which might be one of several DNS-related errors. 401 402 {chrome_common_net::DNS_PROBE_FINISHED_NO_INTERNET, 403 IDS_ERRORPAGES_TITLE_NOT_AVAILABLE, 404 IDS_ERRORPAGES_HEADING_INTERNET_DISCONNECTED, 405 IDS_ERRORPAGES_SUMMARY_INTERNET_DISCONNECTED, 406 IDS_ERRORPAGES_DETAILS_INTERNET_DISCONNECTED, 407 SUGGEST_RELOAD | SUGGEST_CHECK_CONNECTION | SUGGEST_FIREWALL_CONFIG, 408 }, 409 {chrome_common_net::DNS_PROBE_FINISHED_BAD_CONFIG, 410 IDS_ERRORPAGES_TITLE_NOT_AVAILABLE, 411 IDS_ERRORPAGES_HEADING_NOT_AVAILABLE, 412 IDS_ERRORPAGES_SUMMARY_NAME_NOT_RESOLVED, 413 IDS_ERRORPAGES_DETAILS_NAME_NOT_RESOLVED, 414 SUGGEST_RELOAD | SUGGEST_DNS_CONFIG | SUGGEST_FIREWALL_CONFIG, 415 }, 416 {chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN, 417 IDS_ERRORPAGES_TITLE_NOT_AVAILABLE, 418 IDS_ERRORPAGES_HEADING_NOT_AVAILABLE, 419 IDS_ERRORPAGES_SUMMARY_NAME_NOT_RESOLVED, 420 IDS_ERRORPAGES_DETAILS_NAME_NOT_RESOLVED, 421 SUGGEST_RELOAD, 422 }, 423 }; 424 425 const LocalizedErrorMap* FindErrorMapInArray(const LocalizedErrorMap* maps, 426 size_t num_maps, 427 int error_code) { 428 for (size_t i = 0; i < num_maps; ++i) { 429 if (maps[i].error_code == error_code) 430 return &maps[i]; 431 } 432 return NULL; 433 } 434 435 const LocalizedErrorMap* LookupErrorMap(const std::string& error_domain, 436 int error_code, bool is_post) { 437 if (error_domain == net::kErrorDomain) { 438 // Display a different page in the special case of navigating through the 439 // history to an uncached page created by a POST. 440 if (is_post && error_code == net::ERR_CACHE_MISS) 441 return &repost_error; 442 return FindErrorMapInArray(net_error_options, 443 arraysize(net_error_options), 444 error_code); 445 } else if (error_domain == LocalizedError::kHttpErrorDomain) { 446 return FindErrorMapInArray(http_error_options, 447 arraysize(http_error_options), 448 error_code); 449 } else if (error_domain == chrome_common_net::kDnsProbeErrorDomain) { 450 const LocalizedErrorMap* map = 451 FindErrorMapInArray(dns_probe_error_options, 452 arraysize(dns_probe_error_options), 453 error_code); 454 DCHECK(map); 455 return map; 456 } else { 457 NOTREACHED(); 458 return NULL; 459 } 460 } 461 462 bool LocaleIsRTL() { 463 return base::i18n::IsRTL(); 464 } 465 466 // Returns a dictionary containing the strings for the settings menu under the 467 // wrench, and the advanced settings button. 468 base::DictionaryValue* GetStandardMenuItemsText() { 469 base::DictionaryValue* standard_menu_items_text = new base::DictionaryValue(); 470 standard_menu_items_text->SetString("settingsTitle", 471 l10n_util::GetStringUTF16(IDS_SETTINGS_TITLE)); 472 standard_menu_items_text->SetString("advancedTitle", 473 l10n_util::GetStringUTF16(IDS_SETTINGS_SHOW_ADVANCED_SETTINGS)); 474 return standard_menu_items_text; 475 } 476 477 // Gets the icon class for a given |error_domain| and |error_code|. 478 const char* GetIconClassForError(const std::string& error_domain, 479 int error_code) { 480 if ((error_code == net::ERR_INTERNET_DISCONNECTED && 481 error_domain == net::kErrorDomain) || 482 (error_code == chrome_common_net::DNS_PROBE_FINISHED_NO_INTERNET && 483 error_domain == chrome_common_net::kDnsProbeErrorDomain)) 484 return "icon-offline"; 485 486 return "icon-generic"; 487 } 488 489 } // namespace 490 491 const char LocalizedError::kHttpErrorDomain[] = "http"; 492 493 LocalizedError::ErrorPageParams::ErrorPageParams() 494 : suggest_reload(false), 495 reload_tracking_id(-1), 496 search_tracking_id(-1) { 497 } 498 499 LocalizedError::ErrorPageParams::~ErrorPageParams() { 500 } 501 502 void LocalizedError::GetStrings(int error_code, 503 const std::string& error_domain, 504 const GURL& failed_url, 505 bool is_post, 506 bool show_stale_load_button, 507 const std::string& locale, 508 const std::string& accept_languages, 509 scoped_ptr<ErrorPageParams> params, 510 base::DictionaryValue* error_strings) { 511 bool rtl = LocaleIsRTL(); 512 error_strings->SetString("textdirection", rtl ? "rtl" : "ltr"); 513 webui::SetFontAndTextDirection(error_strings); 514 515 // Grab the strings and settings that depend on the error type. Init 516 // options with default values. 517 LocalizedErrorMap options = { 518 0, 519 IDS_ERRORPAGES_TITLE_NOT_AVAILABLE, 520 IDS_ERRORPAGES_HEADING_NOT_AVAILABLE, 521 IDS_ERRORPAGES_SUMMARY_NOT_AVAILABLE, 522 kErrorPagesNoDetails, 523 SUGGEST_NONE, 524 }; 525 526 const LocalizedErrorMap* error_map = LookupErrorMap(error_domain, error_code, 527 is_post); 528 if (error_map) 529 options = *error_map; 530 531 // If we got "access denied" but the url was a file URL, then we say it was a 532 // file instead of just using the "not available" default message. Just adding 533 // ERR_ACCESS_DENIED to the map isn't sufficient, since that message may be 534 // generated by some OSs when the operation doesn't involve a file URL. 535 if (error_domain == net::kErrorDomain && 536 error_code == net::ERR_ACCESS_DENIED && 537 failed_url.scheme() == "file") { 538 options.title_resource_id = IDS_ERRORPAGES_TITLE_ACCESS_DENIED; 539 options.heading_resource_id = IDS_ERRORPAGES_HEADING_FILE_ACCESS_DENIED; 540 options.summary_resource_id = IDS_ERRORPAGES_SUMMARY_FILE_ACCESS_DENIED; 541 options.details_resource_id = IDS_ERRORPAGES_DETAILS_FILE_ACCESS_DENIED; 542 options.suggestions = SUGGEST_NONE; 543 } 544 545 base::string16 failed_url_string(net::FormatUrl( 546 failed_url, accept_languages, net::kFormatUrlOmitNothing, 547 net::UnescapeRule::NORMAL, NULL, NULL, NULL)); 548 // URLs are always LTR. 549 if (rtl) 550 base::i18n::WrapStringWithLTRFormatting(&failed_url_string); 551 error_strings->SetString("title", 552 l10n_util::GetStringFUTF16(options.title_resource_id, failed_url_string)); 553 error_strings->SetString("heading", 554 l10n_util::GetStringUTF16(options.heading_resource_id)); 555 556 std::string icon_class = GetIconClassForError(error_domain, error_code); 557 error_strings->SetString("iconClass", icon_class); 558 559 base::DictionaryValue* summary = new base::DictionaryValue; 560 561 // For offline show a summary message underneath the heading. 562 if (error_code == net::ERR_INTERNET_DISCONNECTED || 563 error_code == chrome_common_net::DNS_PROBE_FINISHED_NO_INTERNET) { 564 error_strings->SetString("primaryParagraph", 565 l10n_util::GetStringUTF16(options.summary_resource_id)); 566 } else { 567 // Set summary message in the details. 568 summary->SetString("msg", 569 l10n_util::GetStringUTF16(options.summary_resource_id)); 570 } 571 summary->SetString("failedUrl", failed_url_string); 572 summary->SetString("hostName", net::IDNToUnicode(failed_url.host(), 573 accept_languages)); 574 summary->SetString("productName", 575 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)); 576 577 error_strings->SetString( 578 "details", l10n_util::GetStringUTF16(IDS_ERRORPAGE_NET_BUTTON_DETAILS)); 579 error_strings->SetString( 580 "hideDetails", l10n_util::GetStringUTF16( 581 IDS_ERRORPAGE_NET_BUTTON_HIDE_DETAILS)); 582 error_strings->Set("summary", summary); 583 584 if (options.details_resource_id != kErrorPagesNoDetails) { 585 error_strings->SetString( 586 "errorDetails", l10n_util::GetStringUTF16(options.details_resource_id)); 587 } 588 589 base::string16 error_string; 590 if (error_domain == net::kErrorDomain) { 591 // Non-internationalized error string, for debugging Chrome itself. 592 error_string = base::ASCIIToUTF16(net::ErrorToShortString(error_code)); 593 } else if (error_domain == chrome_common_net::kDnsProbeErrorDomain) { 594 std::string ascii_error_string = 595 chrome_common_net::DnsProbeStatusToString(error_code); 596 error_string = base::ASCIIToUTF16(ascii_error_string); 597 } else { 598 DCHECK_EQ(LocalizedError::kHttpErrorDomain, error_domain); 599 error_string = base::IntToString16(error_code); 600 } 601 error_strings->SetString("errorCode", 602 l10n_util::GetStringFUTF16(IDS_ERRORPAGES_ERROR_CODE, error_string)); 603 604 // Platform specific information for diagnosing network issues on OSX and 605 // Windows. 606 #if defined(OS_MACOSX) || defined(OS_WIN) 607 if (error_domain == net::kErrorDomain && 608 error_code == net::ERR_INTERNET_DISCONNECTED) { 609 int platform_string_id = 610 IDS_ERRORPAGES_SUMMARY_INTERNET_DISCONNECTED_PLATFORM; 611 #if defined(OS_WIN) 612 // Different versions of Windows have different instructions. 613 base::win::Version windows_version = base::win::GetVersion(); 614 if (windows_version < base::win::VERSION_VISTA) { 615 // XP, XP64, and Server 2003. 616 platform_string_id = 617 IDS_ERRORPAGES_SUMMARY_INTERNET_DISCONNECTED_PLATFORM_XP; 618 } else if (windows_version == base::win::VERSION_VISTA) { 619 // Vista 620 platform_string_id = 621 IDS_ERRORPAGES_SUMMARY_INTERNET_DISCONNECTED_PLATFORM_VISTA; 622 } 623 #endif // defined(OS_WIN) 624 // Platform dependent portion of the summary section. 625 summary->SetString("msg", 626 l10n_util::GetStringFUTF16( 627 IDS_ERRORPAGES_SUMMARY_INTERNET_DISCONNECTED_INSTRUCTIONS_TEMPLATE, 628 l10n_util::GetStringUTF16(platform_string_id))); 629 } 630 #endif // defined(OS_MACOSX) || defined(OS_WIN) 631 632 // If no parameters were provided, use the defaults. 633 if (!params) { 634 params.reset(new ErrorPageParams()); 635 params->suggest_reload = !!(options.suggestions & SUGGEST_RELOAD); 636 } 637 638 base::ListValue* suggestions = NULL; 639 bool use_default_suggestions = true; 640 if (!params->override_suggestions) { 641 suggestions = new base::ListValue(); 642 } else { 643 suggestions = params->override_suggestions.release(); 644 use_default_suggestions = false; 645 } 646 647 error_strings->Set("suggestions", suggestions); 648 649 if (params->search_url.is_valid()) { 650 error_strings->SetString("searchHeader", 651 l10n_util::GetStringUTF16(IDS_ERRORPAGES_SUGGESTION_GOOGLE_SEARCH)); 652 error_strings->SetString("searchUrl", params->search_url.spec()); 653 error_strings->SetString("searchTerms", params->search_terms); 654 error_strings->SetInteger("searchTrackingId", params->search_tracking_id); 655 } 656 657 // Add the reload suggestion, if needed. 658 if (params->suggest_reload) { 659 if (!is_post) { 660 base::DictionaryValue* reload_button = new base::DictionaryValue; 661 reload_button->SetString( 662 "msg", l10n_util::GetStringUTF16(IDS_ERRORPAGES_BUTTON_RELOAD)); 663 reload_button->SetString("reloadUrl", failed_url.spec()); 664 error_strings->Set("reloadButton", reload_button); 665 reload_button->SetInteger("reloadTrackingId", params->reload_tracking_id); 666 } else { 667 // If the page was created by a post, it can't be reloaded in the same 668 // way, so just add a suggestion instead. 669 // TODO(mmenke): Make the reload button bring up the repost confirmation 670 // dialog for pages resulting from posts. 671 base::DictionaryValue* suggest_reload_repost = new base::DictionaryValue; 672 suggest_reload_repost->SetString("header", 673 l10n_util::GetStringUTF16( 674 IDS_ERRORPAGES_SUGGESTION_RELOAD_REPOST_HEADER)); 675 suggest_reload_repost->SetString("body", 676 l10n_util::GetStringUTF16( 677 IDS_ERRORPAGES_SUGGESTION_RELOAD_REPOST_BODY)); 678 // Add at the front, so it appears before other suggestions, in the case 679 // suggestions are being overridden by |params|. 680 suggestions->Insert(0, suggest_reload_repost); 681 } 682 } 683 684 // If not using the default suggestions, nothing else to do. 685 if (!use_default_suggestions) 686 return; 687 688 if (show_stale_load_button) { 689 base::DictionaryValue* stale_load_button = new base::DictionaryValue; 690 stale_load_button->SetString( 691 "msg", l10n_util::GetStringUTF16(IDS_ERRORPAGES_BUTTON_LOAD_STALE)); 692 stale_load_button->SetString( 693 "title", 694 l10n_util::GetStringUTF16(IDS_ERRORPAGES_BUTTON_LOAD_STALE_HELP)); 695 error_strings->Set("staleLoadButton", stale_load_button); 696 } 697 698 #if defined(OS_CHROMEOS) 699 error_strings->SetString( 700 "diagnose", l10n_util::GetStringUTF16(IDS_ERRORPAGES_BUTTON_DIAGNOSE)); 701 #endif // defined(OS_CHROMEOS) 702 703 if (options.suggestions & SUGGEST_CHECK_CONNECTION) { 704 base::DictionaryValue* suggest_check_connection = new base::DictionaryValue; 705 suggest_check_connection->SetString("header", 706 l10n_util::GetStringUTF16( 707 IDS_ERRORPAGES_SUGGESTION_CHECK_CONNECTION_HEADER)); 708 suggest_check_connection->SetString("body", 709 l10n_util::GetStringUTF16( 710 IDS_ERRORPAGES_SUGGESTION_CHECK_CONNECTION_BODY)); 711 suggestions->Append(suggest_check_connection); 712 } 713 714 if (options.suggestions & SUGGEST_DNS_CONFIG) { 715 base::DictionaryValue* suggest_dns_config = new base::DictionaryValue; 716 suggest_dns_config->SetString("header", 717 l10n_util::GetStringUTF16( 718 IDS_ERRORPAGES_SUGGESTION_DNS_CONFIG_HEADER)); 719 suggest_dns_config->SetString("body", 720 l10n_util::GetStringUTF16( 721 IDS_ERRORPAGES_SUGGESTION_DNS_CONFIG_BODY)); 722 suggestions->Append(suggest_dns_config); 723 724 base::DictionaryValue* suggest_network_prediction = 725 GetStandardMenuItemsText(); 726 suggest_network_prediction->SetString("header", 727 l10n_util::GetStringUTF16( 728 IDS_ERRORPAGES_SUGGESTION_NETWORK_PREDICTION_HEADER)); 729 suggest_network_prediction->SetString("body", 730 l10n_util::GetStringUTF16( 731 IDS_ERRORPAGES_SUGGESTION_NETWORK_PREDICTION_BODY)); 732 suggest_network_prediction->SetString( 733 "noNetworkPredictionTitle", 734 l10n_util::GetStringUTF16( 735 IDS_NETWORK_PREDICTION_ENABLED_DESCRIPTION)); 736 suggestions->Append(suggest_network_prediction); 737 } 738 739 if (options.suggestions & SUGGEST_FIREWALL_CONFIG) { 740 base::DictionaryValue* suggest_firewall_config = new base::DictionaryValue; 741 suggest_firewall_config->SetString("header", 742 l10n_util::GetStringUTF16( 743 IDS_ERRORPAGES_SUGGESTION_FIREWALL_CONFIG_HEADER)); 744 suggest_firewall_config->SetString("body", 745 l10n_util::GetStringUTF16( 746 IDS_ERRORPAGES_SUGGESTION_FIREWALL_CONFIG_BODY)); 747 suggestions->Append(suggest_firewall_config); 748 } 749 750 if (options.suggestions & SUGGEST_PROXY_CONFIG) { 751 base::DictionaryValue* suggest_proxy_config = GetStandardMenuItemsText(); 752 suggest_proxy_config->SetString("header", 753 l10n_util::GetStringUTF16( 754 IDS_ERRORPAGES_SUGGESTION_PROXY_CONFIG_HEADER)); 755 suggest_proxy_config->SetString("body", 756 l10n_util::GetStringFUTF16(IDS_ERRORPAGES_SUGGESTION_PROXY_CONFIG_BODY, 757 l10n_util::GetStringUTF16( 758 IDS_ERRORPAGES_SUGGESTION_PROXY_DISABLE_PLATFORM))); 759 suggest_proxy_config->SetString("proxyTitle", 760 l10n_util::GetStringUTF16(IDS_OPTIONS_PROXIES_CONFIGURE_BUTTON)); 761 762 suggestions->Append(suggest_proxy_config); 763 } 764 765 if (options.suggestions & SUGGEST_DISABLE_EXTENSION) { 766 base::DictionaryValue* suggest_disable_extension = 767 new base::DictionaryValue; 768 // There's only a header for this suggestion. 769 suggest_disable_extension->SetString("header", 770 l10n_util::GetStringUTF16( 771 IDS_ERRORPAGES_SUGGESTION_DISABLE_EXTENSION_HEADER)); 772 suggestions->Append(suggest_disable_extension); 773 } 774 775 if (options.suggestions & SUGGEST_VIEW_POLICIES) { 776 base::DictionaryValue* suggest_view_policies = new base::DictionaryValue; 777 suggest_view_policies->SetString( 778 "header", 779 l10n_util::GetStringUTF16( 780 IDS_ERRORPAGES_SUGGESTION_VIEW_POLICIES_HEADER)); 781 suggest_view_policies->SetString( 782 "body", 783 l10n_util::GetStringUTF16( 784 IDS_ERRORPAGES_SUGGESTION_VIEW_POLICIES_BODY)); 785 suggestions->Append(suggest_view_policies); 786 } 787 788 if (options.suggestions & SUGGEST_CONTACT_ADMINISTRATOR) { 789 base::DictionaryValue* suggest_contant_administrator = 790 new base::DictionaryValue; 791 suggest_contant_administrator->SetString( 792 "body", 793 l10n_util::GetStringUTF16( 794 IDS_ERRORPAGES_SUGGESTION_CONTACT_ADMINISTRATOR_BODY)); 795 suggestions->Append(suggest_contant_administrator); 796 } 797 798 if (options.suggestions & SUGGEST_LEARNMORE) { 799 GURL learn_more_url; 800 switch (options.error_code) { 801 case net::ERR_TOO_MANY_REDIRECTS: 802 learn_more_url = GURL(kRedirectLoopLearnMoreUrl); 803 break; 804 case net::ERR_SSL_WEAK_SERVER_EPHEMERAL_DH_KEY: 805 learn_more_url = GURL(kWeakDHKeyLearnMoreUrl); 806 break; 807 default: 808 break; 809 } 810 811 if (learn_more_url.is_valid()) { 812 // Add the language parameter to the URL. 813 std::string query = learn_more_url.query() + "&hl=" + locale; 814 GURL::Replacements repl; 815 repl.SetQueryStr(query); 816 learn_more_url = learn_more_url.ReplaceComponents(repl); 817 818 base::DictionaryValue* suggest_learn_more = new base::DictionaryValue; 819 // There's only a body for this suggestion. 820 suggest_learn_more->SetString("body", 821 l10n_util::GetStringUTF16(IDS_ERRORPAGES_SUGGESTION_LEARNMORE_BODY)); 822 suggest_learn_more->SetString("learnMoreUrl", learn_more_url.spec()); 823 suggestions->Append(suggest_learn_more); 824 } 825 } 826 } 827 828 base::string16 LocalizedError::GetErrorDetails(const blink::WebURLError& error, 829 bool is_post) { 830 const LocalizedErrorMap* error_map = 831 LookupErrorMap(error.domain.utf8(), error.reason, is_post); 832 if (error_map) 833 return l10n_util::GetStringUTF16(error_map->details_resource_id); 834 else 835 return l10n_util::GetStringUTF16(IDS_ERRORPAGES_DETAILS_UNKNOWN); 836 } 837 838 bool LocalizedError::HasStrings(const std::string& error_domain, 839 int error_code) { 840 // Whether or not the there are strings for an error does not depend on 841 // whether or not the page was be generated by a POST, so just claim it was 842 // not. 843 return LookupErrorMap(error_domain, error_code, /*is_post=*/false) != NULL; 844 } 845 846 void LocalizedError::GetAppErrorStrings( 847 const GURL& display_url, 848 const extensions::Extension* app, 849 base::DictionaryValue* error_strings) { 850 DCHECK(app); 851 852 bool rtl = LocaleIsRTL(); 853 error_strings->SetString("textdirection", rtl ? "rtl" : "ltr"); 854 855 base::string16 failed_url(base::ASCIIToUTF16(display_url.spec())); 856 // URLs are always LTR. 857 if (rtl) 858 base::i18n::WrapStringWithLTRFormatting(&failed_url); 859 error_strings->SetString( 860 "url", l10n_util::GetStringFUTF16(IDS_ERRORPAGES_TITLE_NOT_AVAILABLE, 861 failed_url.c_str())); 862 863 error_strings->SetString("title", app->name()); 864 error_strings->SetString( 865 "icon", 866 extensions::IconsInfo::GetIconURL( 867 app, 868 extension_misc::EXTENSION_ICON_GIGANTOR, 869 ExtensionIconSet::MATCH_SMALLER).spec()); 870 error_strings->SetString("name", app->name()); 871 error_strings->SetString( 872 "msg", 873 l10n_util::GetStringUTF16(IDS_ERRORPAGES_APP_WARNING)); 874 875 #if defined(OS_CHROMEOS) 876 GURL learn_more_url(kAppWarningLearnMoreUrl); 877 base::DictionaryValue* suggest_learn_more = new base::DictionaryValue(); 878 suggest_learn_more->SetString("msg", 879 l10n_util::GetStringUTF16( 880 IDS_ERRORPAGES_SUGGESTION_LEARNMORE_BODY)); 881 suggest_learn_more->SetString("learnMoreUrl", learn_more_url.spec()); 882 error_strings->Set("suggestionsLearnMore", suggest_learn_more); 883 #endif // defined(OS_CHROMEOS) 884 } 885