• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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