Remove ProxySettings observer from chrome://net-internals#bandwidth
[chromium-blink-merge.git] / chrome / browser / resources / net_internals / bandwidth_view.js
blobfcaf937da358da117db891bbc1fae018c25b9156
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.
5 /** This view displays summary statistics on bandwidth usage. */
6 var BandwidthView = (function() {
7   'use strict';
9   // We inherit from DivView.
10   var superClass = DivView;
12   /**
13    * @constructor
14    */
15   function BandwidthView() {
16     assertFirstConstructorCall(BandwidthView);
18     // Call superclass's constructor.
19     superClass.call(this, BandwidthView.MAIN_BOX_ID);
21     g_browser.addSessionNetworkStatsObserver(this, true);
22     g_browser.addHistoricNetworkStatsObserver(this, true);
24     // Register to receive data reduction proxy info.
25     g_browser.addDataReductionProxyInfoObserver(this, true);
27     // Register to receive bad proxy info.
28     g_browser.addBadProxiesObserver(this, true);
30     this.sessionNetworkStats_ = null;
31     this.historicNetworkStats_ = null;
32   }
34   BandwidthView.TAB_ID = 'tab-handle-bandwidth';
35   BandwidthView.TAB_NAME = 'Bandwidth';
36   BandwidthView.TAB_HASH = '#bandwidth';
38   // IDs for special HTML elements in bandwidth_view.html
39   BandwidthView.MAIN_BOX_ID = 'bandwidth-view-tab-content';
40   BandwidthView.ENABLED_ID = 'data-reduction-proxy-enabled';
41   BandwidthView.PRIMARY_PROXY_ID = 'data-reduction-proxy-primary';
42   BandwidthView.SECONDARY_PROXY_ID = 'data-reduction-proxy-secondary';
43   BandwidthView.PROBE_STATUS_ID = 'data-reduction-proxy-probe-status';
44   BandwidthView.BYPASS_STATE_ID = 'data-reduction-proxy-bypass-state';
45   BandwidthView.BYPASS_STATE_CONTAINER_ID =
46       'data-reduction-proxy-bypass-state-container';
47   BandwidthView.EVENTS_TBODY_ID = 'data-reduction-proxy-view-events-tbody';
48   BandwidthView.EVENTS_UL = 'data-reduction-proxy-view-events-list';
49   BandwidthView.STATS_BOX_ID = 'bandwidth-stats-table';
51   cr.addSingletonGetter(BandwidthView);
53   BandwidthView.prototype = {
54     // Inherit the superclass's methods.
55     __proto__: superClass.prototype,
57     data_reduction_proxy_config_: null,
58     last_bypass_: null,
59     bad_proxy_config_: null,
61     onLoadLogFinish: function(data) {
62       return this.onBadProxiesChanged(data.badProxies) &&
63           this.onDataReductionProxyInfoChanged(data.dataReductionProxyInfo) &&
64           (this.onSessionNetworkStatsChanged(data.sessionNetworkStats) ||
65               this.onHistoricNetworkStatsChanged(data.historicNetworkStats));
66     },
68     /**
69      * Retains information on bandwidth usage this session.
70      */
71     onSessionNetworkStatsChanged: function(sessionNetworkStats) {
72       this.sessionNetworkStats_ = sessionNetworkStats;
73       return this.updateBandwidthUsageTable_();
74     },
76     /**
77      * Displays information on bandwidth usage this session and over the
78      * browser's lifetime.
79      */
80     onHistoricNetworkStatsChanged: function(historicNetworkStats) {
81       this.historicNetworkStats_ = historicNetworkStats;
82       return this.updateBandwidthUsageTable_();
83     },
85     /**
86      * Updates the UI based on receiving changes in information about the
87      * data reduction proxy summary.
88      */
89     onDataReductionProxyInfoChanged: function(info) {
90       $(BandwidthView.EVENTS_TBODY_ID).innerHTML = '';
92       if (!info)
93         return false;
95       if (info.enabled) {
96         $(BandwidthView.ENABLED_ID).innerText = 'Enabled';
97         $(BandwidthView.PROBE_STATUS_ID).innerText =
98             info.probe != null ? info.probe : 'N/A';
99         this.last_bypass_ = info.last_bypass != null ?
100             this.parseBypassEvent_(info.last_bypass) : null;
101         this.data_reduction_proxy_config_ = info.proxy_config.params;
102       } else {
103         $(BandwidthView.ENABLED_ID).innerText = 'Disabled';
104         $(BandwidthView.PROBE_STATUS_ID).innerText = 'N/A';
105         this.data_reduction_proxy_config_ = null;
106       }
108       this.updateDataReductionProxyConfig_();
110       for (var eventIndex = info.events.length - 1; eventIndex >= 0;
111           --eventIndex) {
112         var event = info.events[eventIndex];
113         var headerRow = addNode($(BandwidthView.EVENTS_TBODY_ID), 'tr');
114         var detailsRow = addNode($(BandwidthView.EVENTS_TBODY_ID), 'tr');
116         var timeCell = addNode(headerRow, 'td');
117         var actionCell = addNode(headerRow, 'td');
118         var detailsCell = addNode(detailsRow, 'td');
119         detailsCell.colSpan = 2;
120         detailsCell.className = 'data-reduction-proxy-view-events-details';
121         var eventTime = timeutil.convertTimeTicksToDate(event.time);
122         timeutil.addNodeWithDate(timeCell, eventTime);
124         switch (event.type) {
125           case EventType.DATA_REDUCTION_PROXY_ENABLED:
126             this.buildEnabledRow_(event, actionCell, detailsCell);
127             break;
128           case EventType.DATA_REDUCTION_PROXY_CANARY_REQUEST:
129             this.buildProbeRow_(event, actionCell, detailsCell);
130             break;
131           case EventType.DATA_REDUCTION_PROXY_CANARY_RESPONSE_RECEIVED:
132             this.buildProbeResponseRow_(event, actionCell, detailsCell);
133             break;
134           case EventType.DATA_REDUCTION_PROXY_BYPASS_REQUESTED:
135             this.buildBypassRow_(event, actionCell, detailsCell);
136             break;
137           case EventType.DATA_REDUCTION_PROXY_FALLBACK:
138             this.buildFallbackRow_(event, actionCell, detailsCell);
139             break;
140         }
141       }
143       return true;
144     },
146     /**
147      * Updates the UI based on receiving changes in information about bad
148      * proxy servers.
149      */
150     onBadProxiesChanged: function(badProxies) {
151       if (!badProxies)
152         return false;
154       var newBadProxies = [];
155       if (badProxies.length == 0) {
156         this.last_bypass_ = null;
157       } else {
158         for (var i = 0; i < badProxies.length; ++i) {
159           var entry = badProxies[i];
160           newBadProxies[entry.proxy_uri] = entry.bad_until;
161         }
162       }
163       this.bad_proxy_config_ = newBadProxies;
164       this.updateDataReductionProxyConfig_();
166       return true;
167     },
169     /**
170      * Update the bandwidth usage table.  Returns false on failure.
171      */
172     updateBandwidthUsageTable_: function() {
173       var sessionNetworkStats = this.sessionNetworkStats_;
174       var historicNetworkStats = this.historicNetworkStats_;
175       if (!sessionNetworkStats || !historicNetworkStats)
176         return false;
178       var sessionOriginal = sessionNetworkStats.session_original_content_length;
179       var sessionReceived = sessionNetworkStats.session_received_content_length;
180       var historicOriginal =
181           historicNetworkStats.historic_original_content_length;
182       var historicReceived =
183           historicNetworkStats.historic_received_content_length;
185       var rows = [];
186       rows.push({
187           title: 'Original (KB)',
188           sessionValue: bytesToRoundedKilobytes_(sessionOriginal),
189           historicValue: bytesToRoundedKilobytes_(historicOriginal)
190       });
191       rows.push({
192           title: 'Received (KB)',
193           sessionValue: bytesToRoundedKilobytes_(sessionReceived),
194           historicValue: bytesToRoundedKilobytes_(historicReceived)
195       });
196       rows.push({
197           title: 'Savings (KB)',
198           sessionValue:
199               bytesToRoundedKilobytes_(sessionOriginal - sessionReceived),
200           historicValue:
201               bytesToRoundedKilobytes_(historicOriginal - historicReceived)
202       });
203       rows.push({
204           title: 'Savings (%)',
205           sessionValue: getPercentSavings_(sessionOriginal, sessionReceived),
206           historicValue: getPercentSavings_(historicOriginal,
207                                             historicReceived)
208       });
210       var input = new JsEvalContext({rows: rows});
211       jstProcess(input, $(BandwidthView.STATS_BOX_ID));
212       return true;
213     },
215     /**
216      * Renders a data reduction proxy enabled/disabled event into the event
217      * tbody.
218      */
219     buildEnabledRow_: function(event, actionCell, detailsCell) {
220       if (event.params.enabled == 1) {
221         addTextNode(actionCell, 'Proxy: Enabled');
222         var proxyWrapper = addNode(detailsCell, 'div');
223         addNodeWithText(proxyWrapper, 'div', 'Proxy configuration:');
225         if (event.params.primary_origin != null &&
226             event.params.primary_origin.trim() != '') {
227           var proxyText = 'Primary: ' + event.params.primary_origin;
228           if (event.params.primary_restricted != null &&
229               event.params.primary_restricted) {
230             proxyText += ' (restricted)';
231           }
232           addNodeWithText(proxyWrapper, 'div', proxyText);
233         }
235         if (event.params.fallback_origin != null &&
236             event.params.fallback_origin.trim() != '') {
237           var proxyText = 'Fallback: ' + event.params.fallback_origin;
238           if (event.params.fallback_restricted != null &&
239               event.params.fallback_restricted) {
240             proxyText += ' (restricted)';
241           }
242           addNodeWithText(proxyWrapper, 'div', proxyText);
243         }
245         if (event.params.ssl_origin != null &&
246             event.params.ssl_origin.trim() != '') {
247           addNodeWithText(proxyWrapper, 'div',
248               'SSL: ' + event.params.ssl_origin);
249         }
250       } else {
251         addTextNode(actionCell, 'Proxy: Disabled');
252       }
253     },
255     /**
256      * Renders a Data Reduction Proxy probe request event into the event
257      * tbody.
258      */
259     buildProbeRow_: function(event, actionCell, detailsCell) {
260       if (event.phase == EventPhase.PHASE_BEGIN) {
261         addTextNode(actionCell, 'Probe request sent');
262         addTextNode(detailsCell, 'URL: ' + event.params.url);
263       } else if (event.phase == EventPhase.PHASE_END) {
264         addTextNode(actionCell, 'Probe request completed');
265         if (event.params.net_error == 0) {
266           addTextNode(detailsCell, 'Result: OK');
267         } else {
268           addTextNode(detailsCell,
269                       'Result: ' + netErrorToString(event.params.net_error));
270         }
271       }
272     },
274     /**
275      * Renders a Data Reduction Proxy probe response event into the event
276      * tbody.
277      */
278     buildProbeResponseRow_: function(event, actionCell, detailsCell) {
279       addTextNode(actionCell, 'Probe response received');
280     },
282     /**
283      * Renders a data reduction proxy bypass event into the event tbody.
284      */
285     buildBypassRow_: function(event, actionCell, detailsCell) {
286       var parsedBypass = this.parseBypassEvent_(event);
288       addTextNode(actionCell,
289                   'Bypass received (' + parsedBypass.bypass_reason + ')');
290       var bypassWrapper = addNode(detailsCell, 'div');
291       addNodeWithText(bypassWrapper, 'div', 'URL: ' + parsedBypass.origin_url);
292       addNodeWithText(
293           bypassWrapper, 'div',
294           'Bypassed for ' + parsedBypass.bypass_duration_seconds + ' seconds.');
295     },
297     /**
298      * Renders a data reduction proxy fallback event into the event tbody.
299      */
300     buildFallbackRow_: function(event, actionCell, detailsCell) {
301       addTextNode(actionCell, 'Proxy fallback');
302     },
304     /**
305      * Parses a data reduction proxy bypass event for use in the summary and
306      * in the event tbody.
307      */
308     parseBypassEvent_: function(event) {
309       var reason;
310       if (event.params.action != null) {
311         reason = event.params.action;
312       } else {
313         reason = getKeyWithValue(
314             DataReductionProxyBypassEventType, event.params.bypass_type);
315       }
317       var parsedBypass = {
318         bypass_reason: reason,
319         origin_url: event.params.url,
320         bypass_duration_seconds: event.params.bypass_duration_seconds,
321         bypass_expiration: event.params.expiration,
322       };
324       return parsedBypass;
325     },
327     /**
328      * Updates the data reduction proxy summary block.
329      */
330     updateDataReductionProxyConfig_: function() {
331       $(BandwidthView.PRIMARY_PROXY_ID).innerHTML = '';
332       $(BandwidthView.SECONDARY_PROXY_ID).innerHTML = '';
333       setNodeDisplay($(BandwidthView.BYPASS_STATE_CONTAINER_ID), false);
335       if (this.data_reduction_proxy_config_) {
336         var primaryProxy = '';
337         var secondaryProxy = '';
338         var hasBypassedProxy = false;
339         var now = timeutil.getCurrentTimeTicks();
341         if (this.last_bypass_ &&
342             this.hasTimePassedLogTime_(+this.last_bypass_.bypass_expiration)) {
343           var input = new JsEvalContext(this.last_bypass_);
344           jstProcess(input, $(BandwidthView.BYPASS_STATE_CONTAINER_ID));
345         } else {
346           var input = new JsEvalContext();
347           jstProcess(input, $(BandwidthView.BYPASS_STATE_CONTAINER_ID));
348         }
350         if (this.data_reduction_proxy_config_.ssl_origin) {
351           if (this.isMarkedAsBad_(this.data_reduction_proxy_config_.ssl_origin))
352             hasBypassedProxy = true;
354           primaryProxy = 'HTTPS Tunnel: ' + this.buildProxyString_(
355               this.data_reduction_proxy_config_.ssl_origin, false);
356         }
358         if (this.data_reduction_proxy_config_.primary_origin) {
359           if (this.isMarkedAsBad_(
360               this.data_reduction_proxy_config_.primary_origin))
361             hasBypassedProxy = true;
363           var proxyString = this.buildProxyString_(
364               this.data_reduction_proxy_config_.primary_origin,
365               this.data_reduction_proxy_config_.primary_restricted);
367           if (primaryProxy == '')
368             primaryProxy = proxyString;
369           else
370             secondaryProxy = proxyString;
371         }
373         if (this.data_reduction_proxy_config_.fallback_origin) {
374           if (this.isMarkedAsBad_(
375               this.data_reduction_proxy_config_.fallback_origin))
376             hasBypassedProxy = true;
378           var proxyString = this.buildProxyString_(
379               this.data_reduction_proxy_config_.fallback_origin,
380               this.data_reduction_proxy_config_.fallback_restricted);
382           if (primaryProxy == '')
383             primaryProxy = proxyString;
384           else if (secondaryProxy == '')
385             secondaryProxy = proxyString;
386         }
388         $(BandwidthView.PRIMARY_PROXY_ID).innerText = primaryProxy;
389         $(BandwidthView.SECONDARY_PROXY_ID).innerText = secondaryProxy;
390         if (hasBypassedProxy)
391           setNodeDisplay($(BandwidthView.BYPASS_STATE_CONTAINER_ID), true);
392       }
393     },
395     /**
396      * Takes a data reduction proxy configuration and renders to a friendly
397      * string.
398      */
399     buildProxyString_: function(proxy, restricted) {
400       var markedAsBad = this.isMarkedAsBad_(proxy);
401       var proxyString = '';
402       if (restricted) {
403         proxyString += proxy + ' (RESTRICTED)';
404       } else {
405         proxyString += proxy;
406         if (markedAsBad) {
407           proxyString += ' (BYPASSED)';
408         } else {
409           proxyString += ' (ACTIVE)';
410         }
411       }
413       return proxyString;
414     },
416     /**
417      * Checks to see if a proxy server is in marked as bad.
418      */
419     isMarkedAsBad_: function(proxy) {
420       for (var entry in this.bad_proxy_config_) {
421         if (entry == proxy &&
422             this.hasTimePassedLogTime_(this.bad_proxy_config_[entry])) {
423           return true;
424         }
425       }
427       return false;
428     },
430     /**
431      * Checks to see if a given time in ticks has passed the time of the
432      * the log. For real time viewing, this is "now", but for loaded logs, it
433      * is the time at which the logs were taken.
434      */
435     hasTimePassedLogTime_: function(timeTicks) {
436       var logTime;
437       if (MainView.isViewingLoadedLog() && ClientInfo.numericDate) {
438         logTime = ClientInfo.numericDate;
439       } else {
440         logTime = timeutil.getCurrentTime();
441       }
443       return timeutil.convertTimeTicksToTime(timeTicks) > logTime;
444     }
445   };
447   /**
448    * Converts bytes to kilobytes rounded to one decimal place.
449    */
450   function bytesToRoundedKilobytes_(val) {
451     return (val / 1024).toFixed(1);
452   }
454   /**
455    * Returns bandwidth savings as a percent rounded to one decimal place.
456    */
457   function getPercentSavings_(original, received) {
458     if (original > 0) {
459       return ((original - received) * 100 / original).toFixed(1);
460     }
461     return '0.0';
462   }
464   return BandwidthView;
465 })();