Commit 7a749216 authored by mgersh's avatar mgersh Committed by Commit bot

Add more data to net-internals view of DNS cache

The cache can now have entries that are expired because they're from a
different network, but are still stored in the cache. This change
updates net-internals to expose that information, and also exposes the
TTL for easier debugging.

BUG=703821
CQ_INCLUDE_TRYBOTS=master.tryserver.chromium.linux:closure_compilation

Review-Url: https://codereview.chromium.org/2773023003
Cr-Commit-Position: refs/heads/master@{#460548}
parent 517d0115
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
<ul> <ul>
<li>Active entries: <span id=dns-view-cache-active></span></li> <li>Active entries: <span id=dns-view-cache-active></span></li>
<li>Expired entries: <span id=dns-view-cache-expired></span></li> <li>Expired entries: <span id=dns-view-cache-expired></span></li>
<li>Network changes: <span id=dns-view-network-changes></span></li>
</ul> </ul>
<table class="styled-table"> <table class="styled-table">
...@@ -37,7 +38,9 @@ ...@@ -37,7 +38,9 @@
<th>Hostname</th> <th>Hostname</th>
<th>Family</th> <th>Family</th>
<th>Addresses</th> <th>Addresses</th>
<th>TTL</th>
<th>Expires</th> <th>Expires</th>
<th>Network changes</th>
</tr> </tr>
</thead> </thead>
<tbody id=dns-view-cache-tbody> <tbody id=dns-view-cache-tbody>
......
...@@ -55,6 +55,7 @@ var DnsView = (function() { ...@@ -55,6 +55,7 @@ var DnsView = (function() {
DnsView.ACTIVE_SPAN_ID = 'dns-view-cache-active'; DnsView.ACTIVE_SPAN_ID = 'dns-view-cache-active';
DnsView.EXPIRED_SPAN_ID = 'dns-view-cache-expired'; DnsView.EXPIRED_SPAN_ID = 'dns-view-cache-expired';
DnsView.NETWORK_SPAN_ID = 'dns-view-network-changes';
DnsView.CACHE_TBODY_ID = 'dns-view-cache-tbody'; DnsView.CACHE_TBODY_ID = 'dns-view-cache-tbody';
cr.addSingletonGetter(DnsView); cr.addSingletonGetter(DnsView);
...@@ -73,6 +74,7 @@ var DnsView = (function() { ...@@ -73,6 +74,7 @@ var DnsView = (function() {
$(DnsView.CACHE_TBODY_ID).innerHTML = ''; $(DnsView.CACHE_TBODY_ID).innerHTML = '';
$(DnsView.ACTIVE_SPAN_ID).innerHTML = '0'; $(DnsView.ACTIVE_SPAN_ID).innerHTML = '0';
$(DnsView.EXPIRED_SPAN_ID).innerHTML = '0'; $(DnsView.EXPIRED_SPAN_ID).innerHTML = '0';
$(DnsView.NETWORK_SPAN_ID).innerHTML = '0';
// Update fields containing async DNS configuration information. // Update fields containing async DNS configuration information.
displayAsyncDnsConfig_(hostResolverInfo); displayAsyncDnsConfig_(hostResolverInfo);
...@@ -84,6 +86,8 @@ var DnsView = (function() { ...@@ -84,6 +86,8 @@ var DnsView = (function() {
// Fill in the basic cache information. // Fill in the basic cache information.
var hostResolverCache = hostResolverInfo.cache; var hostResolverCache = hostResolverInfo.cache;
$(DnsView.CAPACITY_SPAN_ID).innerText = hostResolverCache.capacity; $(DnsView.CAPACITY_SPAN_ID).innerText = hostResolverCache.capacity;
$(DnsView.NETWORK_SPAN_ID).innerText =
valueOrDefault(hostResolverCache.network_changes, '');
var expiredEntries = 0; var expiredEntries = 0;
// Date the cache was logged. This will be either now, when actively // Date the cache was logged. This will be either now, when actively
...@@ -99,6 +103,7 @@ var DnsView = (function() { ...@@ -99,6 +103,7 @@ var DnsView = (function() {
for (var i = 0; i < hostResolverCache.entries.length; ++i) { for (var i = 0; i < hostResolverCache.entries.length; ++i) {
var e = hostResolverCache.entries[i]; var e = hostResolverCache.entries[i];
var tr = addNode($(DnsView.CACHE_TBODY_ID), 'tr'); var tr = addNode($(DnsView.CACHE_TBODY_ID), 'tr');
var expired = false;
var hostnameCell = addNode(tr, 'td'); var hostnameCell = addNode(tr, 'td');
addTextNode(hostnameCell, e.hostname); addTextNode(hostnameCell, e.hostname);
...@@ -116,15 +121,35 @@ var DnsView = (function() { ...@@ -116,15 +121,35 @@ var DnsView = (function() {
addListToNode_(addNode(addressesCell, 'div'), e.addresses); addListToNode_(addNode(addressesCell, 'div'), e.addresses);
} }
var ttlCell = addNode(tr, 'td');
addTextNode(ttlCell, valueOrDefault(e.ttl, ''));
var expiresDate = timeutil.convertTimeTicksToDate(e.expiration); var expiresDate = timeutil.convertTimeTicksToDate(e.expiration);
var expiresCell = addNode(tr, 'td'); var expiresCell = addNode(tr, 'td');
timeutil.addNodeWithDate(expiresCell, expiresDate); timeutil.addNodeWithDate(expiresCell, expiresDate);
if (logDate > timeutil.convertTimeTicksToDate(e.expiration)) { if (logDate > timeutil.convertTimeTicksToDate(e.expiration)) {
++expiredEntries; expired = true;
var expiredSpan = addNode(expiresCell, 'span'); var expiredSpan = addNode(expiresCell, 'span');
expiredSpan.classList.add('warning-text'); expiredSpan.classList.add('warning-text');
addTextNode(expiredSpan, ' [Expired]'); addTextNode(expiredSpan, ' [Expired]');
} }
// HostCache keeps track of how many network changes have happened since
// it was created, and entries store what that number was at the time
// they were created. If more network changes have happened since an
// entry was created, the entry is expired.
var networkChangesCell = addNode(tr, 'td');
addTextNode(networkChangesCell, valueOrDefault(e.network_changes, ''));
if (e.network_changes < hostResolverCache.network_changes) {
expired = true;
var expiredSpan = addNode(networkChangesCell, 'span');
expiredSpan.classList.add('warning-text');
addTextNode(expiredSpan, ' [Expired]');
}
if (expired) {
expiredEntries++;
}
} }
$(DnsView.ACTIVE_SPAN_ID).innerText = $(DnsView.ACTIVE_SPAN_ID).innerText =
...@@ -192,5 +217,13 @@ var DnsView = (function() { ...@@ -192,5 +217,13 @@ var DnsView = (function() {
addNodeWithText(node, 'div', list[i]); addNodeWithText(node, 'div', list[i]);
} }
// TODO(mgersh): The |ttl| and |network_changes| properties were introduced in
// M59 and may not exist when loading older logs. This can be removed in M62.
function valueOrDefault(value, defaultValue) {
if (value != undefined)
return value;
return defaultValue;
}
return DnsView; return DnsView;
})(); })();
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include "content/public/browser/web_ui_message_handler.h" #include "content/public/browser/web_ui_message_handler.h"
#include "net/base/address_list.h" #include "net/base/address_list.h"
#include "net/base/net_errors.h" #include "net/base/net_errors.h"
#include "net/base/network_change_notifier.h"
#include "net/dns/host_cache.h" #include "net/dns/host_cache.h"
#include "net/dns/host_resolver.h" #include "net/dns/host_resolver.h"
#include "net/dns/mock_host_resolver.h" #include "net/dns/mock_host_resolver.h"
...@@ -117,6 +118,9 @@ class NetInternalsTest::MessageHandler : public content::WebUIMessageHandler { ...@@ -117,6 +118,9 @@ class NetInternalsTest::MessageHandler : public content::WebUIMessageHandler {
// must be an empty string. // must be an empty string.
void AddCacheEntry(const base::ListValue* list_value); void AddCacheEntry(const base::ListValue* list_value);
// Simulates a network change.
void ChangeNetwork(const base::ListValue* list_value);
// Opens the given URL in a new tab. // Opens the given URL in a new tab.
void LoadPage(const base::ListValue* list_value); void LoadPage(const base::ListValue* list_value);
...@@ -164,6 +168,10 @@ void NetInternalsTest::MessageHandler::RegisterMessages() { ...@@ -164,6 +168,10 @@ void NetInternalsTest::MessageHandler::RegisterMessages() {
web_ui()->RegisterMessageCallback("addCacheEntry", web_ui()->RegisterMessageCallback("addCacheEntry",
base::Bind(&NetInternalsTest::MessageHandler::AddCacheEntry, base::Bind(&NetInternalsTest::MessageHandler::AddCacheEntry,
base::Unretained(this))); base::Unretained(this)));
web_ui()->RegisterMessageCallback(
"changeNetwork",
base::Bind(&NetInternalsTest::MessageHandler::ChangeNetwork,
base::Unretained(this)));
web_ui()->RegisterMessageCallback("loadPage", web_ui()->RegisterMessageCallback("loadPage",
base::Bind(&NetInternalsTest::MessageHandler::LoadPage, base::Bind(&NetInternalsTest::MessageHandler::LoadPage,
base::Unretained(this))); base::Unretained(this)));
...@@ -224,6 +232,11 @@ void NetInternalsTest::MessageHandler::AddCacheEntry( ...@@ -224,6 +232,11 @@ void NetInternalsTest::MessageHandler::AddCacheEntry(
static_cast<int>(expire_days_from_now))); static_cast<int>(expire_days_from_now)));
} }
void NetInternalsTest::MessageHandler::ChangeNetwork(
const base::ListValue* list_value) {
net::NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
}
void NetInternalsTest::MessageHandler::LoadPage( void NetInternalsTest::MessageHandler::LoadPage(
const base::ListValue* list_value) { const base::ListValue* list_value) {
std::string url; std::string url;
......
...@@ -101,7 +101,7 @@ AddCacheEntryTask.prototype = { ...@@ -101,7 +101,7 @@ AddCacheEntryTask.prototype = {
* Callback from the BrowserBridge. Checks if |hostResolverInfo| has the * Callback from the BrowserBridge. Checks if |hostResolverInfo| has the
* DNS entry specified on creation. If so, validates it and completes the * DNS entry specified on creation. If so, validates it and completes the
* task. If not, continues running. * task. If not, continues running.
* @param {object} hostResolverInfo Results a host resolver info query. * @param {object} hostResolverInfo Results of a host resolver info query.
*/ */
onHostResolverInfoChanged: function(hostResolverInfo) { onHostResolverInfoChanged: function(hostResolverInfo) {
if (!this.isDone()) { if (!this.isDone()) {
...@@ -129,7 +129,7 @@ AddCacheEntryTask.prototype = { ...@@ -129,7 +129,7 @@ AddCacheEntryTask.prototype = {
// only if |expired_| is true. Only checked for entries we add // only if |expired_| is true. Only checked for entries we add
// ourselves to avoid any expiration time race. // ourselves to avoid any expiration time race.
var expirationText = var expirationText =
NetInternalsTest.getTbodyText(DnsView.CACHE_TBODY_ID, index, 3); NetInternalsTest.getTbodyText(DnsView.CACHE_TBODY_ID, index, 4);
expectEquals(this.expired_, /expired/i.test(expirationText)); expectEquals(this.expired_, /expired/i.test(expirationText));
this.onTaskDone(); this.onTaskDone();
...@@ -149,7 +149,57 @@ AddCacheEntryTask.prototype = { ...@@ -149,7 +149,57 @@ AddCacheEntryTask.prototype = {
}; };
/** /**
* A Task clears the cache by simulating a button click. * A Task that simulates a network change and checks that cache entries are
* expired.
* @extends {NetInternalsTest.Task}
*/
function NetworkChangeTask() {
NetInternalsTest.Task.call(this);
}
NetworkChangeTask.prototype = {
__proto__: NetInternalsTest.Task.prototype,
start: function() {
chrome.send('changeNetwork');
g_browser.addHostResolverInfoObserver(this, false);
},
/**
* Callback from the BrowserBridge. Checks if the entry has been expired.
* If so, the task completes.
* @param {object} hostResolverInfo Results of a host resolver info query.
*/
onHostResolverInfoChanged: function(hostResolverInfo) {
if (!this.isDone()) {
checkDisplay(hostResolverInfo);
var entries = hostResolverInfo.cache.entries;
var tableId = DnsView.CACHE_TBODY_ID;
var foundExpired = false;
// Look for an entry that's expired due to a network change.
for (var row = 0; row < entries.length; ++row) {
var text = NetInternalsTest.getTbodyText(tableId, row, 5);
if (/expired/i.test(text)) {
foundExpired = true;
};
}
if (foundExpired) {
// Expect at least one expired entry and at least one network change.
// To avoid any chance of a race, exact values are not tested.
expectLE(0, parseInt($(DnsView.ACTIVE_SPAN_ID).innerText));
expectLE(1, parseInt($(DnsView.EXPIRED_SPAN_ID).innerText));
expectLE(1, parseInt($(DnsView.NETWORK_SPAN_ID).innerText));
this.onTaskDone();
}
}
}
};
/**
* A Task that clears the cache by simulating a button click.
* @extends {NetInternalsTest.Task} * @extends {NetInternalsTest.Task}
*/ */
function ClearCacheTask() { function ClearCacheTask() {
...@@ -275,4 +325,19 @@ TEST_F('NetInternalsTest', 'netInternalsDnsViewIncognitoClears', function() { ...@@ -275,4 +325,19 @@ TEST_F('NetInternalsTest', 'netInternalsDnsViewIncognitoClears', function() {
taskQueue.run(true); taskQueue.run(true);
}); });
/**
* Adds a successful lookup to the DNS cache, then simulates a network change
* and checks that the entry expires.
*/
TEST_F('NetInternalsTest', 'netInternalsDnsViewNetworkChanged', function() {
NetInternalsTest.switchToView('dns');
var taskQueue = new NetInternalsTest.TaskQueue(true);
taskQueue.addTask(new AddCacheEntryTask(
'somewhere.com', '1.2.3.4', 0, false));
taskQueue.addTask(new NetworkChangeTask());
taskQueue.addTask(new ClearCacheTask());
taskQueue.addTask(new WaitForEntryDestructionTask('somewhere.com'));
taskQueue.run(true);
});
})(); // Anonymous namespace })(); // Anonymous namespace
...@@ -79,6 +79,9 @@ class NET_EXPORT HostCache : NON_EXPORTED_BASE(public base::NonThreadSafe) { ...@@ -79,6 +79,9 @@ class NET_EXPORT HostCache : NON_EXPORTED_BASE(public base::NonThreadSafe) {
base::TimeTicks expires() const { return expires_; } base::TimeTicks expires() const { return expires_; }
// Public for the net-internals UI.
int network_changes() const { return network_changes_; }
private: private:
friend class HostCache; friend class HostCache;
...@@ -87,7 +90,6 @@ class NET_EXPORT HostCache : NON_EXPORTED_BASE(public base::NonThreadSafe) { ...@@ -87,7 +90,6 @@ class NET_EXPORT HostCache : NON_EXPORTED_BASE(public base::NonThreadSafe) {
base::TimeDelta ttl, base::TimeDelta ttl,
int network_changes); int network_changes);
int network_changes() const { return network_changes_; }
int total_hits() const { return total_hits_; } int total_hits() const { return total_hits_; }
int stale_hits() const { return stale_hits_; } int stale_hits() const { return stale_hits_; }
...@@ -158,7 +160,7 @@ class NET_EXPORT HostCache : NON_EXPORTED_BASE(public base::NonThreadSafe) { ...@@ -158,7 +160,7 @@ class NET_EXPORT HostCache : NON_EXPORTED_BASE(public base::NonThreadSafe) {
// Following are used by net_internals UI. // Following are used by net_internals UI.
size_t max_entries() const; size_t max_entries() const;
int network_changes() const { return network_changes_; }
const EntryMap& entries() const { return entries_; } const EntryMap& entries() const { return entries_; }
// Creates a default cache. // Creates a default cache.
......
...@@ -382,6 +382,7 @@ NET_EXPORT std::unique_ptr<base::DictionaryValue> GetNetInfo( ...@@ -382,6 +382,7 @@ NET_EXPORT std::unique_ptr<base::DictionaryValue> GetNetInfo(
cache_info_dict->SetInteger("capacity", cache_info_dict->SetInteger("capacity",
static_cast<int>(cache->max_entries())); static_cast<int>(cache->max_entries()));
cache_info_dict->SetInteger("network_changes", cache->network_changes());
base::ListValue* entry_list = new base::ListValue(); base::ListValue* entry_list = new base::ListValue();
...@@ -397,6 +398,8 @@ NET_EXPORT std::unique_ptr<base::DictionaryValue> GetNetInfo( ...@@ -397,6 +398,8 @@ NET_EXPORT std::unique_ptr<base::DictionaryValue> GetNetInfo(
static_cast<int>(key.address_family)); static_cast<int>(key.address_family));
entry_dict->SetString("expiration", entry_dict->SetString("expiration",
NetLog::TickCountToString(entry.expires())); NetLog::TickCountToString(entry.expires()));
entry_dict->SetInteger("ttl", entry.ttl().InMilliseconds());
entry_dict->SetInteger("network_changes", entry.network_changes());
if (entry.error() != OK) { if (entry.error() != OK) {
entry_dict->SetInteger("error", entry.error()); entry_dict->SetInteger("error", entry.error());
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment