summaryrefslogtreecommitdiffstats
path: root/chrome/browser/resources/net_internals/dataview.js
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/resources/net_internals/dataview.js')
-rw-r--r--chrome/browser/resources/net_internals/dataview.js479
1 files changed, 141 insertions, 338 deletions
diff --git a/chrome/browser/resources/net_internals/dataview.js b/chrome/browser/resources/net_internals/dataview.js
index afe49cb..dad9903 100644
--- a/chrome/browser/resources/net_internals/dataview.js
+++ b/chrome/browser/resources/net_internals/dataview.js
@@ -3,26 +3,31 @@
// found in the LICENSE file.
/**
- * This view displays options for importing/exporting the captured data. Its
- * primarily usefulness is to allow users to copy-paste their data in an easy
- * to read format for bug reports.
+ * This view displays options for importing/exporting the captured data. This
+ * view is responsible for the interface and file I/O. The BrowserBridge
+ * handles creation and loading of the data dumps.
*
- * - Has a button to generate a text report.
+ * - Has a button to generate a JSON dump.
+ *
+ * - Has a button to import a JSON dump.
*
* - Shows how many events have been captured.
* @constructor
*/
function DataView(mainBoxId,
downloadIframeId,
- exportFileButtonId,
+ saveFileButtonId,
+ dataViewSaveStatusTextId,
securityStrippingCheckboxId,
byteLoggingCheckboxId,
passivelyCapturedCountId,
activelyCapturedCountId,
deleteAllId,
dumpDataDivId,
- loadDataDivId,
+ loadedDivId,
+ loadedClientInfoTextId,
loadLogFileId,
+ dataViewLoadStatusTextId,
capturingTextSpanId,
loggingTextSpanId) {
DivView.call(this, mainBoxId);
@@ -38,8 +43,9 @@ function DataView(mainBoxId,
this.downloadIframe_ = document.getElementById(downloadIframeId);
- this.exportFileButton_ = document.getElementById(exportFileButtonId);
- this.exportFileButton_.onclick = this.onExportToText_.bind(this);
+ this.saveFileButton_ = document.getElementById(saveFileButtonId);
+ this.saveFileButton_.onclick = this.onSaveFile_.bind(this);
+ this.saveStatusText_ = document.getElementById(dataViewSaveStatusTextId);
this.activelyCapturedCountBox_ =
document.getElementById(activelyCapturedCountId);
@@ -49,13 +55,15 @@ function DataView(mainBoxId,
g_browser.deleteAllEvents.bind(g_browser);
this.dumpDataDiv_ = document.getElementById(dumpDataDivId);
- this.loadDataDiv_ = document.getElementById(loadDataDivId);
this.capturingTextSpan_ = document.getElementById(capturingTextSpanId);
this.loggingTextSpan_ = document.getElementById(loggingTextSpanId);
- var loadLogFileElement = document.getElementById(loadLogFileId);
- loadLogFileElement.onchange =
- this.logFileChanged.bind(this, loadLogFileElement);
+ this.loadedDiv_ = document.getElementById(loadedDivId);
+ this.loadedClientInfoText_ = document.getElementById(loadedClientInfoTextId);
+
+ this.loadFileElement_ = document.getElementById(loadLogFileId);
+ this.loadFileElement_.onchange = this.logFileChanged.bind(this);
+ this.loadStatusText_ = document.getElementById(dataViewLoadStatusTextId);
this.updateEventCounts_();
@@ -87,14 +95,18 @@ DataView.prototype.onAllLogEntriesDeleted = function() {
};
/**
- * Called when either a log file is loaded or when going back to actively
- * logging events. In either case, called after clearing the old entries,
- * but before getting any new ones.
+ * Called when a log file is loaded, after clearing the old log entries and
+ * loading the new ones. Hides parts of the page related to saving data, and
+ * shows those related to loading. Returns true to indicate the view should
+ * still be visible.
*/
-DataView.prototype.onSetIsViewingLogFile = function(isViewingLogFile) {
- setNodeDisplay(this.dumpDataDiv_, !isViewingLogFile);
- setNodeDisplay(this.capturingTextSpan_, !isViewingLogFile);
- setNodeDisplay(this.loggingTextSpan_, isViewingLogFile);
+DataView.prototype.onLoadLogFinish = function(data) {
+ setNodeDisplay(this.dumpDataDiv_, false);
+ setNodeDisplay(this.capturingTextSpan_, false);
+ setNodeDisplay(this.loggingTextSpan_, true);
+ setNodeDisplay(this.loadedDiv_, true);
+ this.updateLoadedClientInfo();
+ return true;
};
/**
@@ -136,9 +148,10 @@ DataView.prototype.onSecurityStrippingChanged = function() {
*
* Gets the log file from the input element and tries to read from it.
*/
-DataView.prototype.logFileChanged = function(loadLogFileElement) {
- var logFile = loadLogFileElement.files[0];
+DataView.prototype.logFileChanged = function() {
+ var logFile = this.loadFileElement_.files[0];
if (logFile) {
+ this.setLoadFileStatus('Loading log...', true);
var fileReader = new FileReader();
fileReader.onload = this.onLoadLogFile.bind(this);
@@ -150,269 +163,99 @@ DataView.prototype.logFileChanged = function(loadLogFileElement) {
/**
* Displays an error message when unable to read the selected log file.
+ * Also clears the file input control, so the same file can be reloaded.
*/
DataView.prototype.onLoadLogFileError = function(event) {
- alert('Error ' + event.target.error.code + '. Unable to load file.');
+ this.loadFileElement_.value = null;
+ this.setLoadFileStatus(
+ 'Error ' + getKeyWithValue(FileError, event.target.error.code) +
+ '. Unable to read file.',
+ false);
};
-/**
- * Tries to load the contents of the log file.
- */
DataView.prototype.onLoadLogFile = function(event) {
- g_browser.loadedLogFile(event.target.result);
+ var result = loadLogFile(event.target.result);
+ this.setLoadFileStatus(result, false);
};
-DataView.prototype.enableExportFileButton_ = function(enabled) {
- this.exportFileButton_.disabled = !enabled;
+/**
+ * Sets the load from file status text, displayed below the load file button,
+ * to |text|. Also enables or disables the save/load buttons based on the value
+ * of |isLoading|, which must be true if the load process is still ongoing, and
+ * false when the operation has stopped, regardless of success of failure.
+ * Also, when loading is done, replaces the load button so the same file can be
+ * loaded again.
+ */
+DataView.prototype.setLoadFileStatus = function(text, isLoading) {
+ this.enableLoadFileElement_(!isLoading);
+ this.enableSaveFileButton_(!isLoading);
+ this.loadStatusText_.innerText = text;
+ this.saveStatusText_.innerText = '';
+
+ if (!isLoading) {
+ // Clear the button, so the same file can be reloaded. Recreating the
+ // element seems to be the only way to do this.
+ var loadFileElementId = this.loadFileElement_.id;
+ var loadFileElementOnChange = this.loadFileElement_.onchange;
+ this.loadFileElement_.outerHTML = this.loadFileElement_.outerHTML;
+ this.loadFileElement_ = document.getElementById(loadFileElementId);
+ this.loadFileElement_.onchange = loadFileElementOnChange;
+ }
};
/**
- * If not already waiting for results from all updates, triggers all
- * updates and starts waiting for them to complete.
+ * Sets the save to file status text, displayed below the save to file button,
+ * to |text|. Also enables or disables the save/load buttons based on the value
+ * of |isSaving|, which must be true if the save process is still ongoing, and
+ * false when the operation has stopped, regardless of success of failure.
*/
-DataView.prototype.onExportToText_ = function() {
- if (this.exportFileButton_.disabled)
- return;
- this.enableExportFileButton_(false);
+DataView.prototype.setSaveFileStatus = function(text, isSaving) {
+ this.enableSaveFileButton_(!isSaving);
+ this.enableLoadFileElement_(!isSaving);
+ this.loadStatusText_.innerText = '';
+ this.saveStatusText_.innerText = text;
+};
+
+DataView.prototype.enableSaveFileButton_ = function(enabled) {
+ this.saveFileButton_.disabled = !enabled;
+};
- g_browser.updateAllInfo(this.onUpdateAllCompleted.bind(this));
+DataView.prototype.enableLoadFileElement_ = function(enabled) {
+ this.loadFileElement_.disabled = !enabled;
};
/**
- * Presents the captured data as formatted text.
+ * If not already busy loading or saving a log dump, triggers generation of
+ * gathering log dump data and starts waiting for the process to complete.
*/
-DataView.prototype.onUpdateAllCompleted = function(data) {
- // It's possible for a log file to be loaded while a dump is being generated.
- // When that happens, don't display the log dump, to avoid any confusion.
- if (g_browser.isViewingLogFile())
+DataView.prototype.onSaveFile_ = function() {
+ if (this.saveFileButton_.disabled)
return;
- this.waitingForUpdate_ = false;
- var text = [];
-
- // Print some basic information about our environment.
- text.push('Data exported on: ' + (new Date()).toLocaleString());
- text.push('');
- text.push('Number of passively captured events: ' +
- g_browser.getNumPassivelyCapturedEvents());
- text.push('Number of actively captured events: ' +
- g_browser.getNumActivelyCapturedEvents());
- text.push('');
-
- text.push('Chrome version: ' + ClientInfo.version +
- ' (' + ClientInfo.official +
- ' ' + ClientInfo.cl +
- ') ' + ClientInfo.version_mod);
- // Third value in first set of parentheses in user-agent string.
- var platform = /\(.*?;.*?; (.*?);/.exec(navigator.userAgent);
- if (platform)
- text.push('Platform: ' + platform[1]);
- text.push('Command line: ' + ClientInfo.command_line);
-
- text.push('');
- var default_address_family = data.hostResolverInfo.default_address_family;
- text.push('Default address family: ' +
- getKeyWithValue(AddressFamily, default_address_family));
- if (default_address_family == AddressFamily.ADDRESS_FAMILY_IPV4)
- text.push(' (IPv6 disabled)');
-
- text.push('');
- text.push('----------------------------------------------');
- text.push(' Proxy settings (effective)');
- text.push('----------------------------------------------');
- text.push('');
-
- text.push(proxySettingsToString(data.proxySettings.effective));
-
- text.push('');
- text.push('----------------------------------------------');
- text.push(' Proxy settings (original)');
- text.push('----------------------------------------------');
- text.push('');
-
- text.push(proxySettingsToString(data.proxySettings.original));
-
- text.push('');
- text.push('----------------------------------------------');
- text.push(' Bad proxies cache');
- text.push('----------------------------------------------');
-
- var badProxiesList = data.badProxies;
- if (badProxiesList.length == 0) {
- text.push('');
- text.push('None');
- } else {
- for (var i = 0; i < badProxiesList.length; ++i) {
- var e = badProxiesList[i];
- text.push('');
- text.push('(' + (i+1) + ')');
- text.push('Proxy: ' + e.proxy_uri);
- text.push('Bad until: ' + this.formatExpirationTime_(e.bad_until));
- }
- }
-
- text.push('');
- text.push('----------------------------------------------');
- text.push(' Host resolver cache');
- text.push('----------------------------------------------');
- text.push('');
-
- var hostResolverCache = data.hostResolverInfo.cache;
-
- text.push('Capacity: ' + hostResolverCache.capacity);
- text.push('Time to live for successful resolves (ms): ' +
- hostResolverCache.ttl_success_ms);
- text.push('Time to live for failed resolves (ms): ' +
- hostResolverCache.ttl_failure_ms);
-
- if (hostResolverCache.entries.length > 0) {
- for (var i = 0; i < hostResolverCache.entries.length; ++i) {
- var e = hostResolverCache.entries[i];
-
- text.push('');
- text.push('(' + (i+1) + ')');
- text.push('Hostname: ' + e.hostname);
- text.push('Address family: ' +
- getKeyWithValue(AddressFamily, e.address_family));
-
- if (e.error != undefined) {
- text.push('Error: ' + e.error);
- } else {
- for (var j = 0; j < e.addresses.length; ++j) {
- text.push('Address ' + (j + 1) + ': ' + e.addresses[j]);
- }
- }
-
- text.push('Valid until: ' + this.formatExpirationTime_(e.expiration));
- var expirationDate = g_browser.convertTimeTicksToDate(e.expiration);
- text.push(' (' + expirationDate.toLocaleString() + ')');
- }
- } else {
- text.push('');
- text.push('None');
- }
-
- text.push('');
- text.push('----------------------------------------------');
- text.push(' Events');
- text.push('----------------------------------------------');
- text.push('');
-
- this.appendEventsPrintedAsText_(text);
-
- text.push('');
- text.push('----------------------------------------------');
- text.push(' Http cache stats');
- text.push('----------------------------------------------');
- text.push('');
-
- var httpCacheStats = data.httpCacheInfo.stats;
- for (var statName in httpCacheStats)
- text.push(statName + ': ' + httpCacheStats[statName]);
-
- text.push('');
- text.push('----------------------------------------------');
- text.push(' Socket pools');
- text.push('----------------------------------------------');
- text.push('');
-
- this.appendSocketPoolsAsText_(text, data.socketPoolInfo);
-
- text.push('');
- text.push('----------------------------------------------');
- text.push(' SPDY Status');
- text.push('----------------------------------------------');
- text.push('');
-
- text.push('SPDY Enabled: ' + data.spdyStatus.spdy_enabled);
- text.push('Use Alternate Protocol: ' +
- data.spdyStatus.use_alternate_protocols);
- text.push('Force SPDY Always: ' + data.spdyStatus.force_spdy_always);
- text.push('Force SPDY Over SSL: ' + data.spdyStatus.force_spdy_over_ssl);
- text.push('Next Protocols: ' + data.spdyStatus.next_protos);
-
-
- text.push('');
- text.push('----------------------------------------------');
- text.push(' SPDY Sessions');
- text.push('----------------------------------------------');
- text.push('');
-
- if (data.spdySessionInfo == null || data.spdySessionInfo.length == 0) {
- text.push('None');
- } else {
- var spdyTablePrinter =
- SpdyView.createSessionTablePrinter(data.spdySessionInfo);
- text.push(spdyTablePrinter.toText(2));
- }
-
- text.push('');
- text.push('----------------------------------------------');
- text.push(' Alternate Protocol Mappings');
- text.push('----------------------------------------------');
- text.push('');
-
- if (data.spdyAlternateProtocolMappings == null ||
- data.spdyAlternateProtocolMappings.length == 0) {
- text.push('None');
- } else {
- var spdyTablePrinter =
- SpdyView.createAlternateProtocolMappingsTablePrinter(
- data.spdyAlternateProtocolMappings);
- text.push(spdyTablePrinter.toText(2));
- }
-
- if (g_browser.isPlatformWindows()) {
- text.push('');
- text.push('----------------------------------------------');
- text.push(' Winsock layered service providers');
- text.push('----------------------------------------------');
- text.push('');
-
- var serviceProviders = data.serviceProviders;
- var layeredServiceProviders = serviceProviders.service_providers;
- for (var i = 0; i < layeredServiceProviders.length; ++i) {
- var provider = layeredServiceProviders[i];
- text.push('name: ' + provider.name);
- text.push('version: ' + provider.version);
- text.push('type: ' +
- ServiceProvidersView.getLayeredServiceProviderType(provider));
- text.push('socket_type: ' +
- ServiceProvidersView.getSocketType(provider));
- text.push('socket_protocol: ' +
- ServiceProvidersView.getProtocolType(provider));
- text.push('path: ' + provider.path);
- text.push('');
- }
-
- text.push('');
- text.push('----------------------------------------------');
- text.push(' Winsock namespace providers');
- text.push('----------------------------------------------');
- text.push('');
+ this.setSaveFileStatus('Preparing data...', true);
- var namespaceProviders = serviceProviders.namespace_providers;
- for (var i = 0; i < namespaceProviders.length; ++i) {
- var provider = namespaceProviders[i];
- text.push('name: ' + provider.name);
- text.push('version: ' + provider.version);
- text.push('type: ' +
- ServiceProvidersView.getNamespaceProviderType(provider));
- text.push('active: ' + provider.active);
- text.push('');
- }
- }
+ createLogDumpAsync(this.onLogDumpCreated.bind(this));
+};
+/**
+ * Starts the process of creating a file containing |dumpText| and downloading
+ * it.
+ */
+DataView.prototype.onLogDumpCreated = function(dumpText) {
var blobBuilder = new WebKitBlobBuilder();
- blobBuilder.append(text.join('\n'), 'native');
+ blobBuilder.append(dumpText, 'native');
var textBlob = blobBuilder.getBlob('octet/stream');
+ this.setSaveFileStatus('Creating file...', true);
+
window.webkitRequestFileSystem(
window.TEMPORARY, textBlob.size,
this.onFileSystemCreate_.bind(this, textBlob),
this.onFileError_.bind(this, 'Unable to create file system.'));
};
-// Once we have access to the file system, create a log file.
+/**
+ * Once we have access to the file system, create a log file.
+ */
DataView.prototype.onFileSystemCreate_ = function(textBlob, fileSystem) {
fileSystem.root.getFile(
'net_internals.log', {create: true},
@@ -420,16 +263,19 @@ DataView.prototype.onFileSystemCreate_ = function(textBlob, fileSystem) {
this.onFileError_.bind(this, 'Unable to create file.'));
};
-// Once the file is created, or an existing one has been opened, create a
-// writer for it.
+/**
+ * Once the file is created, or an existing one has been opened, create a
+ * writer for it.
+ */
DataView.prototype.onFileCreate_ = function(textBlob, fileEntry) {
fileEntry.createWriter(
this.onFileCreateWriter_.bind(this, textBlob, fileEntry),
this.onFileError_.bind(this, 'Unable to create writer.'));
};
-// Once the |fileWriter| has been created, truncate the file, in case it already
-// existed.
+/* Once the |fileWriter| has been created, truncate the file, in case it already
+ * existed.
+ */
DataView.prototype.onFileCreateWriter_ = function(textBlob,
fileEntry, fileWriter) {
fileWriter.onerror = this.onFileError_.bind(this, 'Truncate failed.');
@@ -438,100 +284,57 @@ DataView.prototype.onFileCreateWriter_ = function(textBlob,
fileWriter.truncate(0);
};
-// Once the file has been truncated, write |textBlob| to the file.
+/**
+ * Once the file has been truncated, write |textBlob| to the file.
+ */
DataView.prototype.onFileTruncate_ = function(textBlob, fileWriter, fileEntry) {
fileWriter.onerror = this.onFileError_.bind(this, 'Write failed.');
fileWriter.onwriteend = this.onFileWriteComplete_.bind(this, fileEntry);
fileWriter.write(textBlob);
};
-// Once the file has been written to, start the download.
+/**
+ * Once the file has been written to, start the download.
+ */
DataView.prototype.onFileWriteComplete_ = function(fileEntry) {
this.downloadIframe_.src = fileEntry.toURL();
- this.enableExportFileButton_(true);
+ this.setSaveFileStatus('Dump successful', false);
};
-// On any Javascript File API error, enable the export button and display
-// |errorText|, followed by the specific error.
+/**
+ * On any Javascript File API error, enable the save button and display
+ * |errorText|, followed by the specific error.
+ */
DataView.prototype.onFileError_ = function(errorText, error) {
- this.enableExportFileButton_(true);
- alert(errorText + ' ' + getKeyWithValue(FileError, error.code));
+ this.enableSaveFileButton_(true);
+ this.setSaveFileStatus(
+ errorText + ' ' + getKeyWithValue(FileError, error.code),
+ false);
};
-DataView.prototype.appendEventsPrintedAsText_ = function(out) {
- var allEvents = g_browser.getAllCapturedEvents();
-
- // Group the events into buckets by source ID, and buckets by source type.
- var sourceIds = [];
- var sourceIdToEventList = {};
- var sourceTypeToSourceIdList = {};
-
- // Lists used for actual output.
- var eventLists = [];
-
- for (var i = 0; i < allEvents.length; ++i) {
- var e = allEvents[i];
- var eventList = sourceIdToEventList[e.source.id];
- if (!eventList) {
- eventList = [];
- eventLists.push(eventList);
- if (e.source.type != LogSourceType.NONE)
- sourceIdToEventList[e.source.id] = eventList;
-
- // Update sourceIds
- sourceIds.push(e.source.id);
-
- // Update the sourceTypeToSourceIdList list.
- var idList = sourceTypeToSourceIdList[e.source.type];
- if (!idList) {
- idList = [];
- sourceTypeToSourceIdList[e.source.type] = idList;
- }
- idList.push(e.source.id);
- }
- eventList.push(e);
- }
-
-
- // For each source or event without a source (ordered by when the first
- // output event for that source happened).
- for (var i = 0; i < eventLists.length; ++i) {
- var eventList = eventLists[i];
- var sourceId = eventList[0].source.id;
- var sourceType = eventList[0].source.type;
-
- var startDate = g_browser.convertTimeTicksToDate(eventList[0].time);
+/**
+ * Prints some basic information about the environment when the log was made.
+ */
+DataView.prototype.updateLoadedClientInfo = function() {
+ this.loadedClientInfoText_.innerText = '';
+ if (typeof(ClientInfo) != 'object')
+ return;
- out.push('------------------------------------------');
- out.push(getKeyWithValue(LogSourceType, sourceType) +
- ' (id=' + sourceId + ')' +
- ' [start=' + startDate.toLocaleString() + ']');
- out.push('------------------------------------------');
+ var text = [];
- out.push(PrintSourceEntriesAsText(eventList));
+ // Dumps made with the command line option don't have a date.
+ if (ClientInfo.date) {
+ text.push('Data exported on: ' + ClientInfo.date);
+ text.push('');
}
-};
-DataView.prototype.appendSocketPoolsAsText_ = function(text, socketPoolInfo) {
- var socketPools = SocketPoolWrapper.createArrayFrom(socketPoolInfo);
- var tablePrinter = SocketPoolWrapper.createTablePrinter(socketPools);
- text.push(tablePrinter.toText(2));
-
- text.push('');
-
- for (var i = 0; i < socketPools.length; ++i) {
- if (socketPools[i].origPool.groups == undefined)
- continue;
- var groupTablePrinter = socketPools[i].createGroupTablePrinter();
- text.push(groupTablePrinter.toText(2));
- }
-};
+ text.push(ClientInfo.name +
+ ' ' + ClientInfo.version +
+ ' (' + ClientInfo.official +
+ ' ' + ClientInfo.cl +
+ ') ' + ClientInfo.version_mod);
+ text.push('OS Type: ' + ClientInfo.os_type);
+ text.push('Command line: ' + ClientInfo.command_line);
-/**
- * Format a time ticks count as a timestamp.
- */
-DataView.prototype.formatExpirationTime_ = function(timeTicks) {
- var d = g_browser.convertTimeTicksToDate(timeTicks);
- var isExpired = d.getTime() < (new Date()).getTime();
- return 't=' + d.getTime() + (isExpired ? ' [EXPIRED]' : '');
+ this.loadedClientInfoText_.innerText = text.join('\n');
};