Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 /** | 5 /** |
| 6 * This view displays options for importing/exporting the captured data. Its | 6 * This view displays options for importing/exporting the captured data. Its |
| 7 * primarily usefulness is to allow users to copy-paste their data in an easy | 7 * primarily usefulness is to allow users to copy-paste their data in an easy |
| 8 * to read format for bug reports. | 8 * to read format for bug reports. |
| 9 * | 9 * |
| 10 * - Has a button to generate a text report. | 10 * - Has a button to generate a text report. |
| 11 * | 11 * |
| 12 * - Shows how many events have been captured. | 12 * - Shows how many events have been captured. |
| 13 * @constructor | 13 * @constructor |
| 14 */ | 14 */ |
| 15 function DataView(mainBoxId, | 15 function DataView(mainBoxId, |
| 16 outputTextBoxId, | |
| 17 exportTextButtonId, | 16 exportTextButtonId, |
| 18 securityStrippingCheckboxId, | 17 securityStrippingCheckboxId, |
| 19 byteLoggingCheckboxId, | 18 byteLoggingCheckboxId, |
| 20 passivelyCapturedCountId, | 19 passivelyCapturedCountId, |
| 21 activelyCapturedCountId, | 20 activelyCapturedCountId, |
| 22 deleteAllId, | 21 deleteAllId, |
| 23 dumpDataDivId, | 22 dumpDataDivId, |
| 24 loadDataDivId, | 23 loadDataDivId, |
| 25 loadLogFileId, | 24 loadLogFileId, |
| 26 capturingTextSpanId, | 25 capturingTextSpanId, |
| 27 loggingTextSpanId) { | 26 loggingTextSpanId) { |
| 28 DivView.call(this, mainBoxId); | 27 DivView.call(this, mainBoxId); |
| 29 | 28 |
| 30 this.textPre_ = document.getElementById(outputTextBoxId); | |
| 31 | |
| 32 var securityStrippingCheckbox = | 29 var securityStrippingCheckbox = |
| 33 document.getElementById(securityStrippingCheckboxId); | 30 document.getElementById(securityStrippingCheckboxId); |
| 34 securityStrippingCheckbox.onclick = | 31 securityStrippingCheckbox.onclick = |
| 35 this.onSetSecurityStripping_.bind(this, securityStrippingCheckbox); | 32 this.onSetSecurityStripping_.bind(this, securityStrippingCheckbox); |
| 36 | 33 |
| 37 var byteLoggingCheckbox = document.getElementById(byteLoggingCheckboxId); | 34 var byteLoggingCheckbox = document.getElementById(byteLoggingCheckboxId); |
| 38 byteLoggingCheckbox.onclick = | 35 byteLoggingCheckbox.onclick = |
| 39 this.onSetByteLogging_.bind(this, byteLoggingCheckbox); | 36 this.onSetByteLogging_.bind(this, byteLoggingCheckbox); |
| 40 | 37 |
| 41 var exportTextButton = document.getElementById(exportTextButtonId); | 38 this.exportTextButton_ = document.getElementById(exportTextButtonId); |
| 42 exportTextButton.onclick = this.onExportToText_.bind(this); | 39 this.exportTextButton_.onclick = this.onExportToText_.bind(this); |
| 43 | 40 |
| 44 this.activelyCapturedCountBox_ = | 41 this.activelyCapturedCountBox_ = |
| 45 document.getElementById(activelyCapturedCountId); | 42 document.getElementById(activelyCapturedCountId); |
| 46 this.passivelyCapturedCountBox_ = | 43 this.passivelyCapturedCountBox_ = |
| 47 document.getElementById(passivelyCapturedCountId); | 44 document.getElementById(passivelyCapturedCountId); |
| 48 document.getElementById(deleteAllId).onclick = | 45 document.getElementById(deleteAllId).onclick = |
| 49 g_browser.deleteAllEvents.bind(g_browser); | 46 g_browser.deleteAllEvents.bind(g_browser); |
| 50 | 47 |
| 51 this.dumpDataDiv_ = document.getElementById(dumpDataDivId); | 48 this.dumpDataDiv_ = document.getElementById(dumpDataDivId); |
| 52 this.loadDataDiv_ = document.getElementById(loadDataDivId); | 49 this.loadDataDiv_ = document.getElementById(loadDataDivId); |
| 53 this.capturingTextSpan_ = document.getElementById(capturingTextSpanId); | 50 this.capturingTextSpan_ = document.getElementById(capturingTextSpanId); |
| 54 this.loggingTextSpan_ = document.getElementById(loggingTextSpanId); | 51 this.loggingTextSpan_ = document.getElementById(loggingTextSpanId); |
| 55 | 52 |
| 56 var loadLogFileElement = document.getElementById(loadLogFileId); | 53 var loadLogFileElement = document.getElementById(loadLogFileId); |
| 57 loadLogFileElement.onchange = | 54 loadLogFileElement.onchange = |
| 58 this.logFileChanged.bind(this, loadLogFileElement); | 55 this.logFileChanged.bind(this, loadLogFileElement); |
| 59 | 56 |
| 60 this.updateEventCounts_(); | 57 this.updateEventCounts_(); |
| 61 this.waitingForUpdate_ = false; | |
| 62 | 58 |
| 63 g_browser.addLogObserver(this); | 59 g_browser.addLogObserver(this); |
| 64 } | 60 } |
| 65 | 61 |
| 66 inherits(DataView, DivView); | 62 inherits(DataView, DivView); |
| 67 | 63 |
| 68 /** | 64 /** |
| 69 * Called whenever a new event is received. | 65 * Called whenever a new event is received. |
| 70 */ | 66 */ |
| 71 DataView.prototype.onLogEntryAdded = function(logEntry) { | 67 DataView.prototype.onLogEntryAdded = function(logEntry) { |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 89 | 85 |
| 90 /** | 86 /** |
| 91 * Called when either a log file is loaded or when going back to actively | 87 * Called when either a log file is loaded or when going back to actively |
| 92 * logging events. In either case, called after clearing the old entries, | 88 * logging events. In either case, called after clearing the old entries, |
| 93 * but before getting any new ones. | 89 * but before getting any new ones. |
| 94 */ | 90 */ |
| 95 DataView.prototype.onSetIsViewingLogFile = function(isViewingLogFile) { | 91 DataView.prototype.onSetIsViewingLogFile = function(isViewingLogFile) { |
| 96 setNodeDisplay(this.dumpDataDiv_, !isViewingLogFile); | 92 setNodeDisplay(this.dumpDataDiv_, !isViewingLogFile); |
| 97 setNodeDisplay(this.capturingTextSpan_, !isViewingLogFile); | 93 setNodeDisplay(this.capturingTextSpan_, !isViewingLogFile); |
| 98 setNodeDisplay(this.loggingTextSpan_, isViewingLogFile); | 94 setNodeDisplay(this.loggingTextSpan_, isViewingLogFile); |
| 99 this.setText_(''); | |
| 100 }; | 95 }; |
| 101 | 96 |
| 102 /** | 97 /** |
| 103 * Updates the counters showing how many events have been captured. | 98 * Updates the counters showing how many events have been captured. |
| 104 */ | 99 */ |
| 105 DataView.prototype.updateEventCounts_ = function() { | 100 DataView.prototype.updateEventCounts_ = function() { |
| 106 this.activelyCapturedCountBox_.innerText = | 101 this.activelyCapturedCountBox_.innerText = |
| 107 g_browser.getNumActivelyCapturedEvents() | 102 g_browser.getNumActivelyCapturedEvents() |
| 108 this.passivelyCapturedCountBox_.innerText = | 103 this.passivelyCapturedCountBox_.innerText = |
| 109 g_browser.getNumPassivelyCapturedEvents(); | 104 g_browser.getNumPassivelyCapturedEvents(); |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 123 | 118 |
| 124 /** | 119 /** |
| 125 * Depending on the value of the checkbox, enables or disables stripping | 120 * Depending on the value of the checkbox, enables or disables stripping |
| 126 * cookies and passwords from log dumps and displayed events. | 121 * cookies and passwords from log dumps and displayed events. |
| 127 */ | 122 */ |
| 128 DataView.prototype.onSetSecurityStripping_ = | 123 DataView.prototype.onSetSecurityStripping_ = |
| 129 function(securityStrippingCheckbox) { | 124 function(securityStrippingCheckbox) { |
| 130 g_browser.setSecurityStripping(securityStrippingCheckbox.checked); | 125 g_browser.setSecurityStripping(securityStrippingCheckbox.checked); |
| 131 }; | 126 }; |
| 132 | 127 |
| 133 /** | |
| 134 * Clears displayed text when security stripping is toggled. | |
| 135 */ | |
| 136 DataView.prototype.onSecurityStrippingChanged = function() { | 128 DataView.prototype.onSecurityStrippingChanged = function() { |
| 137 this.setText_(''); | |
| 138 } | 129 } |
| 139 | 130 |
| 140 /** | 131 /** |
| 141 * Called when a log file is selected. | 132 * Called when a log file is selected. |
| 142 * | 133 * |
| 143 * Gets the log file from the input element and tries to read from it. | 134 * Gets the log file from the input element and tries to read from it. |
| 144 */ | 135 */ |
| 145 DataView.prototype.logFileChanged = function(loadLogFileElement) { | 136 DataView.prototype.logFileChanged = function(loadLogFileElement) { |
| 146 var logFile = loadLogFileElement.files[0]; | 137 var logFile = loadLogFileElement.files[0]; |
| 147 if (logFile) { | 138 if (logFile) { |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 161 alert('Error ' + event.target.error.code + '. Unable to load file.'); | 152 alert('Error ' + event.target.error.code + '. Unable to load file.'); |
| 162 } | 153 } |
| 163 | 154 |
| 164 /** | 155 /** |
| 165 * Tries to load the contents of the log file. | 156 * Tries to load the contents of the log file. |
| 166 */ | 157 */ |
| 167 DataView.prototype.onLoadLogFile = function(event) { | 158 DataView.prototype.onLoadLogFile = function(event) { |
| 168 g_browser.loadedLogFile(event.target.result); | 159 g_browser.loadedLogFile(event.target.result); |
| 169 } | 160 } |
| 170 | 161 |
| 162 DataView.prototype.EnableExportTextButton_ = function(enabled) { | |
|
eroman
2011/06/16 00:42:02
nit: use lowercaseCamelCase for function names in
mmenke
2011/06/16 16:16:53
Done.
| |
| 163 this.exportTextButton_.disabled = !enabled; | |
| 164 } | |
| 165 | |
| 171 /** | 166 /** |
| 172 * If not already waiting for results from all updates, triggers all | 167 * If not already waiting for results from all updates, triggers all |
| 173 * updates and starts waiting for them to complete. | 168 * updates and starts waiting for them to complete. |
| 174 */ | 169 */ |
| 175 DataView.prototype.onExportToText_ = function() { | 170 DataView.prototype.onExportToText_ = function() { |
| 176 if (this.waitingForUpdate_) | 171 if (this.exportTextButton_.disabled) |
| 177 return; | 172 return; |
| 178 this.waitingForUpdate = true; | 173 this.EnableExportTextButton_(false); |
| 179 this.setText_('Generating...'); | 174 |
| 180 g_browser.updateAllInfo(this.onUpdateAllCompleted.bind(this)); | 175 g_browser.updateAllInfo(this.onUpdateAllCompleted.bind(this)); |
| 181 }; | 176 }; |
| 182 | 177 |
| 183 /** | 178 /** |
| 184 * Presents the captured data as formatted text. | 179 * Presents the captured data as formatted text. |
| 185 */ | 180 */ |
| 186 DataView.prototype.onUpdateAllCompleted = function(data) { | 181 DataView.prototype.onUpdateAllCompleted = function(data) { |
| 187 // It's possible for a log file to be loaded while a dump is being generated. | 182 // It's possible for a log file to be loaded while a dump is being generated. |
| 188 // When that happens, don't display the log dump, to avoid any confusion. | 183 // When that happens, don't display the log dump, to avoid any confusion. |
| 189 if (g_browser.isViewingLogFile()) | 184 if (g_browser.isViewingLogFile()) |
| (...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 397 var provider = namespaceProviders[i]; | 392 var provider = namespaceProviders[i]; |
| 398 text.push('name: ' + provider.name); | 393 text.push('name: ' + provider.name); |
| 399 text.push('version: ' + provider.version); | 394 text.push('version: ' + provider.version); |
| 400 text.push('type: ' + | 395 text.push('type: ' + |
| 401 ServiceProvidersView.getNamespaceProviderType(provider)); | 396 ServiceProvidersView.getNamespaceProviderType(provider)); |
| 402 text.push('active: ' + provider.active); | 397 text.push('active: ' + provider.active); |
| 403 text.push(''); | 398 text.push(''); |
| 404 } | 399 } |
| 405 } | 400 } |
| 406 | 401 |
| 407 // Open a new window to display this text. | 402 var chunkSize = 100 * 1024; |
|
eroman
2011/06/16 00:42:02
chunkSize is unused.
mmenke
2011/06/16 16:16:53
Removed. Accidentally left over from one of the a
| |
| 408 this.setText_(text.join('\n')); | 403 var flatText = text.join('\n'); |
| 404 window.webkitRequestFileSystem( | |
| 405 window.TEMPORARY, 10*1024 + flatText.length, | |
|
eroman
2011/06/16 00:42:02
nit: the assumption here is that 1 character = 1 b
mmenke
2011/06/16 16:16:53
Fixed. Thanks for catching that. Be a pain to ru
| |
| 406 this.OnFileSystemCreate_.bind(this, flatText), | |
| 407 this.OnFileError_.bind(this, 'Unable to create file system.')); | |
| 408 }; | |
| 409 | 409 |
| 410 this.selectText_(); | 410 DataView.prototype.OnFileSystemCreate_ = function(text, fileSystem) { |
|
eroman
2011/06/16 00:42:02
I believe javascript style stipulates lowercase fo
mmenke
2011/06/16 16:16:53
Fixed everywhere.
| |
| 411 }; | 411 fileSystem.root.getFile( |
| 412 'net_internals_log.txt', {create: true}, | |
|
eroman
2011/06/16 00:42:02
I wander if we should include a unique identifier
mmenke
2011/06/16 16:16:53
I considered that, but wasn't sure it was worth th
| |
| 413 this.OnFileCreate_.bind(this, text), | |
| 414 this.OnFileError_.bind(this, 'Unable to create file.')); | |
| 415 } | |
|
eroman
2011/06/16 00:42:02
nit: can you put semicolon after all of these "sta
mmenke
2011/06/16 16:16:53
Done.
| |
| 416 | |
| 417 DataView.prototype.OnFileCreate_ = function(text, fileEntry) { | |
| 418 fileEntry.createWriter( | |
| 419 this.OnFileCreateWriter_.bind(this, text, fileEntry), | |
| 420 this.OnFileError_.bind(this, 'Unable to create writer.')); | |
| 421 } | |
| 422 | |
| 423 DataView.prototype.OnFileCreateWriter_ = function(text, fileEntry, fileWriter) { | |
| 424 fileWriter.onerror = this.OnFileError_.bind(this, 'Write failed.') | |
| 425 fileWriter.onwriteend = this.OnFileWriteComplete_.bind(this, fileEntry) | |
| 426 var blobBuilder = new WebKitBlobBuilder(); | |
| 427 blobBuilder.append(text); | |
|
eroman
2011/06/16 00:42:02
Do you know how it serializes strings? UTF16? UTF8
mmenke
2011/06/16 16:16:53
Experimentally, just writes out UTF8.
| |
| 428 fileWriter.write(blobBuilder.getBlob('octet/stream')); | |
|
eroman
2011/06/16 00:42:02
One annoyance is line ending on Windows are CR LF,
mmenke
2011/06/16 16:16:53
Fixed (Use CRLF on Windows only).
| |
| 429 } | |
| 430 | |
| 431 DataView.prototype.OnFileWriteComplete_ = function(fileEntry) { | |
| 432 window.location = fileEntry.toURL(); | |
|
eroman
2011/06/16 00:42:02
Not a big deal, but this might cause a flicker in
mmenke
2011/06/16 16:16:53
We don't actually update the address bar until we'
mmenke
2011/06/16 16:26:59
Well...I was wrong about this. I'll go ahead and
| |
| 433 this.EnableExportTextButton_(true); | |
| 434 } | |
| 435 | |
| 436 DataView.prototype.OnFileError_ = function(errorText, error) { | |
| 437 this.EnableExportTextButton_(true); | |
| 438 alert(errorText + ' Error: ' + error.code); | |
|
eroman
2011/06/16 00:42:02
I suggest giving a more informative message, since
mmenke
2011/06/16 16:16:53
Done.
| |
| 439 } | |
| 412 | 440 |
| 413 DataView.prototype.appendEventsPrintedAsText_ = function(out) { | 441 DataView.prototype.appendEventsPrintedAsText_ = function(out) { |
| 414 var allEvents = g_browser.getAllCapturedEvents(); | 442 var allEvents = g_browser.getAllCapturedEvents(); |
| 415 | 443 |
| 416 // Group the events into buckets by source ID, and buckets by source type. | 444 // Group the events into buckets by source ID, and buckets by source type. |
| 417 var sourceIds = []; | 445 var sourceIds = []; |
| 418 var sourceIdToEventList = {}; | 446 var sourceIdToEventList = {}; |
| 419 var sourceTypeToSourceIdList = {}; | 447 var sourceTypeToSourceIdList = {}; |
| 420 | 448 |
| 421 // Lists used for actual output. | 449 // Lists used for actual output. |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 473 | 501 |
| 474 for (var i = 0; i < socketPools.length; ++i) { | 502 for (var i = 0; i < socketPools.length; ++i) { |
| 475 if (socketPools[i].origPool.groups == undefined) | 503 if (socketPools[i].origPool.groups == undefined) |
| 476 continue; | 504 continue; |
| 477 var groupTablePrinter = socketPools[i].createGroupTablePrinter(); | 505 var groupTablePrinter = socketPools[i].createGroupTablePrinter(); |
| 478 text.push(groupTablePrinter.toText(2)); | 506 text.push(groupTablePrinter.toText(2)); |
| 479 } | 507 } |
| 480 }; | 508 }; |
| 481 | 509 |
| 482 /** | 510 /** |
| 483 * Helper function to set this view's content to |text|. | |
| 484 */ | |
| 485 DataView.prototype.setText_ = function(text) { | |
| 486 this.textPre_.innerHTML = ''; | |
| 487 addTextNode(this.textPre_, text); | |
| 488 }; | |
| 489 | |
| 490 /** | |
| 491 * Format a time ticks count as a timestamp. | 511 * Format a time ticks count as a timestamp. |
| 492 */ | 512 */ |
| 493 DataView.prototype.formatExpirationTime_ = function(timeTicks) { | 513 DataView.prototype.formatExpirationTime_ = function(timeTicks) { |
| 494 var d = g_browser.convertTimeTicksToDate(timeTicks); | 514 var d = g_browser.convertTimeTicksToDate(timeTicks); |
| 495 var isExpired = d.getTime() < (new Date()).getTime(); | 515 var isExpired = d.getTime() < (new Date()).getTime(); |
| 496 return 't=' + d.getTime() + (isExpired ? ' [EXPIRED]' : ''); | 516 return 't=' + d.getTime() + (isExpired ? ' [EXPIRED]' : ''); |
| 497 }; | 517 }; |
| 498 | |
| 499 /** | |
| 500 * Select all text from log dump. | |
| 501 */ | |
| 502 DataView.prototype.selectText_ = function() { | |
| 503 var selection = window.getSelection(); | |
| 504 selection.removeAllRanges(); | |
| 505 | |
| 506 var range = document.createRange(); | |
| 507 range.selectNodeContents(this.textPre_); | |
| 508 selection.addRange(range); | |
| 509 }; | |
| OLD | NEW |