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 host resolver:
7 *
8 *   - Shows the default address family.
9 *   - Has a button to enable IPv6, if it is disabled.
10 *   - Shows the current host cache contents.
11 *   - Has a button to clear the host cache.
12 *   - Shows the parameters used to construct the host cache (capacity, ttl).
13 */
14
15// TODO(mmenke):  Add links for each address entry to the corresponding NetLog
16//                source.  This could either be done by adding NetLog source ids
17//                to cache entries, or tracking sources based on their type and
18//                description.  Former is simpler, latter may be useful
19//                elsewhere as well.
20var DnsView = (function() {
21  'use strict';
22
23  // We inherit from DivView.
24  var superClass = DivView;
25
26  /**
27   *  @constructor
28   */
29  function DnsView() {
30    assertFirstConstructorCall(DnsView);
31
32    // Call superclass's constructor.
33    superClass.call(this, DnsView.MAIN_BOX_ID);
34
35    $(DnsView.ENABLE_IPV6_BUTTON_ID).onclick =
36        g_browser.enableIPv6.bind(g_browser);
37    $(DnsView.CLEAR_CACHE_BUTTON_ID).onclick =
38        g_browser.sendClearHostResolverCache.bind(g_browser);
39
40    // Register to receive changes to the host resolver info.
41    g_browser.addHostResolverInfoObserver(this, false);
42  }
43
44  DnsView.TAB_ID = 'tab-handle-dns';
45  DnsView.TAB_NAME = 'DNS';
46  DnsView.TAB_HASH = '#dns';
47
48  // IDs for special HTML elements in dns_view.html
49  DnsView.MAIN_BOX_ID = 'dns-view-tab-content';
50  DnsView.DEFAULT_FAMILY_SPAN_ID = 'dns-view-default-family';
51  DnsView.IPV6_DISABLED_SPAN_ID = 'dns-view-ipv6-disabled';
52  DnsView.ENABLE_IPV6_BUTTON_ID = 'dns-view-enable-ipv6';
53
54  DnsView.INTERNAL_DNS_ENABLED_SPAN_ID = 'dns-view-internal-dns-enabled';
55  DnsView.INTERNAL_DNS_INVALID_CONFIG_SPAN_ID =
56      'dns-view-internal-dns-invalid-config';
57  DnsView.INTERNAL_DNS_CONFIG_TBODY_ID = 'dns-view-internal-dns-config-tbody';
58
59  DnsView.CLEAR_CACHE_BUTTON_ID = 'dns-view-clear-cache';
60  DnsView.CAPACITY_SPAN_ID = 'dns-view-cache-capacity';
61
62  DnsView.ACTIVE_SPAN_ID = 'dns-view-cache-active';
63  DnsView.EXPIRED_SPAN_ID = 'dns-view-cache-expired';
64  DnsView.CACHE_TBODY_ID = 'dns-view-cache-tbody';
65
66  cr.addSingletonGetter(DnsView);
67
68  DnsView.prototype = {
69    // Inherit the superclass's methods.
70    __proto__: superClass.prototype,
71
72    onLoadLogFinish: function(data) {
73      return this.onHostResolverInfoChanged(data.hostResolverInfo);
74    },
75
76    onHostResolverInfoChanged: function(hostResolverInfo) {
77      // Clear the existing values.
78      $(DnsView.DEFAULT_FAMILY_SPAN_ID).innerHTML = '';
79      $(DnsView.CAPACITY_SPAN_ID).innerHTML = '';
80      $(DnsView.CACHE_TBODY_ID).innerHTML = '';
81      $(DnsView.ACTIVE_SPAN_ID).innerHTML = '0';
82      $(DnsView.EXPIRED_SPAN_ID).innerHTML = '0';
83
84      // Update fields containing async DNS configuration information.
85      displayAsyncDnsConfig_(hostResolverInfo);
86
87      // No info.
88      if (!hostResolverInfo || !hostResolverInfo.cache)
89        return false;
90
91      var family = hostResolverInfo.default_address_family;
92      addTextNode($(DnsView.DEFAULT_FAMILY_SPAN_ID),
93                  addressFamilyToString(family));
94
95      var ipv6Disabled = (family == AddressFamily.ADDRESS_FAMILY_IPV4);
96      setNodeDisplay($(DnsView.IPV6_DISABLED_SPAN_ID), ipv6Disabled);
97
98      // Fill in the basic cache information.
99      var hostResolverCache = hostResolverInfo.cache;
100      $(DnsView.CAPACITY_SPAN_ID).innerText = hostResolverCache.capacity;
101
102      var expiredEntries = 0;
103      // Date the cache was logged.  This will be either now, when actively
104      // logging data, or the date the log dump was created.
105      var logDate;
106      if (MainView.isViewingLoadedLog()) {
107        logDate = new Date(ClientInfo.numericDate);
108      } else {
109        logDate = new Date();
110      }
111
112      // Fill in the cache contents table.
113      for (var i = 0; i < hostResolverCache.entries.length; ++i) {
114        var e = hostResolverCache.entries[i];
115        var tr = addNode($(DnsView.CACHE_TBODY_ID), 'tr');
116
117        var hostnameCell = addNode(tr, 'td');
118        addTextNode(hostnameCell, e.hostname);
119
120        var familyCell = addNode(tr, 'td');
121        addTextNode(familyCell,
122                    addressFamilyToString(e.address_family));
123
124        var addressesCell = addNode(tr, 'td');
125
126        if (e.error != undefined) {
127          var errorText =
128              e.error + ' (' + netErrorToString(e.error) + ')';
129          var errorNode = addTextNode(addressesCell, 'error: ' + errorText);
130          addressesCell.classList.add('warning-text');
131        } else {
132          addListToNode_(addNode(addressesCell, 'div'), e.addresses);
133        }
134
135        var expiresDate = timeutil.convertTimeTicksToDate(e.expiration);
136        var expiresCell = addNode(tr, 'td');
137        timeutil.addNodeWithDate(expiresCell, expiresDate);
138        if (logDate > timeutil.convertTimeTicksToDate(e.expiration)) {
139          ++expiredEntries;
140          var expiredSpan = addNode(expiresCell, 'span');
141          expiredSpan.classList.add('warning-text');
142          addTextNode(expiredSpan, ' [Expired]');
143        }
144      }
145
146      $(DnsView.ACTIVE_SPAN_ID).innerText =
147          hostResolverCache.entries.length - expiredEntries;
148      $(DnsView.EXPIRED_SPAN_ID).innerText = expiredEntries;
149      return true;
150    },
151  };
152
153  /**
154   * Displays information corresponding to the current async DNS configuration.
155   * @param {Object} hostResolverInfo The host resolver information.
156   */
157  function displayAsyncDnsConfig_(hostResolverInfo) {
158    // Clear the table.
159    $(DnsView.INTERNAL_DNS_CONFIG_TBODY_ID).innerHTML = '';
160
161    // Figure out if the internal DNS resolver is disabled or has no valid
162    // configuration information, and update display accordingly.
163    var enabled = hostResolverInfo &&
164                  hostResolverInfo.dns_config !== undefined;
165    var noConfig = enabled &&
166                   hostResolverInfo.dns_config.nameservers === undefined;
167    $(DnsView.INTERNAL_DNS_ENABLED_SPAN_ID).innerText = enabled;
168    setNodeDisplay($(DnsView.INTERNAL_DNS_INVALID_CONFIG_SPAN_ID), noConfig);
169
170    // If the internal DNS resolver is disabled or has no valid configuration,
171    // we're done.
172    if (!enabled || noConfig)
173      return;
174
175    var dnsConfig = hostResolverInfo.dns_config;
176
177    // Display nameservers first.
178    var nameserverRow = addNode($(DnsView.INTERNAL_DNS_CONFIG_TBODY_ID), 'tr');
179    addNodeWithText(nameserverRow, 'th', 'nameservers');
180    addListToNode_(addNode(nameserverRow, 'td'), dnsConfig.nameservers);
181
182    // Add everything else in |dnsConfig| to the table.
183    for (var key in dnsConfig) {
184      if (key == 'nameservers')
185        continue;
186      var tr = addNode($(DnsView.INTERNAL_DNS_CONFIG_TBODY_ID), 'tr');
187      addNodeWithText(tr, 'th', key);
188      var td = addNode(tr, 'td');
189
190      // For lists, display each list entry on a separate line.
191      if (typeof dnsConfig[key] == 'object' &&
192          dnsConfig[key].constructor == Array) {
193        addListToNode_(td, dnsConfig[key]);
194        continue;
195      }
196
197      addTextNode(td, dnsConfig[key]);
198    }
199  }
200
201  /**
202   * Takes a last of strings and adds them all to a DOM node, displaying them
203   * on separate lines.
204   * @param {DomNode} node The parent node.
205   * @param {Array.<string>} list List of strings to add to the node.
206   */
207  function addListToNode_(node, list) {
208    for (var i = 0; i < list.length; ++i)
209      addNodeWithText(node, 'div', list[i]);
210  }
211
212  return DnsView;
213})();
214