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