1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
|
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* This view displays information on the host resolver:
*
* - Shows the default address family.
* - Has a button to enable IPv6, if it is disabled.
* - Shows the current host cache contents.
* - Has a button to clear the host cache.
* - Shows the parameters used to construct the host cache (capacity, ttl).
*/
// TODO(mmenke): Add links for each address entry to the corresponding NetLog
// source. This could either be done by adding NetLog source ids
// to cache entries, or tracking sources based on their type and
// description. Former is simpler, latter may be useful
// elsewhere as well.
var DnsView = (function() {
'use strict';
// We inherit from DivView.
var superClass = DivView;
/**
* @constructor
*/
function DnsView() {
assertFirstConstructorCall(DnsView);
// Call superclass's constructor.
superClass.call(this, DnsView.MAIN_BOX_ID);
$(DnsView.ENABLE_IPV6_BUTTON_ID).onclick =
g_browser.enableIPv6.bind(g_browser);
$(DnsView.IPV6_PROBE_BUTTON_ID).onclick = this.runIPv6Probe_.bind(this);
$(DnsView.CLEAR_CACHE_BUTTON_ID).onclick =
g_browser.sendClearHostResolverCache.bind(g_browser);
// Used to track IPv6 probes.
EventsTracker.getInstance().addLogEntryObserver(this);
// ID of most recently started IPv6 probe job. Once the job completes,
// set back to -1.
this.ipv6ProbeJobSourceId_ = -1;
// Register to receive changes to the host resolver info.
g_browser.addHostResolverInfoObserver(this, false);
}
DnsView.TAB_ID = 'tab-handle-dns';
DnsView.TAB_NAME = 'DNS';
DnsView.TAB_HASH = '#dns';
// IDs for special HTML elements in dns_view.html
DnsView.MAIN_BOX_ID = 'dns-view-tab-content';
DnsView.DEFAULT_FAMILY_SPAN_ID = 'dns-view-default-family';
DnsView.IPV6_DISABLED_SPAN_ID = 'dns-view-ipv6-disabled';
DnsView.ENABLE_IPV6_BUTTON_ID = 'dns-view-enable-ipv6';
DnsView.IPV6_PROBE_RUNNING_SPAN_ID = 'dns-view-ipv6-probe-running';
DnsView.IPV6_PROBE_COMPLETE_SPAN_ID = 'dns-view-ipv6-probe-complete';
DnsView.IPV6_PROBE_BUTTON_ID = 'dns-view-run-ipv6-probe';
DnsView.INTERNAL_DNS_ENABLED_SPAN_ID = 'dns-view-internal-dns-enabled';
DnsView.INTERNAL_DNS_INVALID_CONFIG_SPAN_ID =
'dns-view-internal-dns-invalid-config';
DnsView.INTERNAL_DNS_CONFIG_TBODY_ID = 'dns-view-internal-dns-config-tbody';
DnsView.CLEAR_CACHE_BUTTON_ID = 'dns-view-clear-cache';
DnsView.CAPACITY_SPAN_ID = 'dns-view-cache-capacity';
DnsView.ACTIVE_SPAN_ID = 'dns-view-cache-active';
DnsView.EXPIRED_SPAN_ID = 'dns-view-cache-expired';
DnsView.CACHE_TBODY_ID = 'dns-view-cache-tbody';
cr.addSingletonGetter(DnsView);
DnsView.prototype = {
// Inherit the superclass's methods.
__proto__: superClass.prototype,
onLoadLogStart: function(polledData, tabData, logDump) {
// Clear information on whether or not an IPv6 probe is running. Needs
// to be done before loading the events.
this.setIPv6ProbeJobLookupRunning_(false, -1);
},
onLoadLogFinish: function(data) {
return this.onHostResolverInfoChanged(data.hostResolverInfo);
},
onHostResolverInfoChanged: function(hostResolverInfo) {
// Clear the existing values.
$(DnsView.DEFAULT_FAMILY_SPAN_ID).innerHTML = '';
$(DnsView.CAPACITY_SPAN_ID).innerHTML = '';
$(DnsView.CACHE_TBODY_ID).innerHTML = '';
$(DnsView.ACTIVE_SPAN_ID).innerHTML = '0';
$(DnsView.EXPIRED_SPAN_ID).innerHTML = '0';
// Update fields containing async DNS configuration information.
displayAsyncDnsConfig_(hostResolverInfo);
// No info.
if (!hostResolverInfo || !hostResolverInfo.cache)
return false;
var family = hostResolverInfo.default_address_family;
addTextNode($(DnsView.DEFAULT_FAMILY_SPAN_ID),
addressFamilyToString(family));
var ipv6Disabled = (family == AddressFamily.ADDRESS_FAMILY_IPV4);
setNodeDisplay($(DnsView.IPV6_DISABLED_SPAN_ID), ipv6Disabled);
// Fill in the basic cache information.
var hostResolverCache = hostResolverInfo.cache;
$(DnsView.CAPACITY_SPAN_ID).innerText = hostResolverCache.capacity;
var expiredEntries = 0;
// Date the cache was logged. This will be either now, when actively
// logging data, or the date the log dump was created.
var logDate;
if (MainView.isViewingLoadedLog()) {
logDate = new Date(ClientInfo.numericDate);
} else {
logDate = new Date();
}
// Fill in the cache contents table.
for (var i = 0; i < hostResolverCache.entries.length; ++i) {
var e = hostResolverCache.entries[i];
var tr = addNode($(DnsView.CACHE_TBODY_ID), 'tr');
var hostnameCell = addNode(tr, 'td');
addTextNode(hostnameCell, e.hostname);
var familyCell = addNode(tr, 'td');
addTextNode(familyCell,
addressFamilyToString(e.address_family));
var addressesCell = addNode(tr, 'td');
if (e.error != undefined) {
var errorText =
e.error + ' (' + netErrorToString(e.error) + ')';
var errorNode = addTextNode(addressesCell, 'error: ' + errorText);
addressesCell.classList.add('warning-text');
} else {
addListToNode_(addNode(addressesCell, 'div'), e.addresses);
}
var expiresDate = timeutil.convertTimeTicksToDate(e.expiration);
var expiresCell = addNode(tr, 'td');
timeutil.addNodeWithDate(expiresCell, expiresDate);
if (logDate > timeutil.convertTimeTicksToDate(e.expiration)) {
++expiredEntries;
var expiredSpan = addNode(expiresCell, 'span');
expiredSpan.classList.add('warning-text');
addTextNode(expiredSpan, ' [Expired]');
}
}
$(DnsView.ACTIVE_SPAN_ID).innerText =
hostResolverCache.entries.length - expiredEntries;
$(DnsView.EXPIRED_SPAN_ID).innerText = expiredEntries;
return true;
},
/**
* Must be called whenever an IPv6 probe job starts or stops running.
* @param {bool} running True if a probe job is running.
* @param {sourceId} sourceId Source ID of the running probe job, if there
* is one. -1 if |running| is false or we don't yet have the ID.
*/
setIPv6ProbeJobLookupRunning_: function(running, sourceId) {
setNodeDisplay($(DnsView.IPV6_PROBE_RUNNING_SPAN_ID), running);
setNodeDisplay($(DnsView.IPV6_PROBE_COMPLETE_SPAN_ID), !running);
this.ipv6ProbeJobSourceId_ = sourceId;
},
/**
* Triggers a new IPv6 probe and displays the probe running message.
*/
runIPv6Probe_: function() {
// Since there's no source ID yet, have to just use -1. We'll get the
// ID when we see the start event for the probe.
this.setIPv6ProbeJobLookupRunning_(true, -1);
g_browser.sendRunIPv6Probe();
},
onReceivedLogEntries: function(logEntries) {
for (var i = 0; i < logEntries.length; ++i) {
if (logEntries[i].source.type != EventSourceType.IPV6_PROBE_JOB ||
logEntries[i].type != EventType.IPV6_PROBE_RUNNING) {
continue;
}
// For IPV6_PROBE_JOB events, update the display depending on whether or
// not a probe job is running. Only track the most recently started
// probe job, as it will cancel any older jobs.
if (logEntries[i].phase == EventPhase.PHASE_BEGIN) {
this.setIPv6ProbeJobLookupRunning_(true, logEntries[i].source.id);
} else if (logEntries[i].source.id == this.ipv6ProbeJobSourceId_) {
this.setIPv6ProbeJobLookupRunning_(false, -1);
g_browser.sendGetHostResolverInfo();
}
}
},
/**
* Since the only thing that matters is the source ID of the active probe
* job, which clearing events doesn't change, do nothing.
*/
onAllLogEntriesDeleted: function() {
},
};
/**
* Displays information corresponding to the current async DNS configuration.
* @param {Object} hostResolverInfo The host resolver information.
*/
function displayAsyncDnsConfig_(hostResolverInfo) {
// Clear the table.
$(DnsView.INTERNAL_DNS_CONFIG_TBODY_ID).innerHTML = '';
// Figure out if the internal DNS resolver is disabled or has no valid
// configuration information, and update display accordingly.
var enabled = hostResolverInfo &&
hostResolverInfo.dns_config !== undefined;
var noConfig = enabled &&
hostResolverInfo.dns_config.nameservers === undefined;
$(DnsView.INTERNAL_DNS_ENABLED_SPAN_ID).innerText = enabled;
setNodeDisplay($(DnsView.INTERNAL_DNS_INVALID_CONFIG_SPAN_ID), noConfig);
// If the internal DNS resolver is disabled or has no valid configuration,
// we're done.
if (!enabled || noConfig)
return;
var dnsConfig = hostResolverInfo.dns_config;
// Display nameservers first.
var nameserverRow = addNode($(DnsView.INTERNAL_DNS_CONFIG_TBODY_ID), 'tr');
addNodeWithText(nameserverRow, 'th', 'nameservers');
addListToNode_(addNode(nameserverRow, 'td'), dnsConfig.nameservers);
// Add everything else in |dnsConfig| to the table.
for (var key in dnsConfig) {
if (key == 'nameservers')
continue;
var tr = addNode($(DnsView.INTERNAL_DNS_CONFIG_TBODY_ID), 'tr');
addNodeWithText(tr, 'th', key);
var td = addNode(tr, 'td');
// For lists, display each list entry on a separate line.
if (typeof dnsConfig[key] == 'object' &&
dnsConfig[key].constructor == Array) {
addListToNode_(td, dnsConfig[key]);
continue;
}
addTextNode(td, dnsConfig[key]);
}
}
/**
* Takes a last of strings and adds them all to a DOM node, displaying them
* on separate lines.
* @param {DomNode} node The parent node.
* @param {Array.<string>} list List of strings to add to the node.
*/
function addListToNode_(node, list) {
for (var i = 0; i < list.length; ++i)
addNodeWithText(node, 'div', list[i]);
}
return DnsView;
})();
|