Roll src/third_party/WebKit bf18a82:a9cee16 (svn 185297:185304)
[chromium-blink-merge.git] / chrome / browser / resources / net_internals / browser_bridge.js
blob09ce829b4471723eec68b2f9d3a3d87a31759970
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 // Populated by constants from the browser. Used only by this file.
6 var NetInfoSources = null;
8 /**
9 * This class provides a "bridge" for communicating between the javascript and
10 * the browser.
12 var BrowserBridge = (function() {
13 'use strict';
15 /**
16 * Delay in milliseconds between updates of certain browser information.
18 var POLL_INTERVAL_MS = 5000;
20 /**
21 * @constructor
23 function BrowserBridge() {
24 assertFirstConstructorCall(BrowserBridge);
26 // List of observers for various bits of browser state.
27 this.connectionTestsObservers_ = [];
28 this.hstsObservers_ = [];
29 this.constantsObservers_ = [];
30 this.crosONCFileParseObservers_ = [];
31 this.storeDebugLogsObservers_ = [];
32 this.setNetworkDebugModeObservers_ = [];
33 // Unprocessed data received before the constants. This serves to protect
34 // against passing along data before having information on how to interpret
35 // it.
36 this.earlyReceivedData_ = [];
38 this.pollableDataHelpers_ = {};
40 // Add PollableDataHelpers for NetInfoSources, which retrieve information
41 // directly from the network stack.
42 this.addNetInfoPollableDataHelper('proxySettings',
43 'onProxySettingsChanged');
44 this.addNetInfoPollableDataHelper('badProxies', 'onBadProxiesChanged');
45 this.addNetInfoPollableDataHelper('hostResolverInfo',
46 'onHostResolverInfoChanged');
47 this.addNetInfoPollableDataHelper('socketPoolInfo',
48 'onSocketPoolInfoChanged');
49 this.addNetInfoPollableDataHelper('spdySessionInfo',
50 'onSpdySessionInfoChanged');
51 this.addNetInfoPollableDataHelper('spdyStatus', 'onSpdyStatusChanged');
52 this.addNetInfoPollableDataHelper('spdyAlternateProtocolMappings',
53 'onSpdyAlternateProtocolMappingsChanged');
54 this.addNetInfoPollableDataHelper('quicInfo', 'onQuicInfoChanged');
55 this.addNetInfoPollableDataHelper('httpCacheInfo',
56 'onHttpCacheInfoChanged');
58 // Add other PollableDataHelpers.
59 this.pollableDataHelpers_.sessionNetworkStats =
60 new PollableDataHelper('onSessionNetworkStatsChanged',
61 this.sendGetSessionNetworkStats.bind(this));
62 this.pollableDataHelpers_.historicNetworkStats =
63 new PollableDataHelper('onHistoricNetworkStatsChanged',
64 this.sendGetHistoricNetworkStats.bind(this));
65 if (cr.isWindows) {
66 this.pollableDataHelpers_.serviceProviders =
67 new PollableDataHelper('onServiceProvidersChanged',
68 this.sendGetServiceProviders.bind(this));
70 this.pollableDataHelpers_.prerenderInfo =
71 new PollableDataHelper('onPrerenderInfoChanged',
72 this.sendGetPrerenderInfo.bind(this));
73 this.pollableDataHelpers_.extensionInfo =
74 new PollableDataHelper('onExtensionInfoChanged',
75 this.sendGetExtensionInfo.bind(this));
76 if (cr.isChromeOS) {
77 this.pollableDataHelpers_.systemLog =
78 new PollableDataHelper('onSystemLogChanged',
79 this.getSystemLog.bind(this, 'syslog'));
82 // Setting this to true will cause messages from the browser to be ignored,
83 // and no messages will be sent to the browser, either. Intended for use
84 // when viewing log files.
85 this.disabled_ = false;
87 // Interval id returned by window.setInterval for polling timer.
88 this.pollIntervalId_ = null;
91 cr.addSingletonGetter(BrowserBridge);
93 BrowserBridge.prototype = {
95 //--------------------------------------------------------------------------
96 // Messages sent to the browser
97 //--------------------------------------------------------------------------
99 /**
100 * Wraps |chrome.send|. Doesn't send anything when disabled.
102 send: function(value1, value2) {
103 if (!this.disabled_) {
104 if (arguments.length == 1) {
105 chrome.send(value1);
106 } else if (arguments.length == 2) {
107 chrome.send(value1, value2);
108 } else {
109 throw 'Unsupported number of arguments.';
114 sendReady: function() {
115 this.send('notifyReady');
116 this.setPollInterval(POLL_INTERVAL_MS);
120 * Some of the data we are interested is not currently exposed as a
121 * stream. This starts polling those with active observers (visible
122 * views) every |intervalMs|. Subsequent calls override previous calls
123 * to this function. If |intervalMs| is 0, stops polling.
125 setPollInterval: function(intervalMs) {
126 if (this.pollIntervalId_ !== null) {
127 window.clearInterval(this.pollIntervalId_);
128 this.pollIntervalId_ = null;
131 if (intervalMs > 0) {
132 this.pollIntervalId_ =
133 window.setInterval(this.checkForUpdatedInfo.bind(this, false),
134 intervalMs);
138 sendGetNetInfo: function(netInfoSource) {
139 // If don't have constants yet, don't do anything yet.
140 if (NetInfoSources)
141 this.send('getNetInfo', [NetInfoSources[netInfoSource]]);
144 sendReloadProxySettings: function() {
145 this.send('reloadProxySettings');
148 sendClearBadProxies: function() {
149 this.send('clearBadProxies');
152 sendClearHostResolverCache: function() {
153 this.send('clearHostResolverCache');
156 sendClearBrowserCache: function() {
157 this.send('clearBrowserCache');
160 sendClearAllCache: function() {
161 this.sendClearHostResolverCache();
162 this.sendClearBrowserCache();
165 sendStartConnectionTests: function(url) {
166 this.send('startConnectionTests', [url]);
169 sendHSTSQuery: function(domain) {
170 this.send('hstsQuery', [domain]);
173 sendHSTSAdd: function(domain, sts_include_subdomains,
174 pkp_include_subdomains, pins) {
175 this.send('hstsAdd', [domain, sts_include_subdomains,
176 pkp_include_subdomains, pins]);
179 sendHSTSDelete: function(domain) {
180 this.send('hstsDelete', [domain]);
183 sendGetSessionNetworkStats: function() {
184 this.send('getSessionNetworkStats');
187 sendGetHistoricNetworkStats: function() {
188 this.send('getHistoricNetworkStats');
191 sendCloseIdleSockets: function() {
192 this.send('closeIdleSockets');
195 sendFlushSocketPools: function() {
196 this.send('flushSocketPools');
199 sendGetServiceProviders: function() {
200 this.send('getServiceProviders');
203 sendGetPrerenderInfo: function() {
204 this.send('getPrerenderInfo');
207 sendGetExtensionInfo: function() {
208 this.send('getExtensionInfo');
211 enableIPv6: function() {
212 this.send('enableIPv6');
215 setLogLevel: function(logLevel) {
216 this.send('setLogLevel', ['' + logLevel]);
219 refreshSystemLogs: function() {
220 this.send('refreshSystemLogs');
223 getSystemLog: function(log_key, cellId) {
224 this.send('getSystemLog', [log_key, cellId]);
227 importONCFile: function(fileContent, passcode) {
228 this.send('importONCFile', [fileContent, passcode]);
231 storeDebugLogs: function() {
232 this.send('storeDebugLogs');
235 setNetworkDebugMode: function(subsystem) {
236 this.send('setNetworkDebugMode', [subsystem]);
239 //--------------------------------------------------------------------------
240 // Messages received from the browser.
241 //--------------------------------------------------------------------------
243 receive: function(command, params) {
244 // Does nothing if disabled.
245 if (this.disabled_)
246 return;
248 // If no constants have been received, and params does not contain the
249 // constants, delay handling the data.
250 if (Constants == null && command != 'receivedConstants') {
251 this.earlyReceivedData_.push({ command: command, params: params });
252 return;
255 this[command](params);
257 // Handle any data that was received early in the order it was received,
258 // once the constants have been processed.
259 if (this.earlyReceivedData_ != null) {
260 for (var i = 0; i < this.earlyReceivedData_.length; i++) {
261 var command = this.earlyReceivedData_[i];
262 this[command.command](command.params);
264 this.earlyReceivedData_ = null;
268 receivedConstants: function(constants) {
269 NetInfoSources = constants.netInfoSources;
270 for (var i = 0; i < this.constantsObservers_.length; i++)
271 this.constantsObservers_[i].onReceivedConstants(constants);
272 // May have been waiting for the constants to be received before getting
273 // information for the currently displayed tab.
274 this.checkForUpdatedInfo();
277 receivedLogEntries: function(logEntries) {
278 EventsTracker.getInstance().addLogEntries(logEntries);
281 receivedNetInfo: function(netInfo) {
282 // Dispatch |netInfo| to the various PollableDataHelpers listening to
283 // each field it contains.
285 // Currently information is only received from one source at a time, but
286 // the API does allow for data from more that one to be requested at once.
287 for (var source in netInfo)
288 this.pollableDataHelpers_[source].update(netInfo[source]);
291 receivedSessionNetworkStats: function(sessionNetworkStats) {
292 this.pollableDataHelpers_.sessionNetworkStats.update(sessionNetworkStats);
295 receivedHistoricNetworkStats: function(historicNetworkStats) {
296 this.pollableDataHelpers_.historicNetworkStats.update(
297 historicNetworkStats);
300 receivedServiceProviders: function(serviceProviders) {
301 this.pollableDataHelpers_.serviceProviders.update(serviceProviders);
304 receivedStartConnectionTestSuite: function() {
305 for (var i = 0; i < this.connectionTestsObservers_.length; i++)
306 this.connectionTestsObservers_[i].onStartedConnectionTestSuite();
309 receivedStartConnectionTestExperiment: function(experiment) {
310 for (var i = 0; i < this.connectionTestsObservers_.length; i++) {
311 this.connectionTestsObservers_[i].onStartedConnectionTestExperiment(
312 experiment);
316 receivedCompletedConnectionTestExperiment: function(info) {
317 for (var i = 0; i < this.connectionTestsObservers_.length; i++) {
318 this.connectionTestsObservers_[i].onCompletedConnectionTestExperiment(
319 info.experiment, info.result);
323 receivedCompletedConnectionTestSuite: function() {
324 for (var i = 0; i < this.connectionTestsObservers_.length; i++)
325 this.connectionTestsObservers_[i].onCompletedConnectionTestSuite();
328 receivedHSTSResult: function(info) {
329 for (var i = 0; i < this.hstsObservers_.length; i++)
330 this.hstsObservers_[i].onHSTSQueryResult(info);
333 receivedONCFileParse: function(error) {
334 for (var i = 0; i < this.crosONCFileParseObservers_.length; i++)
335 this.crosONCFileParseObservers_[i].onONCFileParse(error);
338 receivedStoreDebugLogs: function(status) {
339 for (var i = 0; i < this.storeDebugLogsObservers_.length; i++)
340 this.storeDebugLogsObservers_[i].onStoreDebugLogs(status);
343 receivedSetNetworkDebugMode: function(status) {
344 for (var i = 0; i < this.setNetworkDebugModeObservers_.length; i++)
345 this.setNetworkDebugModeObservers_[i].onSetNetworkDebugMode(status);
348 receivedPrerenderInfo: function(prerenderInfo) {
349 this.pollableDataHelpers_.prerenderInfo.update(prerenderInfo);
352 receivedExtensionInfo: function(extensionInfo) {
353 this.pollableDataHelpers_.extensionInfo.update(extensionInfo);
356 getSystemLogCallback: function(systemLog) {
357 this.pollableDataHelpers_.systemLog.update(systemLog);
360 //--------------------------------------------------------------------------
363 * Prevents receiving/sending events to/from the browser.
365 disable: function() {
366 this.disabled_ = true;
367 this.setPollInterval(0);
371 * Returns true if the BrowserBridge has been disabled.
373 isDisabled: function() {
374 return this.disabled_;
378 * Adds a listener of the proxy settings. |observer| will be called back
379 * when data is received, through:
381 * observer.onProxySettingsChanged(proxySettings)
383 * |proxySettings| is a dictionary with (up to) two properties:
385 * "original" -- The settings that chrome was configured to use
386 * (i.e. system settings.)
387 * "effective" -- The "effective" proxy settings that chrome is using.
388 * (decides between the manual/automatic modes of the
389 * fetched settings).
391 * Each of these two configurations is formatted as a string, and may be
392 * omitted if not yet initialized.
394 * If |ignoreWhenUnchanged| is true, data is only sent when it changes.
395 * If it's false, data is sent whenever it's received from the browser.
397 addProxySettingsObserver: function(observer, ignoreWhenUnchanged) {
398 this.pollableDataHelpers_.proxySettings.addObserver(observer,
399 ignoreWhenUnchanged);
403 * Adds a listener of the proxy settings. |observer| will be called back
404 * when data is received, through:
406 * observer.onBadProxiesChanged(badProxies)
408 * |badProxies| is an array, where each entry has the property:
409 * badProxies[i].proxy_uri: String identify the proxy.
410 * badProxies[i].bad_until: The time when the proxy stops being considered
411 * bad. Note the time is in time ticks.
413 addBadProxiesObserver: function(observer, ignoreWhenUnchanged) {
414 this.pollableDataHelpers_.badProxies.addObserver(observer,
415 ignoreWhenUnchanged);
419 * Adds a listener of the host resolver info. |observer| will be called back
420 * when data is received, through:
422 * observer.onHostResolverInfoChanged(hostResolverInfo)
424 addHostResolverInfoObserver: function(observer, ignoreWhenUnchanged) {
425 this.pollableDataHelpers_.hostResolverInfo.addObserver(
426 observer, ignoreWhenUnchanged);
430 * Adds a listener of the socket pool. |observer| will be called back
431 * when data is received, through:
433 * observer.onSocketPoolInfoChanged(socketPoolInfo)
435 addSocketPoolInfoObserver: function(observer, ignoreWhenUnchanged) {
436 this.pollableDataHelpers_.socketPoolInfo.addObserver(observer,
437 ignoreWhenUnchanged);
441 * Adds a listener of the network session. |observer| will be called back
442 * when data is received, through:
444 * observer.onSessionNetworkStatsChanged(sessionNetworkStats)
446 addSessionNetworkStatsObserver: function(observer, ignoreWhenUnchanged) {
447 this.pollableDataHelpers_.sessionNetworkStats.addObserver(
448 observer, ignoreWhenUnchanged);
452 * Adds a listener of persistent network session data. |observer| will be
453 * called back when data is received, through:
455 * observer.onHistoricNetworkStatsChanged(historicNetworkStats)
457 addHistoricNetworkStatsObserver: function(observer, ignoreWhenUnchanged) {
458 this.pollableDataHelpers_.historicNetworkStats.addObserver(
459 observer, ignoreWhenUnchanged);
463 * Adds a listener of the QUIC info. |observer| will be called back
464 * when data is received, through:
466 * observer.onQuicInfoChanged(quicInfo)
468 addQuicInfoObserver: function(observer, ignoreWhenUnchanged) {
469 this.pollableDataHelpers_.quicInfo.addObserver(
470 observer, ignoreWhenUnchanged);
474 * Adds a listener of the SPDY info. |observer| will be called back
475 * when data is received, through:
477 * observer.onSpdySessionInfoChanged(spdySessionInfo)
479 addSpdySessionInfoObserver: function(observer, ignoreWhenUnchanged) {
480 this.pollableDataHelpers_.spdySessionInfo.addObserver(
481 observer, ignoreWhenUnchanged);
485 * Adds a listener of the SPDY status. |observer| will be called back
486 * when data is received, through:
488 * observer.onSpdyStatusChanged(spdyStatus)
490 addSpdyStatusObserver: function(observer, ignoreWhenUnchanged) {
491 this.pollableDataHelpers_.spdyStatus.addObserver(observer,
492 ignoreWhenUnchanged);
496 * Adds a listener of the AlternateProtocolMappings. |observer| will be
497 * called back when data is received, through:
499 * observer.onSpdyAlternateProtocolMappingsChanged(
500 * spdyAlternateProtocolMappings)
502 addSpdyAlternateProtocolMappingsObserver: function(observer,
503 ignoreWhenUnchanged) {
504 this.pollableDataHelpers_.spdyAlternateProtocolMappings.addObserver(
505 observer, ignoreWhenUnchanged);
509 * Adds a listener of the service providers info. |observer| will be called
510 * back when data is received, through:
512 * observer.onServiceProvidersChanged(serviceProviders)
514 * Will do nothing if on a platform other than Windows, as service providers
515 * are only present on Windows.
517 addServiceProvidersObserver: function(observer, ignoreWhenUnchanged) {
518 if (this.pollableDataHelpers_.serviceProviders) {
519 this.pollableDataHelpers_.serviceProviders.addObserver(
520 observer, ignoreWhenUnchanged);
525 * Adds a listener for the progress of the connection tests.
526 * The observer will be called back with:
528 * observer.onStartedConnectionTestSuite();
529 * observer.onStartedConnectionTestExperiment(experiment);
530 * observer.onCompletedConnectionTestExperiment(experiment, result);
531 * observer.onCompletedConnectionTestSuite();
533 addConnectionTestsObserver: function(observer) {
534 this.connectionTestsObservers_.push(observer);
538 * Adds a listener for the http cache info results.
539 * The observer will be called back with:
541 * observer.onHttpCacheInfoChanged(info);
543 addHttpCacheInfoObserver: function(observer, ignoreWhenUnchanged) {
544 this.pollableDataHelpers_.httpCacheInfo.addObserver(
545 observer, ignoreWhenUnchanged);
549 * Adds a listener for the results of HSTS (HTTPS Strict Transport Security)
550 * queries. The observer will be called back with:
552 * observer.onHSTSQueryResult(result);
554 addHSTSObserver: function(observer) {
555 this.hstsObservers_.push(observer);
559 * Adds a listener for ONC file parse status. The observer will be called
560 * back with:
562 * observer.onONCFileParse(error);
564 addCrosONCFileParseObserver: function(observer) {
565 this.crosONCFileParseObservers_.push(observer);
569 * Adds a listener for storing log file status. The observer will be called
570 * back with:
572 * observer.onStoreDebugLogs(status);
574 addStoreDebugLogsObserver: function(observer) {
575 this.storeDebugLogsObservers_.push(observer);
579 * Adds a listener for network debugging mode status. The observer
580 * will be called back with:
582 * observer.onSetNetworkDebugMode(status);
584 addSetNetworkDebugModeObserver: function(observer) {
585 this.setNetworkDebugModeObservers_.push(observer);
589 * Adds a listener for the received constants event. |observer| will be
590 * called back when the constants are received, through:
592 * observer.onReceivedConstants(constants);
594 addConstantsObserver: function(observer) {
595 this.constantsObservers_.push(observer);
599 * Adds a listener for updated prerender info events
600 * |observer| will be called back with:
602 * observer.onPrerenderInfoChanged(prerenderInfo);
604 addPrerenderInfoObserver: function(observer, ignoreWhenUnchanged) {
605 this.pollableDataHelpers_.prerenderInfo.addObserver(
606 observer, ignoreWhenUnchanged);
610 * Adds a listener of extension information. |observer| will be called
611 * back when data is received, through:
613 * observer.onExtensionInfoChanged(extensionInfo)
615 addExtensionInfoObserver: function(observer, ignoreWhenUnchanged) {
616 this.pollableDataHelpers_.extensionInfo.addObserver(
617 observer, ignoreWhenUnchanged);
621 * Adds a listener of system log information. |observer| will be called
622 * back when data is received, through:
624 * observer.onSystemLogChanged(systemLogInfo)
626 addSystemLogObserver: function(observer, ignoreWhenUnchanged) {
627 if (this.pollableDataHelpers_.systemLog) {
628 this.pollableDataHelpers_.systemLog.addObserver(
629 observer, ignoreWhenUnchanged);
634 * If |force| is true, calls all startUpdate functions. Otherwise, just
635 * runs updates with active observers.
637 checkForUpdatedInfo: function(force) {
638 for (var name in this.pollableDataHelpers_) {
639 var helper = this.pollableDataHelpers_[name];
640 if (force || helper.hasActiveObserver())
641 helper.startUpdate();
646 * Calls all startUpdate functions and, if |callback| is non-null,
647 * calls it with the results of all updates.
649 updateAllInfo: function(callback) {
650 if (callback)
651 new UpdateAllObserver(callback, this.pollableDataHelpers_);
652 this.checkForUpdatedInfo(true);
656 * Adds a PollableDataHelper that listens to the specified NetInfoSource.
658 addNetInfoPollableDataHelper: function(sourceName, observerMethodName) {
659 this.pollableDataHelpers_[sourceName] = new PollableDataHelper(
660 observerMethodName, this.sendGetNetInfo.bind(this, sourceName));
665 * This is a helper class used by BrowserBridge, to keep track of:
666 * - the list of observers interested in some piece of data.
667 * - the last known value of that piece of data.
668 * - the name of the callback method to invoke on observers.
669 * - the update function.
670 * @constructor
672 function PollableDataHelper(observerMethodName, startUpdateFunction) {
673 this.observerMethodName_ = observerMethodName;
674 this.startUpdate = startUpdateFunction;
675 this.observerInfos_ = [];
678 PollableDataHelper.prototype = {
679 getObserverMethodName: function() {
680 return this.observerMethodName_;
683 isObserver: function(object) {
684 for (var i = 0; i < this.observerInfos_.length; i++) {
685 if (this.observerInfos_[i].observer === object)
686 return true;
688 return false;
692 * If |ignoreWhenUnchanged| is true, we won't send data again until it
693 * changes.
695 addObserver: function(observer, ignoreWhenUnchanged) {
696 this.observerInfos_.push(new ObserverInfo(observer, ignoreWhenUnchanged));
699 removeObserver: function(observer) {
700 for (var i = 0; i < this.observerInfos_.length; i++) {
701 if (this.observerInfos_[i].observer === observer) {
702 this.observerInfos_.splice(i, 1);
703 return;
709 * Helper function to handle calling all the observers, but ONLY if the data
710 * has actually changed since last time or the observer has yet to receive
711 * any data. This is used for data we received from browser on an update
712 * loop.
714 update: function(data) {
715 var prevData = this.currentData_;
716 var changed = false;
718 // If the data hasn't changed since last time, will only need to notify
719 // observers that have not yet received any data.
720 if (!prevData || JSON.stringify(prevData) != JSON.stringify(data)) {
721 changed = true;
722 this.currentData_ = data;
725 // Notify the observers of the change, as needed.
726 for (var i = 0; i < this.observerInfos_.length; i++) {
727 var observerInfo = this.observerInfos_[i];
728 if (changed || !observerInfo.hasReceivedData ||
729 !observerInfo.ignoreWhenUnchanged) {
730 observerInfo.observer[this.observerMethodName_](this.currentData_);
731 observerInfo.hasReceivedData = true;
737 * Returns true if one of the observers actively wants the data
738 * (i.e. is visible).
740 hasActiveObserver: function() {
741 for (var i = 0; i < this.observerInfos_.length; i++) {
742 if (this.observerInfos_[i].observer.isActive())
743 return true;
745 return false;
750 * This is a helper class used by PollableDataHelper, to keep track of
751 * each observer and whether or not it has received any data. The
752 * latter is used to make sure that new observers get sent data on the
753 * update following their creation.
754 * @constructor
756 function ObserverInfo(observer, ignoreWhenUnchanged) {
757 this.observer = observer;
758 this.hasReceivedData = false;
759 this.ignoreWhenUnchanged = ignoreWhenUnchanged;
763 * This is a helper class used by BrowserBridge to send data to
764 * a callback once data from all polls has been received.
766 * It works by keeping track of how many polling functions have
767 * yet to receive data, and recording the data as it it received.
769 * @constructor
771 function UpdateAllObserver(callback, pollableDataHelpers) {
772 this.callback_ = callback;
773 this.observingCount_ = 0;
774 this.updatedData_ = {};
776 for (var name in pollableDataHelpers) {
777 ++this.observingCount_;
778 var helper = pollableDataHelpers[name];
779 helper.addObserver(this);
780 this[helper.getObserverMethodName()] =
781 this.onDataReceived_.bind(this, helper, name);
785 UpdateAllObserver.prototype = {
786 isActive: function() {
787 return true;
790 onDataReceived_: function(helper, name, data) {
791 helper.removeObserver(this);
792 --this.observingCount_;
793 this.updatedData_[name] = data;
794 if (this.observingCount_ == 0)
795 this.callback_(this.updatedData_);
799 return BrowserBridge;
800 })();