Home | History | Annotate | Download | only in net_internals
      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 /**
      6  * This view displays information on the proxy setup:
      7  *
      8  *   - Shows the current proxy settings.
      9  *   - Has a button to reload these settings.
     10  *   - Shows the list of proxy hostnames that are cached as "bad".
     11  *   - Has a button to clear the cached bad proxies.
     12  */
     13 var ProxyView = (function() {
     14   'use strict';
     15 
     16   // We inherit from DivView.
     17   var superClass = DivView;
     18 
     19   /**
     20    * @constructor
     21    */
     22   function ProxyView() {
     23     assertFirstConstructorCall(ProxyView);
     24 
     25     // Call superclass's constructor.
     26     superClass.call(this, ProxyView.MAIN_BOX_ID);
     27 
     28     // Hook up the UI components.
     29     $(ProxyView.RELOAD_SETTINGS_BUTTON_ID).onclick =
     30         g_browser.sendReloadProxySettings.bind(g_browser);
     31     $(ProxyView.CLEAR_BAD_PROXIES_BUTTON_ID).onclick =
     32         g_browser.sendClearBadProxies.bind(g_browser);
     33 
     34     // Register to receive proxy information as it changes.
     35     g_browser.addProxySettingsObserver(this, true);
     36     g_browser.addBadProxiesObserver(this, true);
     37   }
     38 
     39   ProxyView.TAB_ID = 'tab-handle-proxy';
     40   ProxyView.TAB_NAME = 'Proxy';
     41   ProxyView.TAB_HASH = '#proxy';
     42 
     43   // IDs for special HTML elements in proxy_view.html
     44   ProxyView.MAIN_BOX_ID = 'proxy-view-tab-content';
     45   ProxyView.ORIGINAL_SETTINGS_DIV_ID = 'proxy-view-original-settings';
     46   ProxyView.EFFECTIVE_SETTINGS_DIV_ID = 'proxy-view-effective-settings';
     47   ProxyView.RELOAD_SETTINGS_BUTTON_ID = 'proxy-view-reload-settings';
     48   ProxyView.BAD_PROXIES_DIV_ID = 'proxy-view-bad-proxies-div';
     49   ProxyView.BAD_PROXIES_TBODY_ID = 'proxy-view-bad-proxies-tbody';
     50   ProxyView.CLEAR_BAD_PROXIES_BUTTON_ID = 'proxy-view-clear-bad-proxies';
     51   ProxyView.SOCKS_HINTS_DIV_ID = 'proxy-view-socks-hints';
     52   ProxyView.SOCKS_HINTS_FLAG_DIV_ID = 'proxy-view-socks-hints-flag';
     53 
     54   cr.addSingletonGetter(ProxyView);
     55 
     56   ProxyView.prototype = {
     57     // Inherit the superclass's methods.
     58     __proto__: superClass.prototype,
     59 
     60     onLoadLogFinish: function(data) {
     61       return this.onProxySettingsChanged(data.proxySettings) &&
     62              this.onBadProxiesChanged(data.badProxies);
     63     },
     64 
     65     onProxySettingsChanged: function(proxySettings) {
     66       $(ProxyView.ORIGINAL_SETTINGS_DIV_ID).innerHTML = '';
     67       $(ProxyView.EFFECTIVE_SETTINGS_DIV_ID).innerHTML = '';
     68       this.updateSocksHints_(null);
     69 
     70       if (!proxySettings)
     71         return false;
     72 
     73       // Both |original| and |effective| are dictionaries describing the
     74       // settings.
     75       var original = proxySettings.original;
     76       var effective = proxySettings.effective;
     77 
     78       $(ProxyView.ORIGINAL_SETTINGS_DIV_ID).innerText =
     79           proxySettingsToString(original);
     80       $(ProxyView.EFFECTIVE_SETTINGS_DIV_ID).innerText =
     81           proxySettingsToString(effective);
     82 
     83       this.updateSocksHints_(effective);
     84 
     85       return true;
     86     },
     87 
     88     onBadProxiesChanged: function(badProxies) {
     89       $(ProxyView.BAD_PROXIES_TBODY_ID).innerHTML = '';
     90       setNodeDisplay($(ProxyView.BAD_PROXIES_DIV_ID),
     91                      badProxies && badProxies.length > 0);
     92 
     93       if (!badProxies)
     94         return false;
     95 
     96       // Add a table row for each bad proxy entry.
     97       for (var i = 0; i < badProxies.length; ++i) {
     98         var entry = badProxies[i];
     99         var badUntilDate = timeutil.convertTimeTicksToDate(entry.bad_until);
    100 
    101         var tr = addNode($(ProxyView.BAD_PROXIES_TBODY_ID), 'tr');
    102 
    103         var nameCell = addNode(tr, 'td');
    104         var badUntilCell = addNode(tr, 'td');
    105 
    106         addTextNode(nameCell, entry.proxy_uri);
    107         timeutil.addNodeWithDate(badUntilCell, badUntilDate);
    108       }
    109       return true;
    110     },
    111 
    112     updateSocksHints_: function(proxySettings) {
    113       setNodeDisplay($(ProxyView.SOCKS_HINTS_DIV_ID), false);
    114 
    115       if (!proxySettings)
    116         return;
    117 
    118       var socksProxy = getSingleSocks5Proxy_(proxySettings.single_proxy);
    119       if (!socksProxy)
    120         return;
    121 
    122       // Suggest a recommended --host-resolver-rules.
    123       // NOTE: This does not compensate for any proxy bypass rules. If the
    124       // proxy settings include proxy bypasses the user may need to expand the
    125       // exclusions for host resolving.
    126       var hostResolverRules = 'MAP * ~NOTFOUND , EXCLUDE ' + socksProxy.host;
    127       var hostResolverRulesFlag = '--host-resolver-rules="' +
    128                                   hostResolverRules + '"';
    129 
    130       // TODO(eroman): On Linux the ClientInfo.command_line is wrong in that it
    131       // doesn't include any quotes around the parameters. This means the
    132       // string search above is going to fail :(
    133       if (ClientInfo.command_line &&
    134           ClientInfo.command_line.indexOf(hostResolverRulesFlag) != -1) {
    135         // Chrome is already using the suggested resolver rules.
    136         return;
    137       }
    138 
    139       $(ProxyView.SOCKS_HINTS_FLAG_DIV_ID).innerText = hostResolverRulesFlag;
    140       setNodeDisplay($(ProxyView.SOCKS_HINTS_DIV_ID), true);
    141     }
    142   };
    143 
    144   function getSingleSocks5Proxy_(proxyList) {
    145     var proxyString;
    146     if (typeof proxyList == 'string') {
    147       // Older versions of Chrome passed single_proxy as a string.
    148       // TODO(eroman): This behavior changed in M27. Support for older logs can
    149       //               safely be removed circa M29.
    150       proxyString = proxyList;
    151     } else if (Array.isArray(proxyList) && proxyList.length == 1) {
    152       proxyString = proxyList[0];
    153     } else {
    154       return null;
    155     }
    156 
    157     var pattern = /^socks5:\/\/(.*)$/;
    158     var matches = pattern.exec(proxyString);
    159 
    160     if (!matches)
    161       return null;
    162 
    163     var hostPortString = matches[1];
    164 
    165     matches = /^(.*):(\d+)$/.exec(hostPortString);
    166     if (!matches)
    167       return null;
    168 
    169     var result = {host: matches[1], port: matches[2]};
    170 
    171     // Strip brackets off of IPv6 literals.
    172     matches = /^\[(.*)\]$/.exec(result.host);
    173     if (matches)
    174       result.host = matches[1];
    175 
    176     return result;
    177   }
    178 
    179   return ProxyView;
    180 })();
    181