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 */ 13var 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.ORIGINAL_CONTENT_DIV_ID = 'proxy-view-original-content'; 48 ProxyView.EFFECTIVE_CONTENT_DIV_ID = 'proxy-view-effective-content'; 49 ProxyView.RELOAD_SETTINGS_BUTTON_ID = 'proxy-view-reload-settings'; 50 ProxyView.BAD_PROXIES_DIV_ID = 'proxy-view-bad-proxies-div'; 51 ProxyView.BAD_PROXIES_TBODY_ID = 'proxy-view-bad-proxies-tbody'; 52 ProxyView.CLEAR_BAD_PROXIES_BUTTON_ID = 'proxy-view-clear-bad-proxies'; 53 ProxyView.SOCKS_HINTS_DIV_ID = 'proxy-view-socks-hints'; 54 ProxyView.SOCKS_HINTS_FLAG_DIV_ID = 'proxy-view-socks-hints-flag'; 55 56 cr.addSingletonGetter(ProxyView); 57 58 ProxyView.prototype = { 59 // Inherit the superclass's methods. 60 __proto__: superClass.prototype, 61 62 onLoadLogFinish: function(data) { 63 return this.onProxySettingsChanged(data.proxySettings) && 64 this.onBadProxiesChanged(data.badProxies); 65 }, 66 67 onProxySettingsChanged: function(proxySettings) { 68 $(ProxyView.ORIGINAL_SETTINGS_DIV_ID).innerHTML = ''; 69 $(ProxyView.EFFECTIVE_SETTINGS_DIV_ID).innerHTML = ''; 70 this.updateSocksHints_(null); 71 72 if (!proxySettings) 73 return false; 74 75 // Both |original| and |effective| are dictionaries describing the 76 // settings. 77 var original = proxySettings.original; 78 var effective = proxySettings.effective; 79 80 var originalStr = proxySettingsToString(original); 81 var effectiveStr = proxySettingsToString(effective); 82 83 setNodeDisplay($(ProxyView.ORIGINAL_CONTENT_DIV_ID), 84 originalStr != effectiveStr); 85 86 $(ProxyView.ORIGINAL_SETTINGS_DIV_ID).innerText = originalStr; 87 $(ProxyView.EFFECTIVE_SETTINGS_DIV_ID).innerText = effectiveStr; 88 89 this.updateSocksHints_(effective); 90 91 return true; 92 }, 93 94 onBadProxiesChanged: function(badProxies) { 95 $(ProxyView.BAD_PROXIES_TBODY_ID).innerHTML = ''; 96 setNodeDisplay($(ProxyView.BAD_PROXIES_DIV_ID), 97 badProxies && badProxies.length > 0); 98 99 if (!badProxies) 100 return false; 101 102 // Add a table row for each bad proxy entry. 103 for (var i = 0; i < badProxies.length; ++i) { 104 var entry = badProxies[i]; 105 var badUntilDate = timeutil.convertTimeTicksToDate(entry.bad_until); 106 107 var tr = addNode($(ProxyView.BAD_PROXIES_TBODY_ID), 'tr'); 108 109 var nameCell = addNode(tr, 'td'); 110 var badUntilCell = addNode(tr, 'td'); 111 112 addTextNode(nameCell, entry.proxy_uri); 113 timeutil.addNodeWithDate(badUntilCell, badUntilDate); 114 } 115 return true; 116 }, 117 118 updateSocksHints_: function(proxySettings) { 119 setNodeDisplay($(ProxyView.SOCKS_HINTS_DIV_ID), false); 120 121 if (!proxySettings) 122 return; 123 124 var socksProxy = getSingleSocks5Proxy_(proxySettings.single_proxy); 125 if (!socksProxy) 126 return; 127 128 // Suggest a recommended --host-resolver-rules. 129 // NOTE: This does not compensate for any proxy bypass rules. If the 130 // proxy settings include proxy bypasses the user may need to expand the 131 // exclusions for host resolving. 132 var hostResolverRules = 'MAP * ~NOTFOUND , EXCLUDE ' + socksProxy.host; 133 var hostResolverRulesFlag = '--host-resolver-rules="' + 134 hostResolverRules + '"'; 135 136 // TODO(eroman): On Linux the ClientInfo.command_line is wrong in that it 137 // doesn't include any quotes around the parameters. This means the 138 // string search above is going to fail :( 139 if (ClientInfo.command_line && 140 ClientInfo.command_line.indexOf(hostResolverRulesFlag) != -1) { 141 // Chrome is already using the suggested resolver rules. 142 return; 143 } 144 145 $(ProxyView.SOCKS_HINTS_FLAG_DIV_ID).innerText = hostResolverRulesFlag; 146 setNodeDisplay($(ProxyView.SOCKS_HINTS_DIV_ID), true); 147 } 148 }; 149 150 function getSingleSocks5Proxy_(proxyList) { 151 var proxyString; 152 if (typeof proxyList == 'string') { 153 // Older versions of Chrome passed single_proxy as a string. 154 // TODO(eroman): This behavior changed in M27. Support for older logs can 155 // safely be removed circa M29. 156 proxyString = proxyList; 157 } else if (Array.isArray(proxyList) && proxyList.length == 1) { 158 proxyString = proxyList[0]; 159 } else { 160 return null; 161 } 162 163 var pattern = /^socks5:\/\/(.*)$/; 164 var matches = pattern.exec(proxyString); 165 166 if (!matches) 167 return null; 168 169 var hostPortString = matches[1]; 170 171 matches = /^(.*):(\d+)$/.exec(hostPortString); 172 if (!matches) 173 return null; 174 175 var result = {host: matches[1], port: matches[2]}; 176 177 // Strip brackets off of IPv6 literals. 178 matches = /^\[(.*)\]$/.exec(result.host); 179 if (matches) 180 result.host = matches[1]; 181 182 return result; 183 } 184 185 return ProxyView; 186})(); 187