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