OLD | NEW |
(Empty) | |
| 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 * Dictionary of constants (Initialized soon after loading by data from browser, |
| 7 * updated on load log). The *Types dictionaries map strings to numeric IDs, |
| 8 * while the *TypeNames are the other way around. |
| 9 */ |
| 10 var EventType = null; |
| 11 var EventTypeNames = null; |
| 12 var EventPhase = null; |
| 13 var EventSourceType = null; |
| 14 var EventSourceTypeNames = null; |
| 15 var ClientInfo = null; |
| 16 var NetError = null; |
| 17 var QuicError = null; |
| 18 var QuicRstStreamError = null; |
| 19 var LoadFlag = null; |
| 20 var CertStatusFlag = null; |
| 21 var LoadState = null; |
| 22 var AddressFamily = null; |
| 23 var SdchProblemCode = null; |
| 24 var DataReductionProxyBypassEventType = null; |
| 25 |
| 26 /** |
| 27 * Dictionary of all constants, used for saving log files. |
| 28 */ |
| 29 var Constants = null; |
| 30 |
| 31 /** |
| 32 * Object to communicate between the renderer and the browser. |
| 33 * @type {!BrowserBridge} |
| 34 */ |
| 35 var g_browser = null; |
| 36 |
| 37 /** |
| 38 * This class is the root view object of the page. It owns all the other |
| 39 * views, and manages switching between them. It is also responsible for |
| 40 * initializing the views and the BrowserBridge. |
| 41 */ |
| 42 var MainView = (function() { |
| 43 'use strict'; |
| 44 |
| 45 // We inherit from WindowView |
| 46 var superClass = WindowView; |
| 47 |
| 48 /** |
| 49 * Main entry point. Called once the page has loaded. |
| 50 * @constructor |
| 51 */ |
| 52 function MainView() { |
| 53 assertFirstConstructorCall(MainView); |
| 54 |
| 55 if (hasTouchScreen()) |
| 56 document.body.classList.add('touch'); |
| 57 |
| 58 // This must be initialized before the tabs, so they can register as |
| 59 // observers. |
| 60 g_browser = BrowserBridge.getInstance(); |
| 61 |
| 62 // This must be the first constants observer, so other constants observers |
| 63 // can safely use the globals, rather than depending on walking through |
| 64 // the constants themselves. |
| 65 g_browser.addConstantsObserver(new ConstantsObserver()); |
| 66 |
| 67 // Create the tab switcher. |
| 68 this.initTabs_(); |
| 69 |
| 70 // Cut out a small vertical strip at the top of the window, to display |
| 71 // a high level status (i.e. if we are capturing events, or displaying a |
| 72 // log file). Below it we will position the main tabs and their content |
| 73 // area. |
| 74 this.topBarView_ = TopBarView.getInstance(this); |
| 75 var verticalSplitView = new VerticalSplitView( |
| 76 this.topBarView_, this.tabSwitcher_); |
| 77 |
| 78 superClass.call(this, verticalSplitView); |
| 79 |
| 80 // Trigger initial layout. |
| 81 this.resetGeometry(); |
| 82 |
| 83 window.onhashchange = this.onUrlHashChange_.bind(this); |
| 84 |
| 85 // Select the initial view based on the current URL. |
| 86 window.onhashchange(); |
| 87 |
| 88 // No log file loaded yet so set the status bar to that state. |
| 89 this.topBarView_.switchToSubView('loaded').setFileName( |
| 90 'No log to display.'); |
| 91 |
| 92 // TODO(rayraymond): Follow-up is to completely remove all code from |
| 93 // g_browser that interacts with sending/receiving messages from |
| 94 // browser. |
| 95 g_browser.disable(); |
| 96 } |
| 97 |
| 98 cr.addSingletonGetter(MainView); |
| 99 |
| 100 // Tracks if we're viewing a loaded log file, so views can behave |
| 101 // appropriately. Global so safe to call during construction. |
| 102 var isViewingLoadedLog = false; |
| 103 |
| 104 MainView.isViewingLoadedLog = function() { |
| 105 return isViewingLoadedLog; |
| 106 }; |
| 107 |
| 108 MainView.prototype = { |
| 109 // Inherit the superclass's methods. |
| 110 __proto__: superClass.prototype, |
| 111 |
| 112 // This is exposed both so the log import/export code can enumerate all the |
| 113 // tabs, and for testing. |
| 114 tabSwitcher: function() { |
| 115 return this.tabSwitcher_; |
| 116 }, |
| 117 |
| 118 /** |
| 119 * Prevents receiving/sending events to/from the browser, so loaded data |
| 120 * will not be mixed with current Chrome state. Also hides any interactive |
| 121 * HTML elements that send messages to the browser. Cannot be undone |
| 122 * without reloading the page. Must be called before passing loaded data |
| 123 * to the individual views. |
| 124 * |
| 125 * @param {string} opt_fileName The name of the log file that has been |
| 126 * loaded, if we're loading a log file. |
| 127 */ |
| 128 onLoadLog: function(opt_fileName) { |
| 129 isViewingLoadedLog = true; |
| 130 |
| 131 this.stopCapturing(); |
| 132 if (opt_fileName != undefined) { |
| 133 // If there's a file name, a log file was loaded, so swap out the status |
| 134 // bar to indicate we're no longer capturing events. |
| 135 this.topBarView_.switchToSubView('loaded').setFileName(opt_fileName); |
| 136 SourceTracker.getInstance().setPrivacyStripping(false); |
| 137 } |
| 138 }, |
| 139 |
| 140 switchToViewOnlyMode: function() { |
| 141 // Since this won't be dumped to a file, we don't want to remove |
| 142 // cookies and credentials. |
| 143 log_util.createLogDumpAsync('', log_util.loadLogFile, false); |
| 144 }, |
| 145 |
| 146 stopCapturing: function() { |
| 147 g_browser.disable(); |
| 148 document.styleSheets[0].insertRule( |
| 149 '.hide-when-not-capturing { display: none; }', 0); |
| 150 }, |
| 151 |
| 152 initTabs_: function() { |
| 153 this.tabIdToHash_ = {}; |
| 154 this.hashToTabId_ = {}; |
| 155 |
| 156 this.tabSwitcher_ = new TabSwitcherView(this.onTabSwitched_.bind(this)); |
| 157 |
| 158 // Helper function to add a tab given the class for a view singleton. |
| 159 var addTab = function(viewClass) { |
| 160 var tabId = viewClass.TAB_ID; |
| 161 var tabHash = viewClass.TAB_HASH; |
| 162 var tabName = viewClass.TAB_NAME; |
| 163 var view = viewClass.getInstance(); |
| 164 |
| 165 if (!tabId || !view || !tabHash || !tabName) { |
| 166 throw Error('Invalid view class for tab'); |
| 167 } |
| 168 |
| 169 if (tabHash.charAt(0) != '#') { |
| 170 throw Error('Tab hashes must start with a #'); |
| 171 } |
| 172 |
| 173 this.tabSwitcher_.addTab(tabId, view, tabName, tabHash); |
| 174 this.tabIdToHash_[tabId] = tabHash; |
| 175 this.hashToTabId_[tabHash] = tabId; |
| 176 }.bind(this); |
| 177 |
| 178 // Populate the main tabs. Even tabs that don't contain information for |
| 179 // the running OS should be created, so they can load log dumps from other |
| 180 // OSes. |
| 181 addTab(ImportView); |
| 182 addTab(ProxyView); |
| 183 addTab(EventsView); |
| 184 addTab(TimelineView); |
| 185 addTab(DnsView); |
| 186 addTab(SocketsView); |
| 187 addTab(AltSvcView); |
| 188 addTab(SpdyView); |
| 189 addTab(QuicView); |
| 190 addTab(SdchView); |
| 191 addTab(HttpCacheView); |
| 192 // TODO(rayraymond): Re-enable, Modules, Bandwidth, and Prerender tabs. |
| 193 // addTab(ModulesView); |
| 194 // addTab(BandwidthView); |
| 195 // addTab(PrerenderView); |
| 196 addTab(CrosView); |
| 197 |
| 198 this.tabSwitcher_.showTabLink(CrosView.TAB_ID, cr.isChromeOS); |
| 199 }, |
| 200 |
| 201 /** |
| 202 * This function is called by the tab switcher when the current tab has been |
| 203 * changed. It will update the current URL to reflect the new active tab, |
| 204 * so the back can be used to return to previous view. |
| 205 */ |
| 206 onTabSwitched_: function(oldTabId, newTabId) { |
| 207 // Update data needed by newly active tab, as it may be |
| 208 // significantly out of date. |
| 209 if (g_browser) |
| 210 g_browser.checkForUpdatedInfo(); |
| 211 |
| 212 // Change the URL to match the new tab. |
| 213 |
| 214 var newTabHash = this.tabIdToHash_[newTabId]; |
| 215 var parsed = parseUrlHash_(window.location.hash); |
| 216 if (parsed.tabHash != newTabHash) { |
| 217 window.location.hash = newTabHash; |
| 218 } |
| 219 }, |
| 220 |
| 221 onUrlHashChange_: function() { |
| 222 var parsed = parseUrlHash_(window.location.hash); |
| 223 |
| 224 if (!parsed) |
| 225 return; |
| 226 |
| 227 if (!parsed.tabHash) { |
| 228 // Default to the import tab. |
| 229 parsed.tabHash = ImportView.TAB_HASH; |
| 230 } |
| 231 |
| 232 var tabId = this.hashToTabId_[parsed.tabHash]; |
| 233 |
| 234 if (tabId) { |
| 235 this.tabSwitcher_.switchToTab(tabId); |
| 236 if (parsed.parameters) { |
| 237 var view = this.tabSwitcher_.getTabView(tabId); |
| 238 view.setParameters(parsed.parameters); |
| 239 } |
| 240 } |
| 241 }, |
| 242 |
| 243 }; |
| 244 |
| 245 /** |
| 246 * Takes the current hash in form of "#tab¶m1=value1¶m2=value2&..." |
| 247 * and parses it into a dictionary. |
| 248 * |
| 249 * Parameters and values are decoded with decodeURIComponent(). |
| 250 */ |
| 251 function parseUrlHash_(hash) { |
| 252 var parameters = hash.split('&'); |
| 253 |
| 254 var tabHash = parameters[0]; |
| 255 if (tabHash == '' || tabHash == '#') { |
| 256 tabHash = undefined; |
| 257 } |
| 258 |
| 259 // Split each string except the first around the '='. |
| 260 var paramDict = null; |
| 261 for (var i = 1; i < parameters.length; i++) { |
| 262 var paramStrings = parameters[i].split('='); |
| 263 if (paramStrings.length != 2) |
| 264 continue; |
| 265 if (paramDict == null) |
| 266 paramDict = {}; |
| 267 var key = decodeURIComponent(paramStrings[0]); |
| 268 var value = decodeURIComponent(paramStrings[1]); |
| 269 paramDict[key] = value; |
| 270 } |
| 271 |
| 272 return {tabHash: tabHash, parameters: paramDict}; |
| 273 } |
| 274 |
| 275 return MainView; |
| 276 })(); |
| 277 |
| 278 function ConstantsObserver() {} |
| 279 |
| 280 /** |
| 281 * Loads all constants from |constants|. On failure, global dictionaries are |
| 282 * not modifed. |
| 283 * @param {Object} receivedConstants The map of received constants. |
| 284 */ |
| 285 ConstantsObserver.prototype.onReceivedConstants = function(receivedConstants) { |
| 286 if (!areValidConstants(receivedConstants)) |
| 287 return; |
| 288 |
| 289 Constants = receivedConstants; |
| 290 |
| 291 EventType = Constants.logEventTypes; |
| 292 EventTypeNames = makeInverseMap(EventType); |
| 293 EventPhase = Constants.logEventPhase; |
| 294 EventSourceType = Constants.logSourceType; |
| 295 EventSourceTypeNames = makeInverseMap(EventSourceType); |
| 296 ClientInfo = Constants.clientInfo; |
| 297 LoadFlag = Constants.loadFlag; |
| 298 NetError = Constants.netError; |
| 299 QuicError = Constants.quicError; |
| 300 QuicRstStreamError = Constants.quicRstStreamError; |
| 301 AddressFamily = Constants.addressFamily; |
| 302 LoadState = Constants.loadState; |
| 303 SdchProblemCode = Constants.sdchProblemCode; |
| 304 DataReductionProxyBypassEventType = |
| 305 Constants.dataReductionProxyBypassEventType; |
| 306 DataReductionProxyBypassActionType = |
| 307 Constants.dataReductionProxyBypassActionType; |
| 308 // certStatusFlag may not be present when loading old log Files |
| 309 if (typeof(Constants.certStatusFlag) == 'object') |
| 310 CertStatusFlag = Constants.certStatusFlag; |
| 311 else |
| 312 CertStatusFlag = {}; |
| 313 |
| 314 timeutil.setTimeTickOffset(Constants.timeTickOffset); |
| 315 }; |
| 316 |
| 317 /** |
| 318 * Returns true if it's given a valid-looking constants object. |
| 319 * @param {Object} receivedConstants The received map of constants. |
| 320 * @return {boolean} True if the |receivedConstants| object appears valid. |
| 321 */ |
| 322 function areValidConstants(receivedConstants) { |
| 323 return typeof(receivedConstants) == 'object' && |
| 324 typeof(receivedConstants.logEventTypes) == 'object' && |
| 325 typeof(receivedConstants.clientInfo) == 'object' && |
| 326 typeof(receivedConstants.logEventPhase) == 'object' && |
| 327 typeof(receivedConstants.logSourceType) == 'object' && |
| 328 typeof(receivedConstants.loadFlag) == 'object' && |
| 329 typeof(receivedConstants.netError) == 'object' && |
| 330 typeof(receivedConstants.addressFamily) == 'object' && |
| 331 typeof(receivedConstants.timeTickOffset) == 'string' && |
| 332 typeof(receivedConstants.logFormatVersion) == 'number'; |
| 333 } |
| 334 |
| 335 /** |
| 336 * Returns the name for netError. |
| 337 * |
| 338 * Example: netErrorToString(-105) should return |
| 339 * "ERR_NAME_NOT_RESOLVED". |
| 340 * @param {number} netError The net error code. |
| 341 * @return {string} The name of the given error. |
| 342 */ |
| 343 function netErrorToString(netError) { |
| 344 return getKeyWithValue(NetError, netError); |
| 345 } |
| 346 |
| 347 /** |
| 348 * Returns the name for quicError. |
| 349 * |
| 350 * Example: quicErrorToString(25) should return |
| 351 * "TIMED_OUT". |
| 352 * @param {number} quicError The QUIC error code. |
| 353 * @return {string} The name of the given error. |
| 354 */ |
| 355 function quicErrorToString(quicError) { |
| 356 return getKeyWithValue(QuicError, quicError); |
| 357 } |
| 358 |
| 359 /** |
| 360 * Returns the name for quicRstStreamError. |
| 361 * |
| 362 * Example: quicRstStreamErrorToString(3) should return |
| 363 * "BAD_APPLICATION_PAYLOAD". |
| 364 * @param {number} quicRstStreamError The QUIC RST_STREAM error code. |
| 365 * @return {string} The name of the given error. |
| 366 */ |
| 367 function quicRstStreamErrorToString(quicRstStreamError) { |
| 368 return getKeyWithValue(QuicRstStreamError, quicRstStreamError); |
| 369 } |
| 370 |
| 371 /** |
| 372 * Returns a string representation of |family|. |
| 373 * @param {number} family An AddressFamily |
| 374 * @return {string} A representation of the given family. |
| 375 */ |
| 376 function addressFamilyToString(family) { |
| 377 var str = getKeyWithValue(AddressFamily, family); |
| 378 // All the address family start with ADDRESS_FAMILY_*. |
| 379 // Strip that prefix since it is redundant and only clutters the output. |
| 380 return str.replace(/^ADDRESS_FAMILY_/, ''); |
| 381 } |
| 382 |
| 383 /** |
| 384 * Returns the name for sdchProblemCode. |
| 385 * |
| 386 * Example: sdchProblemCodeToString(5) should return |
| 387 * "DECODE_BODY_ERROR". |
| 388 * @param {number} sdchProblemCode The SDCH problem code. |
| 389 * @return {string} The name of the given problem code. |
| 390 */ |
| 391 function sdchProblemCodeToString(sdchProblemCode) { |
| 392 return getKeyWithValue(SdchProblemCode, sdchProblemCode); |
| 393 } |
| 394 |
OLD | NEW |