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