Home | History | Annotate | Download | only in common
      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 "third_party/WebKit/public/platform/WebURLError.h"
     24 #include "ui/base/l10n/l10n_util.h"
     25 #include "ui/webui/web_ui_util.h"
     26 #include "url/gurl.h"
     27 #include "webkit/glue/webkit_glue.h"
     28 
     29 #if defined(OS_WIN)
     30 #include "base/win/windows_version.h"
     31 #endif
     32 
     33 using WebKit::WebURLError;
     34 
     35 // Some error pages have no details.
     36 const unsigned int kErrorPagesNoDetails = 0;
     37 
     38 namespace {
     39 
     40 static const char kRedirectLoopLearnMoreUrl[] =
     41     "https://www.google.com/support/chrome/bin/answer.py?answer=95626";
     42 static 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)
     46 static const char kAppWarningLearnMoreUrl[] =
     47     "chrome-extension://honijodknafkokifofgiaalefdiedpko/main.html"
     48     "?answer=1721911";
     49 #endif  // defined(OS_CHROMEOS)
     50 
     51 enum 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 
     64 struct 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 
     76 const 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.
    304 const 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 
    313 const 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 
    373 const 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 
    420 const 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 
    430 const 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 
    457 bool 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.
    469 base::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 }  // namespace
    479 
    480 const char LocalizedError::kHttpErrorDomain[] = "http";
    481 
    482 void LocalizedError::GetStrings(const WebKit::WebURLError& error,
    483                                 bool is_post,
    484                                 const std::string& locale,
    485                                 base::DictionaryValue* error_strings) {
    486   bool rtl = LocaleIsRTL();
    487   error_strings->SetString("textdirection", rtl ? "rtl" : "ltr");
    488 
    489   // Grab the strings and settings that depend on the error type.  Init
    490   // options with default values.
    491   LocalizedErrorMap options = {
    492     0,
    493     IDS_ERRORPAGES_TITLE_NOT_AVAILABLE,
    494     IDS_ERRORPAGES_HEADING_NOT_AVAILABLE,
    495     IDS_ERRORPAGES_SUMMARY_NOT_AVAILABLE,
    496     kErrorPagesNoDetails,
    497     SUGGEST_NONE,
    498   };
    499 
    500   const std::string error_domain = error.domain.utf8();
    501   int error_code = error.reason;
    502   const LocalizedErrorMap* error_map = LookupErrorMap(error_domain, error_code,
    503                                                       is_post);
    504   if (error_map)
    505     options = *error_map;
    506 
    507   const GURL failed_url = error.unreachableURL;
    508 
    509   // If we got "access denied" but the url was a file URL, then we say it was a
    510   // file instead of just using the "not available" default message. Just adding
    511   // ERR_ACCESS_DENIED to the map isn't sufficient, since that message may be
    512   // generated by some OSs when the operation doesn't involve a file URL.
    513   if (error_domain == net::kErrorDomain &&
    514       error_code == net::ERR_ACCESS_DENIED &&
    515       failed_url.scheme() == "file") {
    516     options.title_resource_id = IDS_ERRORPAGES_TITLE_ACCESS_DENIED;
    517     options.heading_resource_id = IDS_ERRORPAGES_HEADING_FILE_ACCESS_DENIED;
    518     options.summary_resource_id = IDS_ERRORPAGES_SUMMARY_FILE_ACCESS_DENIED;
    519     options.details_resource_id = IDS_ERRORPAGES_DETAILS_FILE_ACCESS_DENIED;
    520     options.suggestions = SUGGEST_NONE;
    521   }
    522 
    523   string16 failed_url_string(UTF8ToUTF16(failed_url.spec()));
    524   // URLs are always LTR.
    525   if (rtl)
    526     base::i18n::WrapStringWithLTRFormatting(&failed_url_string);
    527   error_strings->SetString("title",
    528       l10n_util::GetStringFUTF16(options.title_resource_id, failed_url_string));
    529   error_strings->SetString("heading",
    530       l10n_util::GetStringUTF16(options.heading_resource_id));
    531 
    532   std::string icon_class = (error_code == net::ERR_INTERNET_DISCONNECTED &&
    533                             error_domain == net::kErrorDomain)
    534                                ? "icon-offline"
    535                                : "icon-generic";
    536   error_strings->SetString("iconClass", icon_class);
    537 
    538   base::DictionaryValue* summary = new base::DictionaryValue;
    539   summary->SetString("msg",
    540       l10n_util::GetStringUTF16(options.summary_resource_id));
    541   // TODO(tc): We want the unicode url and host here since they're being
    542   //           displayed.
    543   summary->SetString("failedUrl", failed_url_string);
    544   summary->SetString("hostName", failed_url.host());
    545   summary->SetString("productName",
    546                      l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
    547 
    548   error_strings->SetString(
    549       "more", l10n_util::GetStringUTF16(IDS_ERRORPAGES_BUTTON_MORE));
    550   error_strings->SetString(
    551       "less", l10n_util::GetStringUTF16(IDS_ERRORPAGES_BUTTON_LESS));
    552   error_strings->Set("summary", summary);
    553 #if defined(OS_CHROMEOS)
    554   error_strings->SetString(
    555       "diagnose", l10n_util::GetStringUTF16(IDS_ERRORPAGES_BUTTON_DIAGNOSE));
    556 #endif  // defined(OS_CHROMEOS)
    557 
    558   if (options.details_resource_id != kErrorPagesNoDetails) {
    559     error_strings->SetString(
    560         "errorDetails", l10n_util::GetStringUTF16(options.details_resource_id));
    561   }
    562 
    563   string16 error_string;
    564   if (error_domain == net::kErrorDomain) {
    565     // Non-internationalized error string, for debugging Chrome itself.
    566     std::string ascii_error_string = net::ErrorToString(error_code);
    567     // Remove the leading "net::" from the returned string.
    568     RemoveChars(ascii_error_string, "net:", &ascii_error_string);
    569     error_string = ASCIIToUTF16(ascii_error_string);
    570   } else if (error_domain == chrome_common_net::kDnsProbeErrorDomain) {
    571     std::string ascii_error_string =
    572         chrome_common_net::DnsProbeStatusToString(error_code);
    573     error_string = ASCIIToUTF16(ascii_error_string);
    574   } else {
    575     DCHECK_EQ(LocalizedError::kHttpErrorDomain, error_domain);
    576     error_string = base::IntToString16(error_code);
    577   }
    578   error_strings->SetString("errorCode",
    579       l10n_util::GetStringFUTF16(IDS_ERRORPAGES_ERROR_CODE, error_string));
    580 
    581   base::ListValue* suggestions = new base::ListValue();
    582 
    583   // Platform specific instructions for diagnosing network issues on OSX and
    584   // Windows.
    585 #if defined(OS_MACOSX) || defined(OS_WIN)
    586   if (error_domain == net::kErrorDomain &&
    587       error_code == net::ERR_INTERNET_DISCONNECTED) {
    588     int platform_string_id =
    589         IDS_ERRORPAGES_SUMMARY_INTERNET_DISCONNECTED_PLATFORM;
    590 #if defined(OS_WIN)
    591     // Different versions of Windows have different instructions.
    592     base::win::Version windows_version = base::win::GetVersion();
    593     if (windows_version < base::win::VERSION_VISTA) {
    594       // XP, XP64, and Server 2003.
    595       platform_string_id =
    596           IDS_ERRORPAGES_SUMMARY_INTERNET_DISCONNECTED_PLATFORM_XP;
    597     } else if (windows_version == base::win::VERSION_VISTA) {
    598       // Vista
    599       platform_string_id =
    600           IDS_ERRORPAGES_SUMMARY_INTERNET_DISCONNECTED_PLATFORM_VISTA;
    601     }
    602 #endif  // defined(OS_WIN)
    603     // Lead with the general error description, and suffix with the platform
    604     // dependent portion of the summary section.
    605     summary->SetString("msg",
    606         l10n_util::GetStringFUTF16(
    607             IDS_ERRORPAGES_SUMMARY_INTERNET_DISCONNECTED_INSTRUCTIONS_TEMPLATE,
    608             l10n_util::GetStringUTF16(options.summary_resource_id),
    609             l10n_util::GetStringUTF16(platform_string_id)));
    610   }
    611 #endif  // defined(OS_MACOSX) || defined(OS_WIN)
    612 
    613   if (options.suggestions & SUGGEST_RELOAD) {
    614     if (!is_post) {
    615       base::DictionaryValue* reload_button = new base::DictionaryValue;
    616       reload_button->SetString("msg",
    617           l10n_util::GetStringUTF16(IDS_ERRORPAGES_BUTTON_RELOAD));
    618       reload_button->SetString("reloadUrl", failed_url.spec());
    619       error_strings->Set("reload", reload_button);
    620     } else {
    621       // If the page was created by a post, it can't be reloaded in the same
    622       // way, so just add a suggestion instead.
    623       // TODO(mmenke):  Make the reload button bring up the repost confirmation
    624       //                dialog for pages resulting from posts.
    625       base::DictionaryValue* suggest_reload_repost = new base::DictionaryValue;
    626       suggest_reload_repost->SetString("header",
    627           l10n_util::GetStringUTF16(
    628               IDS_ERRORPAGES_SUGGESTION_RELOAD_REPOST_HEADER));
    629       suggest_reload_repost->SetString("body",
    630           l10n_util::GetStringUTF16(
    631               IDS_ERRORPAGES_SUGGESTION_RELOAD_REPOST_BODY));
    632       suggestions->Append(suggest_reload_repost);
    633     }
    634   }
    635 
    636   if (options.suggestions & SUGGEST_CHECK_CONNECTION) {
    637     base::DictionaryValue* suggest_check_connection = new base::DictionaryValue;
    638     suggest_check_connection->SetString("header",
    639         l10n_util::GetStringUTF16(
    640             IDS_ERRORPAGES_SUGGESTION_CHECK_CONNECTION_HEADER));
    641     suggest_check_connection->SetString("body",
    642         l10n_util::GetStringUTF16(
    643             IDS_ERRORPAGES_SUGGESTION_CHECK_CONNECTION_BODY));
    644     suggestions->Append(suggest_check_connection);
    645   }
    646 
    647   if (options.suggestions & SUGGEST_DNS_CONFIG) {
    648     base::DictionaryValue* suggest_dns_config = new base::DictionaryValue;
    649     suggest_dns_config->SetString("header",
    650         l10n_util::GetStringUTF16(
    651             IDS_ERRORPAGES_SUGGESTION_DNS_CONFIG_HEADER));
    652     suggest_dns_config->SetString("body",
    653         l10n_util::GetStringUTF16(
    654             IDS_ERRORPAGES_SUGGESTION_DNS_CONFIG_BODY));
    655     suggestions->Append(suggest_dns_config);
    656 
    657     base::DictionaryValue* suggest_network_prediction =
    658         GetStandardMenuItemsText();
    659     suggest_network_prediction->SetString("header",
    660         l10n_util::GetStringUTF16(
    661             IDS_ERRORPAGES_SUGGESTION_NETWORK_PREDICTION_HEADER));
    662     suggest_network_prediction->SetString("body",
    663         l10n_util::GetStringUTF16(
    664             IDS_ERRORPAGES_SUGGESTION_NETWORK_PREDICTION_BODY));
    665     suggest_network_prediction->SetString(
    666         "noNetworkPredictionTitle",
    667         l10n_util::GetStringUTF16(
    668             IDS_NETWORK_PREDICTION_ENABLED_DESCRIPTION));
    669     suggestions->Append(suggest_network_prediction);
    670   }
    671 
    672   if (options.suggestions & SUGGEST_FIREWALL_CONFIG) {
    673     base::DictionaryValue* suggest_firewall_config = new base::DictionaryValue;
    674     suggest_firewall_config->SetString("header",
    675         l10n_util::GetStringUTF16(
    676             IDS_ERRORPAGES_SUGGESTION_FIREWALL_CONFIG_HEADER));
    677     suggest_firewall_config->SetString("body",
    678         l10n_util::GetStringUTF16(
    679             IDS_ERRORPAGES_SUGGESTION_FIREWALL_CONFIG_BODY));
    680     suggestions->Append(suggest_firewall_config);
    681   }
    682 
    683   if (options.suggestions & SUGGEST_PROXY_CONFIG) {
    684     base::DictionaryValue* suggest_proxy_config = GetStandardMenuItemsText();
    685     suggest_proxy_config->SetString("header",
    686         l10n_util::GetStringUTF16(
    687             IDS_ERRORPAGES_SUGGESTION_PROXY_CONFIG_HEADER));
    688     suggest_proxy_config->SetString("body",
    689         l10n_util::GetStringFUTF16(IDS_ERRORPAGES_SUGGESTION_PROXY_CONFIG_BODY,
    690             l10n_util::GetStringUTF16(
    691                 IDS_ERRORPAGES_SUGGESTION_PROXY_DISABLE_PLATFORM)));
    692     suggest_proxy_config->SetString("proxyTitle",
    693         l10n_util::GetStringUTF16(IDS_OPTIONS_PROXIES_CONFIGURE_BUTTON));
    694 
    695     suggestions->Append(suggest_proxy_config);
    696   }
    697 
    698   if (options.suggestions & SUGGEST_DISABLE_EXTENSION) {
    699     base::DictionaryValue* suggest_disable_extension =
    700         new base::DictionaryValue;
    701     // There's only a header for this suggestion.
    702     suggest_disable_extension->SetString("header",
    703         l10n_util::GetStringUTF16(
    704             IDS_ERRORPAGES_SUGGESTION_DISABLE_EXTENSION_HEADER));
    705     suggestions->Append(suggest_disable_extension);
    706   }
    707 
    708   if (options.suggestions & SUGGEST_VIEW_POLICIES) {
    709     base::DictionaryValue* suggest_view_policies = new base::DictionaryValue;
    710     suggest_view_policies->SetString(
    711         "header",
    712         l10n_util::GetStringUTF16(
    713             IDS_ERRORPAGES_SUGGESTION_VIEW_POLICIES_HEADER));
    714     suggest_view_policies->SetString(
    715         "body",
    716         l10n_util::GetStringUTF16(
    717             IDS_ERRORPAGES_SUGGESTION_VIEW_POLICIES_BODY));
    718     suggestions->Append(suggest_view_policies);
    719   }
    720 
    721   if (options.suggestions & SUGGEST_CONTACT_ADMINISTRATOR) {
    722     base::DictionaryValue* suggest_contant_administrator =
    723         new base::DictionaryValue;
    724     suggest_contant_administrator->SetString(
    725         "body",
    726         l10n_util::GetStringUTF16(
    727             IDS_ERRORPAGES_SUGGESTION_CONTACT_ADMINISTRATOR_BODY));
    728     suggestions->Append(suggest_contant_administrator);
    729   }
    730 
    731   if (options.suggestions & SUGGEST_LEARNMORE) {
    732     GURL learn_more_url;
    733     switch (options.error_code) {
    734       case net::ERR_TOO_MANY_REDIRECTS:
    735         learn_more_url = GURL(kRedirectLoopLearnMoreUrl);
    736         break;
    737       case net::ERR_SSL_WEAK_SERVER_EPHEMERAL_DH_KEY:
    738         learn_more_url = GURL(kWeakDHKeyLearnMoreUrl);
    739         break;
    740       default:
    741         break;
    742     }
    743 
    744     if (learn_more_url.is_valid()) {
    745       // Add the language parameter to the URL.
    746       std::string query = learn_more_url.query() + "&hl=" + locale;
    747       GURL::Replacements repl;
    748       repl.SetQueryStr(query);
    749       learn_more_url = learn_more_url.ReplaceComponents(repl);
    750 
    751       base::DictionaryValue* suggest_learn_more = new base::DictionaryValue;
    752       // There's only a body for this suggestion.
    753       suggest_learn_more->SetString("body",
    754           l10n_util::GetStringUTF16(IDS_ERRORPAGES_SUGGESTION_LEARNMORE_BODY));
    755       suggest_learn_more->SetString("learnMoreUrl", learn_more_url.spec());
    756       suggestions->Append(suggest_learn_more);
    757     }
    758   }
    759 
    760   error_strings->Set("suggestions", suggestions);
    761 }
    762 
    763 string16 LocalizedError::GetErrorDetails(const WebKit::WebURLError& error,
    764                                          bool is_post) {
    765   const LocalizedErrorMap* error_map =
    766       LookupErrorMap(error.domain.utf8(), error.reason, is_post);
    767   if (error_map)
    768     return l10n_util::GetStringUTF16(error_map->details_resource_id);
    769   else
    770     return l10n_util::GetStringUTF16(IDS_ERRORPAGES_DETAILS_UNKNOWN);
    771 }
    772 
    773 bool LocalizedError::HasStrings(const std::string& error_domain,
    774                                 int error_code) {
    775   // Whether or not the there are strings for an error does not depend on
    776   // whether or not the page was be generated by a POST, so just claim it was
    777   // not.
    778   return LookupErrorMap(error_domain, error_code, /*is_post=*/false) != NULL;
    779 }
    780 
    781 void LocalizedError::GetAppErrorStrings(
    782     const WebURLError& error,
    783     const GURL& display_url,
    784     const extensions::Extension* app,
    785     base::DictionaryValue* error_strings) {
    786   DCHECK(app);
    787 
    788   bool rtl = LocaleIsRTL();
    789   error_strings->SetString("textdirection", rtl ? "rtl" : "ltr");
    790 
    791   string16 failed_url(ASCIIToUTF16(display_url.spec()));
    792   // URLs are always LTR.
    793   if (rtl)
    794     base::i18n::WrapStringWithLTRFormatting(&failed_url);
    795   error_strings->SetString(
    796      "url", l10n_util::GetStringFUTF16(IDS_ERRORPAGES_TITLE_NOT_AVAILABLE,
    797                                        failed_url.c_str()));
    798 
    799   error_strings->SetString("title", app->name());
    800   error_strings->SetString(
    801       "icon",
    802       extensions::IconsInfo::GetIconURL(
    803           app,
    804           extension_misc::EXTENSION_ICON_GIGANTOR,
    805           ExtensionIconSet::MATCH_SMALLER).spec());
    806   error_strings->SetString("name", app->name());
    807   error_strings->SetString(
    808       "msg",
    809       l10n_util::GetStringUTF16(IDS_ERRORPAGES_APP_WARNING));
    810 
    811 #if defined(OS_CHROMEOS)
    812   GURL learn_more_url(kAppWarningLearnMoreUrl);
    813   base::DictionaryValue* suggest_learn_more = new base::DictionaryValue();
    814   suggest_learn_more->SetString("msg",
    815                                 l10n_util::GetStringUTF16(
    816                                     IDS_ERRORPAGES_SUGGESTION_LEARNMORE_BODY));
    817   suggest_learn_more->SetString("learnMoreUrl", learn_more_url.spec());
    818   error_strings->Set("suggestionsLearnMore", suggest_learn_more);
    819 #endif  // defined(OS_CHROMEOS)
    820 }
    821