proxy_view.js revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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  // ID for special HTML element in category_tabs.html
40  ProxyView.TAB_HANDLE_ID = 'tab-handle-proxy';
41
42  // IDs for special HTML elements in proxy_view.html
43  ProxyView.MAIN_BOX_ID = 'proxy-view-tab-content';
44  ProxyView.ORIGINAL_SETTINGS_DIV_ID = 'proxy-view-original-settings';
45  ProxyView.EFFECTIVE_SETTINGS_DIV_ID = 'proxy-view-effective-settings';
46  ProxyView.RELOAD_SETTINGS_BUTTON_ID = 'proxy-view-reload-settings';
47  ProxyView.BAD_PROXIES_TBODY_ID = 'proxy-view-bad-proxies-tbody';
48  ProxyView.CLEAR_BAD_PROXIES_BUTTON_ID = 'proxy-view-clear-bad-proxies';
49  ProxyView.SOCKS_HINTS_DIV_ID = 'proxy-view-socks-hints';
50  ProxyView.SOCKS_HINTS_FLAG_DIV_ID = 'proxy-view-socks-hints-flag';
51
52  cr.addSingletonGetter(ProxyView);
53
54  ProxyView.prototype = {
55    // Inherit the superclass's methods.
56    __proto__: superClass.prototype,
57
58    onLoadLogFinish: function(data) {
59      return this.onProxySettingsChanged(data.proxySettings) &&
60             this.onBadProxiesChanged(data.badProxies);
61    },
62
63    onProxySettingsChanged: function(proxySettings) {
64      $(ProxyView.ORIGINAL_SETTINGS_DIV_ID).innerHTML = '';
65      $(ProxyView.EFFECTIVE_SETTINGS_DIV_ID).innerHTML = '';
66      this.updateSocksHints_(null);
67
68      if (!proxySettings)
69        return false;
70
71      // Both |original| and |effective| are dictionaries describing the
72      // settings.
73      var original = proxySettings.original;
74      var effective = proxySettings.effective;
75
76      $(ProxyView.ORIGINAL_SETTINGS_DIV_ID).innerText =
77          proxySettingsToString(original);
78      $(ProxyView.EFFECTIVE_SETTINGS_DIV_ID).innerText =
79          proxySettingsToString(effective);
80
81      this.updateSocksHints_(effective);
82
83      return true;
84    },
85
86    onBadProxiesChanged: function(badProxies) {
87      $(ProxyView.BAD_PROXIES_TBODY_ID).innerHTML = '';
88
89      if (!badProxies)
90        return false;
91
92      // Add a table row for each bad proxy entry.
93      for (var i = 0; i < badProxies.length; ++i) {
94        var entry = badProxies[i];
95        var badUntilDate = timeutil.convertTimeTicksToDate(entry.bad_until);
96
97        var tr = addNode($(ProxyView.BAD_PROXIES_TBODY_ID), 'tr');
98
99        var nameCell = addNode(tr, 'td');
100        var badUntilCell = addNode(tr, 'td');
101
102        addTextNode(nameCell, entry.proxy_uri);
103        timeutil.addNodeWithDate(badUntilCell, badUntilDate);
104      }
105      return true;
106    },
107
108    updateSocksHints_: function(proxySettings) {
109      setNodeDisplay($(ProxyView.SOCKS_HINTS_DIV_ID), false);
110
111      if (!proxySettings)
112        return;
113
114      var socksProxy = getSocks5Proxy_(proxySettings.single_proxy);
115      if (!socksProxy)
116        return;
117
118      // Suggest a recommended --host-resolver-rules.
119      // NOTE: This does not compensate for any proxy bypass rules. If the
120      // proxy settings include proxy bypasses the user may need to expand the
121      // exclusions for host resolving.
122      var hostResolverRules = 'MAP * ~NOTFOUND , EXCLUDE ' + socksProxy.host;
123      var hostResolverRulesFlag = '--host-resolver-rules="' +
124                                  hostResolverRules + '"';
125
126      // TODO(eroman): On Linux the ClientInfo.command_line is wrong in that it
127      // doesn't include any quotes around the parameters. This means the
128      // string search above is going to fail :(
129      if (ClientInfo.command_line &&
130          ClientInfo.command_line.indexOf(hostResolverRulesFlag) != -1) {
131        // Chrome is already using the suggested resolver rules.
132        return;
133      }
134
135      $(ProxyView.SOCKS_HINTS_FLAG_DIV_ID).innerText = hostResolverRulesFlag;
136      setNodeDisplay($(ProxyView.SOCKS_HINTS_DIV_ID), true);
137    }
138  };
139
140  function getSocks5Proxy_(proxyString) {
141    var pattern = /^socks5:\/\/(.*)$/;
142    var matches = pattern.exec(proxyString);
143
144    if (!matches)
145      return null;
146
147    var hostPortString = matches[1];
148
149    matches = /^(.*):(\d+)$/.exec(hostPortString);
150    if (!matches)
151      return null;
152
153    var result = {host: matches[1], port: matches[2]};
154
155    // Strip brackets off of IPv6 literals.
156    matches = /^\[(.*)\]$/.exec(result.host);
157    if (matches)
158      result.host = matches[1];
159
160    return result;
161  }
162
163  return ProxyView;
164})();
165